Browse Source

Implement a quick script inheritance check

Optimizes, simplifies and fixes EditorResourcePicker (was not refreshing custom clases).
Juan Linietsky 2 years ago
parent
commit
3dcf380161

+ 31 - 0
core/object/script_language.cpp

@@ -245,9 +245,12 @@ void ScriptServer::thread_exit() {
 }
 
 HashMap<StringName, ScriptServer::GlobalScriptClass> ScriptServer::global_classes;
+HashMap<StringName, Vector<StringName>> 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<StringName> *r_classes) {
+	if (inheriters_cache_dirty) {
+		inheriters_cache.clear();
+		for (const KeyValue<StringName, GlobalScriptClass> &K : global_classes) {
+			if (!inheriters_cache.has(K.value.base)) {
+				inheriters_cache[K.value.base] = Vector<StringName>();
+			}
+			inheriters_cache[K.value.base].push_back(K.key);
+		}
+		for (KeyValue<StringName, Vector<StringName>> &K : inheriters_cache) {
+			K.value.sort_custom<StringName::AlphCompare>();
+		}
+		inheriters_cache_dirty = false;
+	}
+
+	if (!inheriters_cache.has(p_base_type)) {
+		return;
+	}
+
+	const Vector<StringName> &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<StringName, GlobalScriptClass> &kv : global_classes) {
 		if (kv.value.path == p_path) {
 			global_classes.erase(kv.key);
+			inheriters_cache_dirty = true;
 			return;
 		}
 	}

+ 4 - 1
core/object/script_language.h

@@ -56,10 +56,12 @@ class ScriptServer {
 	struct GlobalScriptClass {
 		StringName language;
 		String path;
-		String base;
+		StringName base;
 	};
 
 	static HashMap<StringName, GlobalScriptClass> global_classes;
+	static HashMap<StringName, Vector<StringName>> 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<StringName> *r_global_classes);
+	static void get_inheriters_list(const StringName &p_base_type, List<StringName> *r_classes);
 	static void save_global_classes();
 
 	static void init_languages();

+ 44 - 71
editor/editor_resource_picker.cpp

@@ -42,12 +42,6 @@
 #include "editor/plugins/script_editor_plugin.h"
 #include "editor/scene_tree_dock.h"
 
-HashMap<StringName, List<StringName>> 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<String> allowed_types;
+		HashSet<StringName> allowed_types;
 		_get_allowed_types(false, &allowed_types);
 
 		Vector<EditorData::CustomType> 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<Resource> &p_resource)
 	return res_type;
 }
 
-void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const {
-	Vector<String> allowed_types = base_type.split(",");
-	int size = allowed_types.size();
+static void _add_allowed_type(const StringName &p_type, HashSet<StringName> *p_vector) {
+	if (p_vector->has(p_type)) {
+		// Already added
+		return;
+	}
 
-	List<StringName> global_classes;
-	ScriptServer::get_global_class_list(&global_classes);
+	if (ClassDB::class_exists(p_type)) {
+		// Engine class,
 
-	for (int i = 0; i < size; i++) {
-		String base = allowed_types[i].strip_edges();
-		if (!ClassDB::is_virtual(base)) {
-			p_vector->insert(base);
+		if (!ClassDB::is_virtual(p_type)) {
+			p_vector->insert(p_type);
 		}
 
-		// If we hit a familiar base type, take all the data from cache.
-		if (allowed_types_cache.has(base)) {
-			List<StringName> 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<StringName> allowed_subtypes;
+		List<StringName> 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<StringName> 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);
-			}
+	List<StringName> inheriters;
+	ScriptServer::get_inheriters_list(p_type, &inheriters);
+	for (const StringName &S : inheriters) {
+		_add_allowed_type(S, p_vector);
+	}
+}
 
-			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);
-				}
-			}
+void EditorResourcePicker::_get_allowed_types(bool p_with_convert, HashSet<StringName> *p_vector) const {
+	Vector<String> allowed_types = base_type.split(",");
+	int size = allowed_types.size();
 
-			// Store the subtypes of the base type in the cache for future use.
-			allowed_types_cache[base] = allowed_subtypes;
-		}
+	for (int i = 0; i < size; i++) {
+		String base = allowed_types[i].strip_edges();
+
+		_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<Strin
 			}
 		}
 	}
-
-	if (EditorNode::get_editor_data().get_custom_types().has("Resource")) {
-		Vector<EditorData::CustomType> 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<String> allowed_types;
+	HashSet<StringName> 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<String> 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<StringName> 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<String> allowed_types;
+		HashSet<StringName> 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<Texture2D>(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<String> allowed_types;
+		HashSet<StringName> 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<String> allowed_types;
-		_get_allowed_types(false, &allowed_types);
 	}
 }
 
@@ -858,7 +831,7 @@ String EditorResourcePicker::get_base_type() const {
 }
 
 Vector<String> EditorResourcePicker::get_allowed_types() const {
-	HashSet<String> allowed_types;
+	HashSet<StringName> allowed_types;
 	_get_allowed_types(false, &allowed_types);
 
 	Vector<String> types;
@@ -866,7 +839,7 @@ Vector<String> 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<Resource> p_resource) {
 	}
 
 	if (!base_type.is_empty()) {
-		HashSet<String> allowed_types;
+		HashSet<StringName> allowed_types;
 		_get_allowed_types(true, &allowed_types);
 
 		StringName custom_class;

+ 2 - 6
editor/editor_resource_picker.h

@@ -42,8 +42,6 @@ class EditorQuickOpen;
 class EditorResourcePicker : public HBoxContainer {
 	GDCLASS(EditorResourcePicker, HBoxContainer);
 
-	static HashMap<StringName, List<StringName>> allowed_types_cache;
-
 	String base_type;
 	Ref<Resource> edited_resource;
 
@@ -92,9 +90,9 @@ class EditorResourcePicker : public HBoxContainer {
 	void _button_input(const Ref<InputEvent> &p_event);
 
 	String _get_resource_type(const Ref<Resource> &p_resource) const;
-	void _get_allowed_types(bool p_with_convert, HashSet<String> *p_vector) const;
+	void _get_allowed_types(bool p_with_convert, HashSet<StringName> *p_vector) const;
 	bool _is_drop_valid(const Dictionary &p_drag_data) const;
-	bool _is_type_valid(const String p_type_name, HashSet<String> p_allowed_types) const;
+	bool _is_type_valid(const String p_type_name, HashSet<StringName> 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<String> get_allowed_types() const;

+ 0 - 2
editor/register_editor_types.cpp

@@ -219,6 +219,4 @@ void unregister_editor_types() {
 	if (EditorPaths::get_singleton()) {
 		EditorPaths::free();
 	}
-
-	EditorResourcePicker::clear_caches();
 }