diff options
Diffstat (limited to 'core/class_db.cpp')
-rw-r--r-- | core/class_db.cpp | 1571 |
1 files changed, 0 insertions, 1571 deletions
diff --git a/core/class_db.cpp b/core/class_db.cpp deleted file mode 100644 index 81bc901561..0000000000 --- a/core/class_db.cpp +++ /dev/null @@ -1,1571 +0,0 @@ -/*************************************************************************/ -/* class_db.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "class_db.h" - -#include "core/engine.h" -#include "core/os/mutex.h" -#include "core/version.h" - -#define OBJTYPE_RLOCK RWLockRead _rw_lockr_(lock); -#define OBJTYPE_WLOCK RWLockWrite _rw_lockw_(lock); - -#ifdef DEBUG_METHODS_ENABLED - -MethodDefinition D_METHOD(const char *p_name) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.push_back(StaticCString::create(p_arg1)); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(2); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(3); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(4); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - md.args.write[3] = StaticCString::create(p_arg4); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(5); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - md.args.write[3] = StaticCString::create(p_arg4); - md.args.write[4] = StaticCString::create(p_arg5); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(6); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - md.args.write[3] = StaticCString::create(p_arg4); - md.args.write[4] = StaticCString::create(p_arg5); - md.args.write[5] = StaticCString::create(p_arg6); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(7); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - md.args.write[3] = StaticCString::create(p_arg4); - md.args.write[4] = StaticCString::create(p_arg5); - md.args.write[5] = StaticCString::create(p_arg6); - md.args.write[6] = StaticCString::create(p_arg7); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(8); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - md.args.write[3] = StaticCString::create(p_arg4); - md.args.write[4] = StaticCString::create(p_arg5); - md.args.write[5] = StaticCString::create(p_arg6); - md.args.write[6] = StaticCString::create(p_arg7); - md.args.write[7] = StaticCString::create(p_arg8); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(9); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - md.args.write[3] = StaticCString::create(p_arg4); - md.args.write[4] = StaticCString::create(p_arg5); - md.args.write[5] = StaticCString::create(p_arg6); - md.args.write[6] = StaticCString::create(p_arg7); - md.args.write[7] = StaticCString::create(p_arg8); - md.args.write[8] = StaticCString::create(p_arg9); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(10); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - md.args.write[3] = StaticCString::create(p_arg4); - md.args.write[4] = StaticCString::create(p_arg5); - md.args.write[5] = StaticCString::create(p_arg6); - md.args.write[6] = StaticCString::create(p_arg7); - md.args.write[7] = StaticCString::create(p_arg8); - md.args.write[8] = StaticCString::create(p_arg9); - md.args.write[9] = StaticCString::create(p_arg10); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(11); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - md.args.write[3] = StaticCString::create(p_arg4); - md.args.write[4] = StaticCString::create(p_arg5); - md.args.write[5] = StaticCString::create(p_arg6); - md.args.write[6] = StaticCString::create(p_arg7); - md.args.write[7] = StaticCString::create(p_arg8); - md.args.write[8] = StaticCString::create(p_arg9); - md.args.write[9] = StaticCString::create(p_arg10); - md.args.write[10] = StaticCString::create(p_arg11); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(12); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - md.args.write[3] = StaticCString::create(p_arg4); - md.args.write[4] = StaticCString::create(p_arg5); - md.args.write[5] = StaticCString::create(p_arg6); - md.args.write[6] = StaticCString::create(p_arg7); - md.args.write[7] = StaticCString::create(p_arg8); - md.args.write[8] = StaticCString::create(p_arg9); - md.args.write[9] = StaticCString::create(p_arg10); - md.args.write[10] = StaticCString::create(p_arg11); - md.args.write[11] = StaticCString::create(p_arg12); - return md; -} - -MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12, const char *p_arg13) { - MethodDefinition md; - md.name = StaticCString::create(p_name); - md.args.resize(13); - md.args.write[0] = StaticCString::create(p_arg1); - md.args.write[1] = StaticCString::create(p_arg2); - md.args.write[2] = StaticCString::create(p_arg3); - md.args.write[3] = StaticCString::create(p_arg4); - md.args.write[4] = StaticCString::create(p_arg5); - md.args.write[5] = StaticCString::create(p_arg6); - md.args.write[6] = StaticCString::create(p_arg7); - md.args.write[7] = StaticCString::create(p_arg8); - md.args.write[8] = StaticCString::create(p_arg9); - md.args.write[9] = StaticCString::create(p_arg10); - md.args.write[10] = StaticCString::create(p_arg11); - md.args.write[11] = StaticCString::create(p_arg12); - md.args.write[12] = StaticCString::create(p_arg13); - return md; -} - -#endif - -ClassDB::APIType ClassDB::current_api = API_CORE; - -void ClassDB::set_current_api(APIType p_api) { - current_api = p_api; -} - -ClassDB::APIType ClassDB::get_current_api() { - return current_api; -} - -HashMap<StringName, ClassDB::ClassInfo> ClassDB::classes; -HashMap<StringName, StringName> ClassDB::resource_base_extensions; -HashMap<StringName, StringName> ClassDB::compat_classes; - -bool ClassDB::_is_parent_class(const StringName &p_class, const StringName &p_inherits) { - StringName inherits = p_class; - - while (inherits.operator String().length()) { - if (inherits == p_inherits) { - return true; - } - inherits = _get_parent_class(inherits); - } - - return false; -} - -bool ClassDB::is_parent_class(const StringName &p_class, const StringName &p_inherits) { - OBJTYPE_RLOCK; - - return _is_parent_class(p_class, p_inherits); -} - -void ClassDB::get_class_list(List<StringName> *p_classes) { - OBJTYPE_RLOCK; - - const StringName *k = nullptr; - - while ((k = classes.next(k))) { - p_classes->push_back(*k); - } - - p_classes->sort(); -} - -void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) { - OBJTYPE_RLOCK; - - const StringName *k = nullptr; - - while ((k = classes.next(k))) { - if (*k != p_class && _is_parent_class(*k, p_class)) { - p_classes->push_back(*k); - } - } -} - -void ClassDB::get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) { - OBJTYPE_RLOCK; - - const StringName *k = nullptr; - - while ((k = classes.next(k))) { - if (*k != p_class && _get_parent_class(*k) == p_class) { - p_classes->push_back(*k); - } - } -} - -StringName ClassDB::get_parent_class_nocheck(const StringName &p_class) { - OBJTYPE_RLOCK; - - ClassInfo *ti = classes.getptr(p_class); - if (!ti) { - return StringName(); - } - return ti->inherits; -} - -StringName ClassDB::get_compatibility_remapped_class(const StringName &p_class) { - if (classes.has(p_class)) { - return p_class; - } - - if (compat_classes.has(p_class)) { - return compat_classes[p_class]; - } - - return p_class; -} - -StringName ClassDB::_get_parent_class(const StringName &p_class) { - ClassInfo *ti = classes.getptr(p_class); - ERR_FAIL_COND_V_MSG(!ti, StringName(), "Cannot get class '" + String(p_class) + "'."); - return ti->inherits; -} - -StringName ClassDB::get_parent_class(const StringName &p_class) { - OBJTYPE_RLOCK; - - return _get_parent_class(p_class); -} - -ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) { - OBJTYPE_RLOCK; - - ClassInfo *ti = classes.getptr(p_class); - - ERR_FAIL_COND_V_MSG(!ti, API_NONE, "Cannot get class '" + String(p_class) + "'."); - return ti->api; -} - -uint64_t ClassDB::get_api_hash(APIType p_api) { - OBJTYPE_RLOCK; -#ifdef DEBUG_METHODS_ENABLED - - uint64_t hash = hash_djb2_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG)); - - List<StringName> names; - - const StringName *k = nullptr; - - while ((k = classes.next(k))) { - names.push_back(*k); - } - //must be alphabetically sorted for hash to compute - names.sort_custom<StringName::AlphCompare>(); - - for (List<StringName>::Element *E = names.front(); E; E = E->next()) { - ClassInfo *t = classes.getptr(E->get()); - ERR_FAIL_COND_V_MSG(!t, 0, "Cannot get class '" + String(E->get()) + "'."); - if (t->api != p_api || !t->exposed) { - continue; - } - hash = hash_djb2_one_64(t->name.hash(), hash); - hash = hash_djb2_one_64(t->inherits.hash(), hash); - - { //methods - - List<StringName> snames; - - k = nullptr; - - while ((k = t->method_map.next(k))) { - String name = k->operator String(); - - ERR_CONTINUE(name.empty()); - - if (name[0] == '_') { - continue; // Ignore non-virtual methods that start with an underscore - } - - snames.push_back(*k); - } - - snames.sort_custom<StringName::AlphCompare>(); - - for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { - MethodBind *mb = t->method_map[F->get()]; - hash = hash_djb2_one_64(mb->get_name().hash(), hash); - hash = hash_djb2_one_64(mb->get_argument_count(), hash); - hash = hash_djb2_one_64(mb->get_argument_type(-1), hash); //return - - for (int i = 0; i < mb->get_argument_count(); i++) { - const PropertyInfo info = mb->get_argument_info(i); - hash = hash_djb2_one_64(info.type, hash); - hash = hash_djb2_one_64(info.name.hash(), hash); - hash = hash_djb2_one_64(info.hint, hash); - hash = hash_djb2_one_64(info.hint_string.hash(), hash); - } - - hash = hash_djb2_one_64(mb->get_default_argument_count(), hash); - - for (int i = 0; i < mb->get_default_argument_count(); i++) { - //hash should not change, i hope for tis - Variant da = mb->get_default_argument(i); - hash = hash_djb2_one_64(da.hash(), hash); - } - - hash = hash_djb2_one_64(mb->get_hint_flags(), hash); - } - } - - { //constants - - List<StringName> snames; - - k = nullptr; - - while ((k = t->constant_map.next(k))) { - snames.push_back(*k); - } - - snames.sort_custom<StringName::AlphCompare>(); - - for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { - hash = hash_djb2_one_64(F->get().hash(), hash); - hash = hash_djb2_one_64(t->constant_map[F->get()], hash); - } - } - - { //signals - - List<StringName> snames; - - k = nullptr; - - while ((k = t->signal_map.next(k))) { - snames.push_back(*k); - } - - snames.sort_custom<StringName::AlphCompare>(); - - for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { - MethodInfo &mi = t->signal_map[F->get()]; - hash = hash_djb2_one_64(F->get().hash(), hash); - for (int i = 0; i < mi.arguments.size(); i++) { - hash = hash_djb2_one_64(mi.arguments[i].type, hash); - } - } - } - - { //properties - - List<StringName> snames; - - k = nullptr; - - while ((k = t->property_setget.next(k))) { - snames.push_back(*k); - } - - snames.sort_custom<StringName::AlphCompare>(); - - for (List<StringName>::Element *F = snames.front(); F; F = F->next()) { - PropertySetGet *psg = t->property_setget.getptr(F->get()); - ERR_FAIL_COND_V(!psg, 0); - - hash = hash_djb2_one_64(F->get().hash(), hash); - hash = hash_djb2_one_64(psg->setter.hash(), hash); - hash = hash_djb2_one_64(psg->getter.hash(), hash); - } - } - - //property list - for (List<PropertyInfo>::Element *F = t->property_list.front(); F; F = F->next()) { - hash = hash_djb2_one_64(F->get().name.hash(), hash); - hash = hash_djb2_one_64(F->get().type, hash); - hash = hash_djb2_one_64(F->get().hint, hash); - hash = hash_djb2_one_64(F->get().hint_string.hash(), hash); - hash = hash_djb2_one_64(F->get().usage, hash); - } - } - - return hash; -#else - return 0; -#endif -} - -bool ClassDB::class_exists(const StringName &p_class) { - OBJTYPE_RLOCK; - return classes.has(p_class); -} - -void ClassDB::add_compatibility_class(const StringName &p_class, const StringName &p_fallback) { - OBJTYPE_WLOCK; - compat_classes[p_class] = p_fallback; -} - -Object *ClassDB::instance(const StringName &p_class) { - ClassInfo *ti; - { - OBJTYPE_RLOCK; - ti = classes.getptr(p_class); - if (!ti || ti->disabled || !ti->creation_func) { - if (compat_classes.has(p_class)) { - ti = classes.getptr(compat_classes[p_class]); - } - } - ERR_FAIL_COND_V_MSG(!ti, nullptr, "Cannot get class '" + String(p_class) + "'."); - ERR_FAIL_COND_V_MSG(ti->disabled, nullptr, "Class '" + String(p_class) + "' is disabled."); - ERR_FAIL_COND_V(!ti->creation_func, nullptr); - } -#ifdef TOOLS_ENABLED - if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) { - ERR_PRINT("Class '" + String(p_class) + "' can only be instantiated by editor."); - return nullptr; - } -#endif - return ti->creation_func(); -} - -bool ClassDB::can_instance(const StringName &p_class) { - OBJTYPE_RLOCK; - - ClassInfo *ti = classes.getptr(p_class); - ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'."); -#ifdef TOOLS_ENABLED - if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) { - return false; - } -#endif - return (!ti->disabled && ti->creation_func != nullptr); -} - -void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) { - OBJTYPE_WLOCK; - - const StringName &name = p_class; - - ERR_FAIL_COND_MSG(classes.has(name), "Class '" + String(p_class) + "' already exists."); - - classes[name] = ClassInfo(); - ClassInfo &ti = classes[name]; - ti.name = name; - ti.inherits = p_inherits; - ti.api = current_api; - - if (ti.inherits) { - ERR_FAIL_COND(!classes.has(ti.inherits)); //it MUST be registered. - ti.inherits_ptr = &classes[ti.inherits]; - - } else { - ti.inherits_ptr = nullptr; - } -} - -#ifdef DEBUG_METHODS_ENABLED -static MethodInfo info_from_bind(MethodBind *p_method) { - MethodInfo minfo; - minfo.name = p_method->get_name(); - minfo.id = p_method->get_method_id(); - - for (int i = 0; i < p_method->get_argument_count(); i++) { - minfo.arguments.push_back(p_method->get_argument_info(i)); - } - - minfo.return_val = p_method->get_return_info(); - minfo.flags = p_method->get_hint_flags(); - - for (int i = 0; i < p_method->get_argument_count(); i++) { - if (p_method->has_default_argument(i)) { - minfo.default_arguments.push_back(p_method->get_default_argument(i)); - } - } - - return minfo; -} -#endif - -void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - - while (type) { - if (type->disabled) { - if (p_no_inheritance) { - break; - } - - type = type->inherits_ptr; - continue; - } - -#ifdef DEBUG_METHODS_ENABLED - - for (List<MethodInfo>::Element *E = type->virtual_methods.front(); E; E = E->next()) { - p_methods->push_back(E->get()); - } - - for (List<StringName>::Element *E = type->method_order.front(); E; E = E->next()) { - if (p_exclude_from_properties && type->methods_in_properties.has(E->get())) { - continue; - } - - MethodBind *method = type->method_map.get(E->get()); - MethodInfo minfo = info_from_bind(method); - - p_methods->push_back(minfo); - } - -#else - - const StringName *K = nullptr; - - while ((K = type->method_map.next(K))) { - MethodBind *m = type->method_map[*K]; - MethodInfo mi; - mi.name = m->get_name(); - p_methods->push_back(mi); - } - -#endif - - if (p_no_inheritance) { - break; - } - - type = type->inherits_ptr; - } -} - -bool ClassDB::get_method_info(StringName p_class, StringName p_method, MethodInfo *r_info, bool p_no_inheritance, bool p_exclude_from_properties) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - - while (type) { - if (type->disabled) { - if (p_no_inheritance) { - break; - } - - type = type->inherits_ptr; - continue; - } - -#ifdef DEBUG_METHODS_ENABLED - MethodBind **method = type->method_map.getptr(p_method); - if (method && *method) { - if (r_info != nullptr) { - MethodInfo minfo = info_from_bind(*method); - *r_info = minfo; - } - return true; - } else if (type->virtual_methods_map.has(p_method)) { - if (r_info) { - *r_info = type->virtual_methods_map[p_method]; - } - return true; - } -#else - if (type->method_map.has(p_method)) { - if (r_info) { - MethodBind *m = type->method_map[p_method]; - MethodInfo mi; - mi.name = m->get_name(); - *r_info = mi; - } - return true; - } -#endif - - if (p_no_inheritance) { - break; - } - - type = type->inherits_ptr; - } - - return false; -} - -MethodBind *ClassDB::get_method(StringName p_class, StringName p_name) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - - while (type) { - MethodBind **method = type->method_map.getptr(p_name); - if (method && *method) { - return *method; - } - type = type->inherits_ptr; - } - return nullptr; -} - -void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int p_constant) { - OBJTYPE_WLOCK; - - ClassInfo *type = classes.getptr(p_class); - - ERR_FAIL_COND(!type); - - if (type->constant_map.has(p_name)) { - ERR_FAIL(); - } - - type->constant_map[p_name] = p_constant; - - String enum_name = p_enum; - if (enum_name != String()) { - if (enum_name.find(".") != -1) { - enum_name = enum_name.get_slicec('.', 1); - } - - List<StringName> *constants_list = type->enum_map.getptr(enum_name); - - if (constants_list) { - constants_list->push_back(p_name); - } else { - List<StringName> new_list; - new_list.push_back(p_name); - type->enum_map[enum_name] = new_list; - } - } - -#ifdef DEBUG_METHODS_ENABLED - type->constant_order.push_back(p_name); -#endif -} - -void ClassDB::get_integer_constant_list(const StringName &p_class, List<String> *p_constants, bool p_no_inheritance) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - - while (type) { -#ifdef DEBUG_METHODS_ENABLED - for (List<StringName>::Element *E = type->constant_order.front(); E; E = E->next()) { - p_constants->push_back(E->get()); - } -#else - const StringName *K = nullptr; - - while ((K = type->constant_map.next(K))) { - p_constants->push_back(*K); - } - -#endif - if (p_no_inheritance) { - break; - } - - type = type->inherits_ptr; - } -} - -int ClassDB::get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - - while (type) { - int *constant = type->constant_map.getptr(p_name); - if (constant) { - if (p_success) { - *p_success = true; - } - return *constant; - } - - type = type->inherits_ptr; - } - - if (p_success) { - *p_success = false; - } - - return 0; -} - -bool ClassDB::has_integer_constant(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - - while (type) { - if (type->constant_map.has(p_name)) { - return true; - } - if (p_no_inheritance) { - return false; - } - - type = type->inherits_ptr; - } - - return false; -} - -StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - - while (type) { - const StringName *k = nullptr; - while ((k = type->enum_map.next(k))) { - List<StringName> &constants_list = type->enum_map.get(*k); - const List<StringName>::Element *found = constants_list.find(p_name); - if (found) { - return *k; - } - } - - if (p_no_inheritance) { - break; - } - - type = type->inherits_ptr; - } - - return StringName(); -} - -void ClassDB::get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - - while (type) { - const StringName *k = nullptr; - while ((k = type->enum_map.next(k))) { - p_enums->push_back(*k); - } - - if (p_no_inheritance) { - break; - } - - type = type->inherits_ptr; - } -} - -void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - - while (type) { - const List<StringName> *constants = type->enum_map.getptr(p_enum); - - if (constants) { - for (const List<StringName>::Element *E = constants->front(); E; E = E->next()) { - p_constants->push_back(E->get()); - } - } - - if (p_no_inheritance) { - break; - } - - type = type->inherits_ptr; - } -} - -bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - - while (type) { - if (type->enum_map.has(p_name)) { - return true; - } - if (p_no_inheritance) { - return false; - } - - type = type->inherits_ptr; - } - - return false; -} - -void ClassDB::add_signal(StringName p_class, const MethodInfo &p_signal) { - OBJTYPE_WLOCK; - - ClassInfo *type = classes.getptr(p_class); - ERR_FAIL_COND(!type); - - StringName sname = p_signal.name; - -#ifdef DEBUG_METHODS_ENABLED - ClassInfo *check = type; - while (check) { - ERR_FAIL_COND_MSG(check->signal_map.has(sname), "Class '" + String(p_class) + "' already has signal '" + String(sname) + "'."); - check = check->inherits_ptr; - } -#endif - - type->signal_map[sname] = p_signal; -} - -void ClassDB::get_signal_list(StringName p_class, List<MethodInfo> *p_signals, bool p_no_inheritance) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - ERR_FAIL_COND(!type); - - ClassInfo *check = type; - - while (check) { - const StringName *S = nullptr; - while ((S = check->signal_map.next(S))) { - p_signals->push_back(check->signal_map[*S]); - } - - if (p_no_inheritance) { - return; - } - - check = check->inherits_ptr; - } -} - -bool ClassDB::has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance) { - OBJTYPE_RLOCK; - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - if (check->signal_map.has(p_signal)) { - return true; - } - if (p_no_inheritance) { - return false; - } - check = check->inherits_ptr; - } - - return false; -} - -bool ClassDB::get_signal(StringName p_class, StringName p_signal, MethodInfo *r_signal) { - OBJTYPE_RLOCK; - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - if (check->signal_map.has(p_signal)) { - if (r_signal) { - *r_signal = check->signal_map[p_signal]; - } - return true; - } - check = check->inherits_ptr; - } - - return false; -} - -void ClassDB::add_property_group(StringName p_class, const String &p_name, const String &p_prefix) { - OBJTYPE_WLOCK; - ClassInfo *type = classes.getptr(p_class); - ERR_FAIL_COND(!type); - - type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_GROUP)); -} - -void ClassDB::add_property_subgroup(StringName p_class, const String &p_name, const String &p_prefix) { - OBJTYPE_WLOCK; - ClassInfo *type = classes.getptr(p_class); - ERR_FAIL_COND(!type); - - type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_SUBGROUP)); -} - -void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) { - lock->read_lock(); - ClassInfo *type = classes.getptr(p_class); - lock->read_unlock(); - - ERR_FAIL_COND(!type); - - MethodBind *mb_set = nullptr; - if (p_setter) { - mb_set = get_method(p_class, p_setter); -#ifdef DEBUG_METHODS_ENABLED - - ERR_FAIL_COND_MSG(!mb_set, "Invalid setter '" + p_class + "::" + p_setter + "' for property '" + p_pinfo.name + "'."); - - int exp_args = 1 + (p_index >= 0 ? 1 : 0); - ERR_FAIL_COND_MSG(mb_set->get_argument_count() != exp_args, "Invalid function for setter '" + p_class + "::" + p_setter + " for property '" + p_pinfo.name + "'."); -#endif - } - - MethodBind *mb_get = nullptr; - if (p_getter) { - mb_get = get_method(p_class, p_getter); -#ifdef DEBUG_METHODS_ENABLED - - ERR_FAIL_COND_MSG(!mb_get, "Invalid getter '" + p_class + "::" + p_getter + "' for property '" + p_pinfo.name + "'."); - - int exp_args = 0 + (p_index >= 0 ? 1 : 0); - ERR_FAIL_COND_MSG(mb_get->get_argument_count() != exp_args, "Invalid function for getter '" + p_class + "::" + p_getter + "' for property: '" + p_pinfo.name + "'."); -#endif - } - -#ifdef DEBUG_METHODS_ENABLED - ERR_FAIL_COND_MSG(type->property_setget.has(p_pinfo.name), "Object '" + p_class + "' already has property '" + p_pinfo.name + "'."); -#endif - - OBJTYPE_WLOCK - - type->property_list.push_back(p_pinfo); - type->property_map[p_pinfo.name] = p_pinfo; -#ifdef DEBUG_METHODS_ENABLED - if (mb_get) { - type->methods_in_properties.insert(p_getter); - } - if (mb_set) { - type->methods_in_properties.insert(p_setter); - } -#endif - PropertySetGet psg; - psg.setter = p_setter; - psg.getter = p_getter; - psg._setptr = mb_set; - psg._getptr = mb_get; - psg.index = p_index; - psg.type = p_pinfo.type; - - type->property_setget[p_pinfo.name] = psg; -} - -void ClassDB::set_property_default_value(StringName p_class, const StringName &p_name, const Variant &p_default) { - if (!default_values.has(p_class)) { - default_values[p_class] = HashMap<StringName, Variant>(); - } - default_values[p_class][p_name] = p_default; -} - -void ClassDB::get_property_list(StringName p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator) { - OBJTYPE_RLOCK; - - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - for (List<PropertyInfo>::Element *E = check->property_list.front(); E; E = E->next()) { - if (p_validator) { - PropertyInfo pi = E->get(); - p_validator->_validate_property(pi); - p_list->push_back(pi); - } else { - p_list->push_back(E->get()); - } - } - - if (p_no_inheritance) { - return; - } - check = check->inherits_ptr; - } -} - -bool ClassDB::get_property_info(StringName p_class, StringName p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) { - OBJTYPE_RLOCK; - - ClassInfo *check = classes.getptr(p_class); - while (check) { - if (check->property_map.has(p_property)) { - PropertyInfo pinfo = check->property_map[p_property]; - if (p_validator) { - p_validator->_validate_property(pinfo); - } - if (r_info) { - *r_info = pinfo; - } - return true; - } - if (p_no_inheritance) { - break; - } - check = check->inherits_ptr; - } - - return false; -} - -bool ClassDB::set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid) { - ClassInfo *type = classes.getptr(p_object->get_class_name()); - ClassInfo *check = type; - while (check) { - const PropertySetGet *psg = check->property_setget.getptr(p_property); - if (psg) { - if (!psg->setter) { - if (r_valid) { - *r_valid = false; - } - return true; //return true but do nothing - } - - Callable::CallError ce; - - if (psg->index >= 0) { - Variant index = psg->index; - const Variant *arg[2] = { &index, &p_value }; - //p_object->call(psg->setter,arg,2,ce); - if (psg->_setptr) { - psg->_setptr->call(p_object, arg, 2, ce); - } else { - p_object->call(psg->setter, arg, 2, ce); - } - - } else { - const Variant *arg[1] = { &p_value }; - if (psg->_setptr) { - psg->_setptr->call(p_object, arg, 1, ce); - } else { - p_object->call(psg->setter, arg, 1, ce); - } - } - - if (r_valid) { - *r_valid = ce.error == Callable::CallError::CALL_OK; - } - - return true; - } - - check = check->inherits_ptr; - } - - return false; -} - -bool ClassDB::get_property(Object *p_object, const StringName &p_property, Variant &r_value) { - ClassInfo *type = classes.getptr(p_object->get_class_name()); - ClassInfo *check = type; - while (check) { - const PropertySetGet *psg = check->property_setget.getptr(p_property); - if (psg) { - if (!psg->getter) { - return true; //return true but do nothing - } - - if (psg->index >= 0) { - Variant index = psg->index; - const Variant *arg[1] = { &index }; - Callable::CallError ce; - r_value = p_object->call(psg->getter, arg, 1, ce); - - } else { - Callable::CallError ce; - if (psg->_getptr) { - r_value = psg->_getptr->call(p_object, nullptr, 0, ce); - } else { - r_value = p_object->call(psg->getter, nullptr, 0, ce); - } - } - return true; - } - - const int *c = check->constant_map.getptr(p_property); //constants count - if (c) { - r_value = *c; - return true; - } - - if (check->method_map.has(p_property)) { //methods count - r_value = Callable(p_object, p_property); - return true; - } - - if (check->signal_map.has(p_property)) { //signals count - r_value = Signal(p_object, p_property); - return true; - } - - check = check->inherits_ptr; - } - - return false; -} - -int ClassDB::get_property_index(const StringName &p_class, const StringName &p_property, bool *r_is_valid) { - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - const PropertySetGet *psg = check->property_setget.getptr(p_property); - if (psg) { - if (r_is_valid) { - *r_is_valid = true; - } - - return psg->index; - } - - check = check->inherits_ptr; - } - if (r_is_valid) { - *r_is_valid = false; - } - - return -1; -} - -Variant::Type ClassDB::get_property_type(const StringName &p_class, const StringName &p_property, bool *r_is_valid) { - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - const PropertySetGet *psg = check->property_setget.getptr(p_property); - if (psg) { - if (r_is_valid) { - *r_is_valid = true; - } - - return psg->type; - } - - check = check->inherits_ptr; - } - if (r_is_valid) { - *r_is_valid = false; - } - - return Variant::NIL; -} - -StringName ClassDB::get_property_setter(StringName p_class, const StringName &p_property) { - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - const PropertySetGet *psg = check->property_setget.getptr(p_property); - if (psg) { - return psg->setter; - } - - check = check->inherits_ptr; - } - - return StringName(); -} - -StringName ClassDB::get_property_getter(StringName p_class, const StringName &p_property) { - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - const PropertySetGet *psg = check->property_setget.getptr(p_property); - if (psg) { - return psg->getter; - } - - check = check->inherits_ptr; - } - - return StringName(); -} - -bool ClassDB::has_property(const StringName &p_class, const StringName &p_property, bool p_no_inheritance) { - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - if (check->property_setget.has(p_property)) { - return true; - } - - if (p_no_inheritance) { - break; - } - check = check->inherits_ptr; - } - - return false; -} - -void ClassDB::set_method_flags(StringName p_class, StringName p_method, int p_flags) { - OBJTYPE_WLOCK; - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - ERR_FAIL_COND(!check); - ERR_FAIL_COND(!check->method_map.has(p_method)); - check->method_map[p_method]->set_hint_flags(p_flags); -} - -bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inheritance) { - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - if (check->method_map.has(p_method)) { - return true; - } - if (p_no_inheritance) { - return false; - } - check = check->inherits_ptr; - } - - return false; -} - -#ifdef DEBUG_METHODS_ENABLED -MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) { - StringName mdname = method_name.name; -#else -MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const char *method_name, const Variant **p_defs, int p_defcount) { - StringName mdname = StaticCString::create(method_name); -#endif - - OBJTYPE_WLOCK; - ERR_FAIL_COND_V(!p_bind, nullptr); - p_bind->set_name(mdname); - - String instance_type = p_bind->get_instance_class(); - -#ifdef DEBUG_ENABLED - - ERR_FAIL_COND_V_MSG(has_method(instance_type, mdname), nullptr, "Class " + String(instance_type) + " already has a method " + String(mdname) + "."); -#endif - - ClassInfo *type = classes.getptr(instance_type); - if (!type) { - memdelete(p_bind); - ERR_FAIL_V_MSG(nullptr, "Couldn't bind method '" + mdname + "' for instance '" + instance_type + "'."); - } - - if (type->method_map.has(mdname)) { - memdelete(p_bind); - // overloading not supported - ERR_FAIL_V_MSG(nullptr, "Method already bound '" + instance_type + "::" + mdname + "'."); - } - -#ifdef DEBUG_METHODS_ENABLED - - if (method_name.args.size() > p_bind->get_argument_count()) { - memdelete(p_bind); - ERR_FAIL_V_MSG(nullptr, "Method definition provides more arguments than the method actually has '" + instance_type + "::" + mdname + "'."); - } - - p_bind->set_argument_names(method_name.args); - - type->method_order.push_back(mdname); -#endif - - type->method_map[mdname] = p_bind; - - Vector<Variant> defvals; - - defvals.resize(p_defcount); - for (int i = 0; i < p_defcount; i++) { - defvals.write[i] = *p_defs[i]; - } - - p_bind->set_default_arguments(defvals); - p_bind->set_hint_flags(p_flags); - return p_bind; -} - -void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual) { - ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'."); - - OBJTYPE_WLOCK; - -#ifdef DEBUG_METHODS_ENABLED - MethodInfo mi = p_method; - if (p_virtual) { - mi.flags |= METHOD_FLAG_VIRTUAL; - } - classes[p_class].virtual_methods.push_back(mi); - classes[p_class].virtual_methods_map[p_method.name] = mi; - -#endif -} - -void ClassDB::get_virtual_methods(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance) { - ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'."); - -#ifdef DEBUG_METHODS_ENABLED - - ClassInfo *type = classes.getptr(p_class); - ClassInfo *check = type; - while (check) { - for (List<MethodInfo>::Element *E = check->virtual_methods.front(); E; E = E->next()) { - p_methods->push_back(E->get()); - } - - if (p_no_inheritance) { - return; - } - check = check->inherits_ptr; - } - -#endif -} - -void ClassDB::set_class_enabled(StringName p_class, bool p_enable) { - OBJTYPE_WLOCK; - - ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'."); - classes[p_class].disabled = !p_enable; -} - -bool ClassDB::is_class_enabled(StringName p_class) { - OBJTYPE_RLOCK; - - ClassInfo *ti = classes.getptr(p_class); - if (!ti || !ti->creation_func) { - if (compat_classes.has(p_class)) { - ti = classes.getptr(compat_classes[p_class]); - } - } - - ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'."); - return !ti->disabled; -} - -bool ClassDB::is_class_exposed(StringName p_class) { - OBJTYPE_RLOCK; - - ClassInfo *ti = classes.getptr(p_class); - ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'."); - return ti->exposed; -} - -StringName ClassDB::get_category(const StringName &p_node) { - ERR_FAIL_COND_V(!classes.has(p_node), StringName()); -#ifdef DEBUG_ENABLED - return classes[p_node].category; -#else - return StringName(); -#endif -} - -void ClassDB::add_resource_base_extension(const StringName &p_extension, const StringName &p_class) { - if (resource_base_extensions.has(p_extension)) { - return; - } - - resource_base_extensions[p_extension] = p_class; -} - -void ClassDB::get_resource_base_extensions(List<String> *p_extensions) { - const StringName *K = nullptr; - - while ((K = resource_base_extensions.next(K))) { - p_extensions->push_back(*K); - } -} - -void ClassDB::get_extensions_for_type(const StringName &p_class, List<String> *p_extensions) { - const StringName *K = nullptr; - - while ((K = resource_base_extensions.next(K))) { - StringName cmp = resource_base_extensions[*K]; - if (is_parent_class(p_class, cmp) || is_parent_class(cmp, p_class)) { - p_extensions->push_back(*K); - } - } -} - -HashMap<StringName, HashMap<StringName, Variant>> ClassDB::default_values; -Set<StringName> ClassDB::default_values_cached; - -Variant ClassDB::class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid) { - if (!default_values_cached.has(p_class)) { - if (!default_values.has(p_class)) { - default_values[p_class] = HashMap<StringName, Variant>(); - } - - Object *c = nullptr; - bool cleanup_c = false; - - if (Engine::get_singleton()->has_singleton(p_class)) { - c = Engine::get_singleton()->get_singleton_object(p_class); - cleanup_c = false; - } else if (ClassDB::can_instance(p_class)) { - c = ClassDB::instance(p_class); - cleanup_c = true; - } - - if (c) { - List<PropertyInfo> plist; - c->get_property_list(&plist); - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - if (E->get().usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR)) { - if (!default_values[p_class].has(E->get().name)) { - Variant v = c->get(E->get().name); - default_values[p_class][E->get().name] = v; - } - } - } - - if (cleanup_c) { - memdelete(c); - } - } - - default_values_cached.insert(p_class); - } - - if (!default_values.has(p_class)) { - if (r_valid != nullptr) { - *r_valid = false; - } - return Variant(); - } - - if (!default_values[p_class].has(p_property)) { - if (r_valid != nullptr) { - *r_valid = false; - } - return Variant(); - } - - if (r_valid != nullptr) { - *r_valid = true; - } - - Variant var = default_values[p_class][p_property]; - -#ifdef DEBUG_ENABLED - // Some properties may have an instantiated Object as default value, - // (like Path2D's `curve` used to have), but that's not a good practice. - // Instead, those properties should use PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT - // to be auto-instantiated when created in the editor. - if (var.get_type() == Variant::OBJECT) { - Object *obj = var.get_validated_object(); - if (obj) { - WARN_PRINT(vformat("Instantiated %s used as default value for %s's \"%s\" property.", obj->get_class(), p_class, p_property)); - } - } -#endif - - return var; -} - -RWLock *ClassDB::lock = nullptr; - -void ClassDB::init() { - lock = RWLock::create(); -} - -void ClassDB::cleanup_defaults() { - default_values.clear(); - default_values_cached.clear(); -} - -void ClassDB::cleanup() { - //OBJTYPE_LOCK; hah not here - - const StringName *k = nullptr; - - while ((k = classes.next(k))) { - ClassInfo &ti = classes[*k]; - - const StringName *m = nullptr; - while ((m = ti.method_map.next(m))) { - memdelete(ti.method_map[*m]); - } - } - classes.clear(); - resource_base_extensions.clear(); - compat_classes.clear(); - - memdelete(lock); -} - -// |