Merge pull request #71683 from reduz/fast-script-class-inheritance-check
Implement a quick script inheritance check
This commit is contained in:
commit
c02572d3d0
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
static void _add_allowed_type(const StringName &p_type, HashSet<StringName> *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<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;
|
||||
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<StringName> *p_vector) const {
|
||||
Vector<String> allowed_types = base_type.split(",");
|
||||
int size = allowed_types.size();
|
||||
|
||||
List<StringName> 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<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;
|
||||
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<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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -219,6 +219,4 @@ void unregister_editor_types() {
|
|||
if (EditorPaths::get_singleton()) {
|
||||
EditorPaths::free();
|
||||
}
|
||||
|
||||
EditorResourcePicker::clear_caches();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue