Optimize enumeration of global classes in create dialog and autocomplete

This commit is contained in:
Pedro J. Estébanez 2025-01-28 10:27:56 +01:00
parent 318af42020
commit a20934c8e4
6 changed files with 67 additions and 70 deletions

View file

@ -983,20 +983,6 @@ bool EditorData::script_class_is_parent(const String &p_class, const String &p_i
return true;
}
StringName EditorData::script_class_get_base(const String &p_class) const {
Ref<Script> script = script_class_load_script(p_class);
if (script.is_null()) {
return StringName();
}
Ref<Script> base_script = script->get_base_script();
if (base_script.is_null()) {
return ScriptServer::get_global_class_base(p_class);
}
return script->get_language()->get_global_class_name(base_script->get_path());
}
Variant EditorData::script_class_instance(const String &p_class) {
if (ScriptServer::is_global_class(p_class)) {
Ref<Script> script = script_class_load_script(p_class);
@ -1026,22 +1012,25 @@ void EditorData::script_class_set_icon_path(const String &p_class, const String
_script_class_icon_paths[p_class] = p_icon_path;
}
String EditorData::script_class_get_icon_path(const String &p_class) const {
if (!ScriptServer::is_global_class(p_class)) {
return String();
}
String EditorData::script_class_get_icon_path(const String &p_class, bool *r_valid) const {
String current = p_class;
String ret = _script_class_icon_paths[current];
while (ret.is_empty()) {
current = script_class_get_base(current);
while (true) {
if (!ScriptServer::is_global_class(current)) {
// If the classnames chain has a native class ancestor, we're done with success.
if (r_valid) {
*r_valid = ClassDB::class_exists(current);
}
return String();
}
ret = _script_class_icon_paths.has(current) ? _script_class_icon_paths[current] : String();
HashMap<StringName, String>::ConstIterator E = _script_class_icon_paths.find(current);
if ((bool)E) {
if (r_valid) {
*r_valid = true;
}
return E->value;
}
current = ScriptServer::get_global_class_base(current);
}
return ret;
}
StringName EditorData::script_class_get_name(const String &p_path) const {
@ -1126,28 +1115,42 @@ Ref<Texture2D> EditorData::_load_script_icon(const String &p_path) const {
return nullptr;
}
Ref<Texture2D> EditorData::get_script_icon(const Ref<Script> &p_script) {
Ref<Texture2D> EditorData::get_script_icon(const String &p_script_path) {
// Take from the local cache, if available.
if (_script_icon_cache.has(p_script)) {
if (_script_icon_cache.has(p_script_path)) {
// Can be an empty value if we can't resolve any icon for this script.
// An empty value is still cached to avoid unnecessary attempts at resolving it again.
return _script_icon_cache[p_script];
return _script_icon_cache[p_script_path];
}
Ref<Script> base_scr = p_script;
// Fast path in case the whole hierarchy is made of global classes.
StringName class_name = script_class_get_name(p_script_path);
{
if (class_name != StringName()) {
bool icon_valid = false;
String icon_path = script_class_get_icon_path(class_name, &icon_valid);
if (icon_valid) {
Ref<Texture2D> icon = _load_script_icon(icon_path);
_script_icon_cache[p_script_path] = icon;
return icon;
}
}
}
Ref<Script> base_scr = ResourceLoader::load(p_script_path, "Script");
while (base_scr.is_valid()) {
// Check for scripted classes.
String icon_path;
StringName class_name = script_class_get_name(base_scr->get_path());
if (base_scr->is_built_in() || class_name == StringName()) {
StringName base_class_name = script_class_get_name(base_scr->get_path());
if (base_scr->is_built_in() || base_class_name == StringName()) {
icon_path = base_scr->get_class_icon_path();
} else {
icon_path = script_class_get_icon_path(class_name);
icon_path = script_class_get_icon_path(base_class_name);
}
Ref<Texture2D> icon = _load_script_icon(icon_path);
if (icon.is_valid()) {
_script_icon_cache[p_script] = icon;
_script_icon_cache[p_script_path] = icon;
return icon;
}
@ -1155,7 +1158,7 @@ Ref<Texture2D> EditorData::get_script_icon(const Ref<Script> &p_script) {
// TODO: Should probably be deprecated in 4.x
const EditorData::CustomType *ctype = get_custom_type_by_path(base_scr->get_path());
if (ctype && ctype->icon.is_valid()) {
_script_icon_cache[p_script] = ctype->icon;
_script_icon_cache[p_script_path] = ctype->icon;
return ctype->icon;
}
@ -1163,21 +1166,16 @@ Ref<Texture2D> EditorData::get_script_icon(const Ref<Script> &p_script) {
base_scr = base_scr->get_base_script();
}
// No custom icon was found in the inheritance chain, so check the base
// class of the script instead.
String base_type;
p_script->get_language()->get_global_class_name(p_script->get_path(), &base_type);
// Check if the base type is an extension-defined type.
Ref<Texture2D> ext_icon = extension_class_get_icon(base_type);
Ref<Texture2D> ext_icon = extension_class_get_icon(class_name);
if (ext_icon.is_valid()) {
_script_icon_cache[p_script] = ext_icon;
_script_icon_cache[p_script_path] = ext_icon;
return ext_icon;
}
// If no icon found, cache it as null.
_script_icon_cache[p_script] = Ref<Texture>();
return nullptr;
_script_icon_cache[p_script_path] = Ref<Texture2D>();
return Ref<Texture2D>();
}
void EditorData::clear_script_icon_cache() {