From 25f9aee00565996eae4c1cd011c9573a7e37922c Mon Sep 17 00:00:00 2001
From: George Marques <george@gmarqu.es>
Date: Sat, 9 Mar 2019 00:47:27 -0300
Subject: [PATCH] Allow class_name scripts to have nested inheritance

---
 core/io/resource_loader.cpp  | 2 +-
 core/io/resource_saver.cpp   | 2 +-
 core/script_language.cpp     | 8 ++++++++
 core/script_language.h       | 1 +
 editor/create_dialog.cpp     | 2 +-
 editor/editor_data.cpp       | 2 +-
 editor/editor_node.cpp       | 2 +-
 editor/editor_properties.cpp | 2 +-
 editor/scene_tree_dock.cpp   | 4 ++--
 9 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index c917b9ba28d..e4b694b64f5 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -946,7 +946,7 @@ void ResourceLoader::add_custom_loaders() {
 	for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) {
 
 		StringName class_name = E->get();
-		StringName base_class = ScriptServer::get_global_class_base(class_name);
+		StringName base_class = ScriptServer::get_global_class_native_base(class_name);
 
 		if (base_class == custom_loader_base_class) {
 			String path = ScriptServer::get_global_class_path(class_name);
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index c992e2bf94b..0cecca904d2 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -249,7 +249,7 @@ void ResourceSaver::add_custom_savers() {
 	for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) {
 
 		StringName class_name = E->get();
-		StringName base_class = ScriptServer::get_global_class_base(class_name);
+		StringName base_class = ScriptServer::get_global_class_native_base(class_name);
 
 		if (base_class == custom_saver_base_class) {
 			String path = ScriptServer::get_global_class_path(class_name);
diff --git a/core/script_language.cpp b/core/script_language.cpp
index 1c244661b0d..4a6f904f9d4 100644
--- a/core/script_language.cpp
+++ b/core/script_language.cpp
@@ -190,6 +190,14 @@ StringName ScriptServer::get_global_class_base(const String &p_class) {
 	ERR_FAIL_COND_V(!global_classes.has(p_class), String());
 	return global_classes[p_class].base;
 }
+StringName ScriptServer::get_global_class_native_base(const String &p_class) {
+	ERR_FAIL_COND_V(!global_classes.has(p_class), String());
+	String base = global_classes[p_class].base;
+	while (global_classes.has(base)) {
+		base = global_classes[base].base;
+	}
+	return base;
+}
 void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
 	const StringName *K = NULL;
 	List<StringName> classes;
diff --git a/core/script_language.h b/core/script_language.h
index 65fb0f0268a..b6d7bea9c73 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -87,6 +87,7 @@ public:
 	static StringName get_global_class_language(const StringName &p_class);
 	static String get_global_class_path(const String &p_class);
 	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 save_global_classes();
 
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index f42154bd394..364c5126d7d 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -204,7 +204,7 @@ void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p
 		if (cpp_type) {
 			String cpp_to_select_type = to_select_type;
 			if (ScriptServer::is_global_class(to_select_type))
-				cpp_to_select_type = ScriptServer::get_global_class_base(to_select_type);
+				cpp_to_select_type = ScriptServer::get_global_class_native_base(to_select_type);
 			current_item_is_preferred = ClassDB::is_parent_class(p_type, preferred_search_result_type) && !ClassDB::is_parent_class(cpp_to_select_type, preferred_search_result_type);
 		} else {
 			current_item_is_preferred = ed.script_class_is_parent(p_type, preferred_search_result_type) && !ed.script_class_is_parent(to_select_type, preferred_search_result_type) && search_box->get_text() != to_select_type;
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index b87b80dafde..f61a8310159 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -895,7 +895,7 @@ StringName EditorData::script_class_get_base(const String &p_class) const {
 
 Object *EditorData::script_class_instance(const String &p_class) {
 	if (ScriptServer::is_global_class(p_class)) {
-		Object *obj = ClassDB::instance(ScriptServer::get_global_class_base(p_class));
+		Object *obj = ClassDB::instance(ScriptServer::get_global_class_native_base(p_class));
 		if (obj) {
 			RES script = ResourceLoader::load(ScriptServer::get_global_class_path(p_class));
 			if (script.is_valid())
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index f0c9e87b761..1e03adc2198 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -3354,7 +3354,7 @@ Ref<Texture> EditorNode::get_class_icon(const String &p_class, const String &p_f
 			icon = ResourceLoader::load(icon_path);
 		}
 		if (!icon.is_valid()) {
-			icon = gui_base->get_icon(ScriptServer::get_global_class_base(p_class), "EditorIcons");
+			icon = gui_base->get_icon(ScriptServer::get_global_class_native_base(p_class), "EditorIcons");
 		}
 		return icon;
 	}
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 4f32fc7ac40..d7faa444417 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2190,7 +2190,7 @@ void EditorPropertyResource::_menu_option(int p_which) {
 			Object *obj = NULL;
 
 			if (ScriptServer::is_global_class(intype)) {
-				obj = ClassDB::instance(ScriptServer::get_global_class_base(intype));
+				obj = ClassDB::instance(ScriptServer::get_global_class_native_base(intype));
 				if (obj) {
 					Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(intype));
 					if (script.is_valid()) {
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 084830ed7bd..66163d7e0ac 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -827,7 +827,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 			if (TOOL_CREATE_FAVORITE == p_tool) {
 				String name = selected_favorite_root.get_slicec(' ', 0);
 				if (ScriptServer::is_global_class(name)) {
-					new_node = Object::cast_to<Node>(ClassDB::instance(ScriptServer::get_global_class_base(name)));
+					new_node = Object::cast_to<Node>(ClassDB::instance(ScriptServer::get_global_class_native_base(name)));
 					Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script");
 					if (new_node && script.is_valid()) {
 						new_node->set_script(script.get_ref_ptr());
@@ -2294,7 +2294,7 @@ void SceneTreeDock::_update_create_root_dialog() {
 					button->set_text(TTR(l));
 					String name = l.get_slicec(' ', 0);
 					if (ScriptServer::is_global_class(name))
-						name = ScriptServer::get_global_class_base(name);
+						name = ScriptServer::get_global_class_native_base(name);
 					button->set_icon(EditorNode::get_singleton()->get_class_icon(name));
 					button->connect("pressed", this, "_favorite_root_selected", make_binds(l));
 				}