feat: updated engine version to 4.4-rc1
This commit is contained in:
parent
ee00efde1f
commit
21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions
|
|
@ -33,7 +33,6 @@
|
|||
#include "core/config/engine.h"
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/object/script_language.h"
|
||||
#include "core/os/mutex.h"
|
||||
#include "core/version.h"
|
||||
|
||||
#define OBJTYPE_RLOCK RWLockRead _rw_lockr_(lock);
|
||||
|
|
@ -181,7 +180,7 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static GDExtensionObjectPtr placeholder_class_create_instance(void *p_class_userdata) {
|
||||
static GDExtensionObjectPtr placeholder_class_create_instance(void *p_class_userdata, GDExtensionBool p_notify_postinitialize) {
|
||||
ClassDB::ClassInfo *ti = (ClassDB::ClassInfo *)p_class_userdata;
|
||||
|
||||
// Find the closest native parent, that isn't a runtime class.
|
||||
|
|
@ -192,7 +191,7 @@ public:
|
|||
ERR_FAIL_NULL_V(native_parent->creation_func, nullptr);
|
||||
|
||||
// Construct a placeholder.
|
||||
Object *obj = native_parent->creation_func();
|
||||
Object *obj = native_parent->creation_func(static_cast<bool>(p_notify_postinitialize));
|
||||
|
||||
// ClassDB::set_object_extension_instance() won't be called for placeholders.
|
||||
// We need need to make sure that all the things it would have done (even if
|
||||
|
|
@ -220,23 +219,19 @@ public:
|
|||
memdelete(instance);
|
||||
}
|
||||
|
||||
static GDExtensionClassCallVirtual placeholder_class_get_virtual(void *p_class_userdata, GDExtensionConstStringNamePtr p_name) {
|
||||
static GDExtensionClassCallVirtual placeholder_class_get_virtual(void *p_class_userdata, GDExtensionConstStringNamePtr p_name, uint32_t p_hash) {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
bool ClassDB::_is_parent_class(const StringName &p_class, const StringName &p_inherits) {
|
||||
if (!classes.has(p_class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
StringName inherits = p_class;
|
||||
while (inherits.operator String().length()) {
|
||||
if (inherits == p_inherits) {
|
||||
ClassInfo *c = classes.getptr(p_class);
|
||||
while (c) {
|
||||
if (c->name == p_inherits) {
|
||||
return true;
|
||||
}
|
||||
inherits = _get_parent_class(inherits);
|
||||
c = c->inherits_ptr;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -271,6 +266,22 @@ void ClassDB::get_extensions_class_list(List<StringName> *p_classes) {
|
|||
|
||||
p_classes->sort_custom<StringName::AlphCompare>();
|
||||
}
|
||||
|
||||
void ClassDB::get_extension_class_list(const Ref<GDExtension> &p_extension, List<StringName> *p_classes) {
|
||||
OBJTYPE_RLOCK;
|
||||
|
||||
for (const KeyValue<StringName, ClassInfo> &E : classes) {
|
||||
if (E.value.api != API_EXTENSION && E.value.api != API_EDITOR_EXTENSION) {
|
||||
continue;
|
||||
}
|
||||
if (!E.value.gdextension || E.value.gdextension->library != p_extension.ptr()) {
|
||||
continue;
|
||||
}
|
||||
p_classes->push_back(E.key);
|
||||
}
|
||||
|
||||
p_classes->sort_custom<StringName::AlphCompare>();
|
||||
}
|
||||
#endif
|
||||
|
||||
void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
|
||||
|
|
@ -303,6 +314,29 @@ StringName ClassDB::get_parent_class_nocheck(const StringName &p_class) {
|
|||
return ti->inherits;
|
||||
}
|
||||
|
||||
bool ClassDB::get_inheritance_chain_nocheck(const StringName &p_class, Vector<StringName> &r_result) {
|
||||
OBJTYPE_RLOCK;
|
||||
|
||||
ClassInfo *start = classes.getptr(p_class);
|
||||
if (!start) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int classes_to_add = 0;
|
||||
for (ClassInfo *ti = start; ti; ti = ti->inherits_ptr) {
|
||||
classes_to_add++;
|
||||
}
|
||||
|
||||
int64_t old_size = r_result.size();
|
||||
r_result.resize(old_size + classes_to_add);
|
||||
StringName *w = r_result.ptrw() + old_size;
|
||||
for (ClassInfo *ti = start; ti; ti = ti->inherits_ptr) {
|
||||
*w++ = ti->name;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
StringName ClassDB::get_compatibility_remapped_class(const StringName &p_class) {
|
||||
if (classes.has(p_class)) {
|
||||
return p_class;
|
||||
|
|
@ -317,7 +351,7 @@ StringName ClassDB::get_compatibility_remapped_class(const StringName &p_class)
|
|||
|
||||
StringName ClassDB::_get_parent_class(const StringName &p_class) {
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
ERR_FAIL_NULL_V_MSG(ti, StringName(), "Cannot get class '" + String(p_class) + "'.");
|
||||
ERR_FAIL_NULL_V_MSG(ti, StringName(), vformat("Cannot get class '%s'.", String(p_class)));
|
||||
return ti->inherits;
|
||||
}
|
||||
|
||||
|
|
@ -332,7 +366,7 @@ ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) {
|
|||
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
|
||||
ERR_FAIL_NULL_V_MSG(ti, API_NONE, "Cannot get class '" + String(p_class) + "'.");
|
||||
ERR_FAIL_NULL_V_MSG(ti, API_NONE, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
return ti->api;
|
||||
}
|
||||
|
||||
|
|
@ -355,7 +389,7 @@ uint32_t ClassDB::get_api_hash(APIType p_api) {
|
|||
|
||||
for (const StringName &E : class_list) {
|
||||
ClassInfo *t = classes.getptr(E);
|
||||
ERR_FAIL_NULL_V_MSG(t, 0, "Cannot get class '" + String(E) + "'.");
|
||||
ERR_FAIL_NULL_V_MSG(t, 0, vformat("Cannot get class '%s'.", String(E)));
|
||||
if (t->api != p_api || !t->exposed) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -419,7 +453,7 @@ uint32_t ClassDB::get_api_hash(APIType p_api) {
|
|||
|
||||
for (const StringName &F : snames) {
|
||||
hash = hash_murmur3_one_64(F.hash(), hash);
|
||||
hash = hash_murmur3_one_64(t->constant_map[F], hash);
|
||||
hash = hash_murmur3_one_64(uint64_t(t->constant_map[F]), hash);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -502,48 +536,92 @@ StringName ClassDB::get_compatibility_class(const StringName &p_class) {
|
|||
return StringName();
|
||||
}
|
||||
|
||||
Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require_real_class) {
|
||||
Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require_real_class, bool p_notify_postinitialize) {
|
||||
ClassInfo *ti;
|
||||
{
|
||||
OBJTYPE_RLOCK;
|
||||
ti = classes.getptr(p_class);
|
||||
if (!ti || ti->disabled || !ti->creation_func || (ti->gdextension && !ti->gdextension->create_instance)) {
|
||||
if (!_can_instantiate(ti)) {
|
||||
if (compat_classes.has(p_class)) {
|
||||
ti = classes.getptr(compat_classes[p_class]);
|
||||
}
|
||||
}
|
||||
ERR_FAIL_NULL_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_NULL_V_MSG(ti->creation_func, nullptr, "Class '" + String(p_class) + "' or its base class cannot be instantiated.");
|
||||
ERR_FAIL_NULL_V_MSG(ti, nullptr, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
ERR_FAIL_COND_V_MSG(ti->disabled, nullptr, vformat("Class '%s' is disabled.", String(p_class)));
|
||||
ERR_FAIL_NULL_V_MSG(ti->creation_func, nullptr, vformat("Class '%s' or its base class cannot be instantiated.", String(p_class)));
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
|
||||
ERR_PRINT("Class '" + String(p_class) + "' can only be instantiated by editor.");
|
||||
ERR_PRINT(vformat("Class '%s' can only be instantiated by editor.", String(p_class)));
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
if (ti->gdextension && ti->gdextension->create_instance) {
|
||||
ObjectGDExtension *extension = ti->gdextension;
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!p_require_real_class && ti->is_runtime && Engine::get_singleton()->is_editor_hint()) {
|
||||
extension = get_placeholder_extension(ti->name);
|
||||
}
|
||||
#endif
|
||||
return (Object *)extension->create_instance(extension->class_userdata);
|
||||
} else {
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (!p_require_real_class && ti->is_runtime && Engine::get_singleton()->is_editor_hint()) {
|
||||
if (!ti->inherits_ptr || !ti->inherits_ptr->creation_func) {
|
||||
ERR_PRINT(vformat("Cannot make a placeholder instance of runtime class %s because its parent cannot be constructed.", ti->name));
|
||||
} else {
|
||||
ObjectGDExtension *extension = get_placeholder_extension(ti->name);
|
||||
return (Object *)extension->create_instance(extension->class_userdata);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ti->creation_func();
|
||||
#ifdef TOOLS_ENABLED
|
||||
// Try to create placeholder.
|
||||
if (!p_require_real_class && ti->is_runtime && Engine::get_singleton()->is_editor_hint()) {
|
||||
bool can_create_placeholder = false;
|
||||
if (ti->gdextension) {
|
||||
if (ti->gdextension->create_instance2) {
|
||||
can_create_placeholder = true;
|
||||
}
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
else if (ti->gdextension->create_instance) {
|
||||
can_create_placeholder = true;
|
||||
}
|
||||
#endif // DISABLE_DEPRECATED
|
||||
} else if (!ti->inherits_ptr || !ti->inherits_ptr->creation_func) {
|
||||
ERR_PRINT(vformat("Cannot make a placeholder instance of runtime class %s because its parent cannot be constructed.", ti->name));
|
||||
} else {
|
||||
can_create_placeholder = true;
|
||||
}
|
||||
|
||||
if (can_create_placeholder) {
|
||||
ObjectGDExtension *extension = get_placeholder_extension(ti->name);
|
||||
return (Object *)extension->create_instance2(extension->class_userdata, p_notify_postinitialize);
|
||||
}
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
if (ti->gdextension && ti->gdextension->create_instance2) {
|
||||
ObjectGDExtension *extension = ti->gdextension;
|
||||
return (Object *)extension->create_instance2(extension->class_userdata, p_notify_postinitialize);
|
||||
}
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
else if (ti->gdextension && ti->gdextension->create_instance) {
|
||||
ObjectGDExtension *extension = ti->gdextension;
|
||||
return (Object *)extension->create_instance(extension->class_userdata);
|
||||
}
|
||||
#endif // DISABLE_DEPRECATED
|
||||
else {
|
||||
return ti->creation_func(p_notify_postinitialize);
|
||||
}
|
||||
}
|
||||
|
||||
bool ClassDB::_can_instantiate(ClassInfo *p_class_info) {
|
||||
if (!p_class_info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p_class_info->disabled || !p_class_info->creation_func) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!p_class_info->gdextension) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (p_class_info->gdextension->create_instance2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (p_class_info->gdextension->create_instance) {
|
||||
return true;
|
||||
}
|
||||
#endif // DISABLE_DEPRECATED
|
||||
return false;
|
||||
}
|
||||
|
||||
Object *ClassDB::instantiate(const StringName &p_class) {
|
||||
|
|
@ -554,6 +632,10 @@ Object *ClassDB::instantiate_no_placeholders(const StringName &p_class) {
|
|||
return _instantiate_internal(p_class, true);
|
||||
}
|
||||
|
||||
Object *ClassDB::instantiate_without_postinitialization(const StringName &p_class) {
|
||||
return _instantiate_internal(p_class, true, false);
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
ObjectGDExtension *ClassDB::get_placeholder_extension(const StringName &p_class) {
|
||||
ObjectGDExtension *placeholder_extension = placeholder_extensions.getptr(p_class);
|
||||
|
|
@ -565,13 +647,13 @@ ObjectGDExtension *ClassDB::get_placeholder_extension(const StringName &p_class)
|
|||
{
|
||||
OBJTYPE_RLOCK;
|
||||
ti = classes.getptr(p_class);
|
||||
if (!ti || ti->disabled || !ti->creation_func || (ti->gdextension && !ti->gdextension->create_instance)) {
|
||||
if (!_can_instantiate(ti)) {
|
||||
if (compat_classes.has(p_class)) {
|
||||
ti = classes.getptr(compat_classes[p_class]);
|
||||
}
|
||||
}
|
||||
ERR_FAIL_NULL_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_NULL_V_MSG(ti, nullptr, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
ERR_FAIL_COND_V_MSG(ti->disabled, nullptr, vformat("Class '%s' is disabled.", String(p_class)));
|
||||
}
|
||||
|
||||
// Make a "fake" extension to act as a placeholder.
|
||||
|
|
@ -626,10 +708,17 @@ ObjectGDExtension *ClassDB::get_placeholder_extension(const StringName &p_class)
|
|||
placeholder_extension->get_rid = &PlaceholderExtensionInstance::placeholder_instance_get_rid;
|
||||
|
||||
placeholder_extension->class_userdata = ti;
|
||||
placeholder_extension->create_instance = &PlaceholderExtensionInstance::placeholder_class_create_instance;
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
placeholder_extension->create_instance = nullptr;
|
||||
#endif // DISABLE_DEPRECATED
|
||||
placeholder_extension->create_instance2 = &PlaceholderExtensionInstance::placeholder_class_create_instance;
|
||||
placeholder_extension->free_instance = &PlaceholderExtensionInstance::placeholder_class_free_instance;
|
||||
placeholder_extension->get_virtual = &PlaceholderExtensionInstance::placeholder_class_get_virtual;
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
placeholder_extension->get_virtual = nullptr;
|
||||
placeholder_extension->get_virtual_call_data = nullptr;
|
||||
#endif // DISABLE_DEPRECATED
|
||||
placeholder_extension->get_virtual2 = &PlaceholderExtensionInstance::placeholder_class_get_virtual;
|
||||
placeholder_extension->get_virtual_call_data2 = nullptr;
|
||||
placeholder_extension->call_virtual_with_data = nullptr;
|
||||
placeholder_extension->recreate_instance = &PlaceholderExtensionInstance::placeholder_class_recreate_instance;
|
||||
|
||||
|
|
@ -643,14 +732,14 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName &
|
|||
{
|
||||
OBJTYPE_RLOCK;
|
||||
ti = classes.getptr(p_class);
|
||||
if (!ti || ti->disabled || !ti->creation_func || (ti->gdextension && !ti->gdextension->create_instance)) {
|
||||
if (!_can_instantiate(ti)) {
|
||||
if (compat_classes.has(p_class)) {
|
||||
ti = classes.getptr(compat_classes[p_class]);
|
||||
}
|
||||
}
|
||||
ERR_FAIL_NULL_MSG(ti, "Cannot get class '" + String(p_class) + "'.");
|
||||
ERR_FAIL_COND_MSG(ti->disabled, "Class '" + String(p_class) + "' is disabled.");
|
||||
ERR_FAIL_NULL_MSG(ti->gdextension, "Class '" + String(p_class) + "' has no native extension.");
|
||||
ERR_FAIL_NULL_MSG(ti, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
ERR_FAIL_COND_MSG(ti->disabled, vformat("Class '%s' is disabled.", String(p_class)));
|
||||
ERR_FAIL_NULL_MSG(ti->gdextension, vformat("Class '%s' has no native extension.", String(p_class)));
|
||||
}
|
||||
|
||||
p_object->_extension = ti->gdextension;
|
||||
|
|
@ -664,58 +753,87 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName &
|
|||
}
|
||||
|
||||
bool ClassDB::can_instantiate(const StringName &p_class) {
|
||||
OBJTYPE_RLOCK;
|
||||
String script_path;
|
||||
{
|
||||
OBJTYPE_RLOCK;
|
||||
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
if (!ti) {
|
||||
if (!ScriptServer::is_global_class(p_class)) {
|
||||
ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'.");
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
if (!ti) {
|
||||
if (!ScriptServer::is_global_class(p_class)) {
|
||||
ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
}
|
||||
script_path = ScriptServer::get_global_class_path(p_class);
|
||||
goto use_script; // Open the lock for resource loading.
|
||||
}
|
||||
String path = ScriptServer::get_global_class_path(p_class);
|
||||
Ref<Script> scr = ResourceLoader::load(path);
|
||||
return scr.is_valid() && scr->is_valid() && !scr->is_abstract();
|
||||
}
|
||||
#ifdef TOOLS_ENABLED
|
||||
if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
|
||||
return false;
|
||||
}
|
||||
if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return (!ti->disabled && ti->creation_func != nullptr && !(ti->gdextension && !ti->gdextension->create_instance));
|
||||
return _can_instantiate(ti);
|
||||
}
|
||||
|
||||
use_script:
|
||||
Ref<Script> scr = ResourceLoader::load(script_path);
|
||||
return scr.is_valid() && scr->is_valid() && !scr->is_abstract();
|
||||
}
|
||||
|
||||
bool ClassDB::is_abstract(const StringName &p_class) {
|
||||
OBJTYPE_RLOCK;
|
||||
String script_path;
|
||||
{
|
||||
OBJTYPE_RLOCK;
|
||||
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
if (!ti) {
|
||||
if (!ScriptServer::is_global_class(p_class)) {
|
||||
ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'.");
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
if (!ti) {
|
||||
if (!ScriptServer::is_global_class(p_class)) {
|
||||
ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
}
|
||||
script_path = ScriptServer::get_global_class_path(p_class);
|
||||
goto use_script; // Open the lock for resource loading.
|
||||
}
|
||||
String path = ScriptServer::get_global_class_path(p_class);
|
||||
Ref<Script> scr = ResourceLoader::load(path);
|
||||
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
|
||||
|
||||
if (ti->creation_func != nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (!ti->gdextension) {
|
||||
return true;
|
||||
}
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
return ti->gdextension->create_instance2 == nullptr && ti->gdextension->create_instance == nullptr;
|
||||
#else
|
||||
return ti->gdextension->create_instance2 == nullptr;
|
||||
#endif // DISABLE_DEPRECATED
|
||||
}
|
||||
return ti->creation_func == nullptr && (!ti->gdextension || ti->gdextension->create_instance == nullptr);
|
||||
|
||||
use_script:
|
||||
Ref<Script> scr = ResourceLoader::load(script_path);
|
||||
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
|
||||
}
|
||||
|
||||
bool ClassDB::is_virtual(const StringName &p_class) {
|
||||
OBJTYPE_RLOCK;
|
||||
String script_path;
|
||||
{
|
||||
OBJTYPE_RLOCK;
|
||||
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
if (!ti) {
|
||||
if (!ScriptServer::is_global_class(p_class)) {
|
||||
ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'.");
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
if (!ti) {
|
||||
if (!ScriptServer::is_global_class(p_class)) {
|
||||
ERR_FAIL_V_MSG(false, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
}
|
||||
script_path = ScriptServer::get_global_class_path(p_class);
|
||||
goto use_script; // Open the lock for resource loading.
|
||||
}
|
||||
String path = ScriptServer::get_global_class_path(p_class);
|
||||
Ref<Script> scr = ResourceLoader::load(path);
|
||||
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
|
||||
}
|
||||
#ifdef TOOLS_ENABLED
|
||||
if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
|
||||
return false;
|
||||
}
|
||||
if ((ti->api == API_EDITOR || ti->api == API_EDITOR_EXTENSION) && !Engine::get_singleton()->is_editor_hint()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return (!ti->disabled && ti->creation_func != nullptr && !(ti->gdextension && !ti->gdextension->create_instance) && ti->is_virtual);
|
||||
return (_can_instantiate(ti) && ti->is_virtual);
|
||||
}
|
||||
|
||||
use_script:
|
||||
Ref<Script> scr = ResourceLoader::load(script_path);
|
||||
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
|
||||
}
|
||||
|
||||
void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) {
|
||||
|
|
@ -723,7 +841,7 @@ void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherit
|
|||
|
||||
const StringName &name = p_class;
|
||||
|
||||
ERR_FAIL_COND_MSG(classes.has(name), "Class '" + String(p_class) + "' already exists.");
|
||||
ERR_FAIL_COND_MSG(classes.has(name), vformat("Class '%s' already exists.", String(p_class)));
|
||||
|
||||
classes[name] = ClassInfo();
|
||||
ClassInfo &ti = classes[name];
|
||||
|
|
@ -824,7 +942,7 @@ void ClassDB::get_method_list_with_compatibility(const StringName &p_class, List
|
|||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
for (const MethodInfo &E : type->virtual_methods) {
|
||||
Pair<MethodInfo, uint32_t> pair(E, 0);
|
||||
Pair<MethodInfo, uint32_t> pair(E, E.get_compatibility_hash());
|
||||
p_methods->push_back(pair);
|
||||
}
|
||||
|
||||
|
|
@ -1001,7 +1119,7 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName
|
|||
|
||||
String enum_name = p_enum;
|
||||
if (!enum_name.is_empty()) {
|
||||
if (enum_name.contains(".")) {
|
||||
if (enum_name.contains_char('.')) {
|
||||
enum_name = enum_name.get_slicec('.', 1);
|
||||
}
|
||||
|
||||
|
|
@ -1231,7 +1349,7 @@ void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal)
|
|||
#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) + "'.");
|
||||
ERR_FAIL_COND_MSG(check->signal_map.has(sname), vformat("Class '%s' already has signal '%s'.", String(p_class), String(sname)));
|
||||
check = check->inherits_ptr;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1345,10 +1463,10 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf
|
|||
mb_set = get_method(p_class, p_setter);
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
|
||||
ERR_FAIL_NULL_MSG(mb_set, "Invalid setter '" + p_class + "::" + p_setter + "' for property '" + p_pinfo.name + "'.");
|
||||
ERR_FAIL_NULL_MSG(mb_set, vformat("Invalid setter '%s::%s' for property '%s'.", p_class, p_setter, 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 + "'.");
|
||||
ERR_FAIL_COND_MSG(mb_set->get_argument_count() != exp_args, vformat("Invalid function for setter '%s::%s' for property '%s'.", p_class, p_setter, p_pinfo.name));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -1357,15 +1475,15 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf
|
|||
mb_get = get_method(p_class, p_getter);
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
|
||||
ERR_FAIL_NULL_MSG(mb_get, "Invalid getter '" + p_class + "::" + p_getter + "' for property '" + p_pinfo.name + "'.");
|
||||
ERR_FAIL_NULL_MSG(mb_get, vformat("Invalid getter '%s::%s' for property '%s'.", p_class, p_getter, 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 + "'.");
|
||||
ERR_FAIL_COND_MSG(mb_get->get_argument_count() != exp_args, vformat("Invalid function for getter '%s::%s' for property '%s'.", p_class, p_getter, 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 + "'.");
|
||||
ERR_FAIL_COND_MSG(type->property_setget.has(p_pinfo.name), vformat("Object '%s' already has property '%s'.", p_class, p_pinfo.name));
|
||||
#endif
|
||||
|
||||
OBJTYPE_WLOCK
|
||||
|
|
@ -1547,14 +1665,16 @@ bool ClassDB::get_property(Object *p_object, const StringName &p_property, Varia
|
|||
Variant index = psg->index;
|
||||
const Variant *arg[1] = { &index };
|
||||
Callable::CallError ce;
|
||||
r_value = p_object->callp(psg->getter, arg, 1, ce);
|
||||
const Variant value = p_object->callp(psg->getter, arg, 1, ce);
|
||||
r_value = (ce.error == Callable::CallError::CALL_OK) ? value : Variant();
|
||||
|
||||
} else {
|
||||
Callable::CallError ce;
|
||||
if (psg->_getptr) {
|
||||
r_value = psg->_getptr->call(p_object, nullptr, 0, ce);
|
||||
} else {
|
||||
r_value = p_object->callp(psg->getter, nullptr, 0, ce);
|
||||
const Variant value = p_object->callp(psg->getter, nullptr, 0, ce);
|
||||
r_value = (ce.error == Callable::CallError::CALL_OK) ? value : Variant();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -1746,9 +1866,12 @@ void ClassDB::_bind_compatibility(ClassInfo *type, MethodBind *p_method) {
|
|||
void ClassDB::_bind_method_custom(const StringName &p_class, MethodBind *p_method, bool p_compatibility) {
|
||||
OBJTYPE_WLOCK;
|
||||
|
||||
StringName method_name = p_method->get_name();
|
||||
|
||||
ClassInfo *type = classes.getptr(p_class);
|
||||
if (!type) {
|
||||
ERR_FAIL_MSG("Couldn't bind custom method '" + p_method->get_name() + "' for instance '" + p_class + "'.");
|
||||
memdelete(p_method);
|
||||
ERR_FAIL_MSG(vformat("Couldn't bind custom method '%s' for instance '%s'.", method_name, p_class));
|
||||
}
|
||||
|
||||
if (p_compatibility) {
|
||||
|
|
@ -1756,16 +1879,17 @@ void ClassDB::_bind_method_custom(const StringName &p_class, MethodBind *p_metho
|
|||
return;
|
||||
}
|
||||
|
||||
if (type->method_map.has(p_method->get_name())) {
|
||||
if (type->method_map.has(method_name)) {
|
||||
// overloading not supported
|
||||
ERR_FAIL_MSG("Method already bound '" + p_class + "::" + p_method->get_name() + "'.");
|
||||
memdelete(p_method);
|
||||
ERR_FAIL_MSG(vformat("Method already bound '%s::%s'.", p_class, method_name));
|
||||
}
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
type->method_order.push_back(p_method->get_name());
|
||||
type->method_order.push_back(method_name);
|
||||
#endif
|
||||
|
||||
type->method_map[p_method->get_name()] = p_method;
|
||||
type->method_map[method_name] = p_method;
|
||||
}
|
||||
|
||||
MethodBind *ClassDB::_bind_vararg_method(MethodBind *p_bind, const StringName &p_name, const Vector<Variant> &p_default_args, bool p_compatibility) {
|
||||
|
|
@ -1789,7 +1913,7 @@ MethodBind *ClassDB::_bind_vararg_method(MethodBind *p_bind, const StringName &p
|
|||
if (type->method_map.has(p_name)) {
|
||||
memdelete(bind);
|
||||
// Overloading not supported
|
||||
ERR_FAIL_V_MSG(nullptr, "Method already bound: " + instance_type + "::" + p_name + ".");
|
||||
ERR_FAIL_V_MSG(nullptr, vformat("Method already bound: '%s::%s'.", instance_type, p_name));
|
||||
}
|
||||
type->method_map[p_name] = bind;
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
|
|
@ -1817,26 +1941,31 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, bool p_
|
|||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
ERR_FAIL_COND_V_MSG(!p_compatibility && has_method(instance_type, mdname), nullptr, "Class " + String(instance_type) + " already has a method " + String(mdname) + ".");
|
||||
ERR_FAIL_COND_V_MSG(!p_compatibility && has_method(instance_type, mdname), nullptr, vformat("Class '%s' already has a method '%s'.", String(instance_type), 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 + "'.");
|
||||
ERR_FAIL_V_MSG(nullptr, vformat("Couldn't bind method '%s' for instance '%s'.", mdname, instance_type));
|
||||
}
|
||||
|
||||
if (!p_compatibility && type->method_map.has(mdname)) {
|
||||
memdelete(p_bind);
|
||||
// overloading not supported
|
||||
ERR_FAIL_V_MSG(nullptr, "Method already bound '" + instance_type + "::" + mdname + "'.");
|
||||
ERR_FAIL_V_MSG(nullptr, vformat("Method already bound '%s::%s'.", 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 + "'.");
|
||||
ERR_FAIL_V_MSG(nullptr, vformat("Method definition provides more arguments than the method actually has '%s::%s'.", instance_type, mdname));
|
||||
}
|
||||
|
||||
if (p_defcount > p_bind->get_argument_count()) {
|
||||
memdelete(p_bind);
|
||||
ERR_FAIL_V_MSG(nullptr, vformat("Method definition for '%s::%s' provides more default arguments than the method has arguments.", instance_type, mdname));
|
||||
}
|
||||
|
||||
p_bind->set_argument_names(method_name.args);
|
||||
|
|
@ -1865,7 +1994,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, bool p_
|
|||
}
|
||||
|
||||
void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual, const Vector<String> &p_arg_names, bool p_object_core) {
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'.");
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
|
||||
|
||||
OBJTYPE_WLOCK;
|
||||
|
||||
|
|
@ -1880,7 +2009,7 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
|
|||
|
||||
if (!p_object_core) {
|
||||
if (p_arg_names.size() != mi.arguments.size()) {
|
||||
WARN_PRINT("Mismatch argument name count for virtual method: " + String(p_class) + "::" + p_method.name);
|
||||
WARN_PRINT(vformat("Mismatch argument name count for virtual method: '%s::%s'.", String(p_class), p_method.name));
|
||||
} else {
|
||||
List<PropertyInfo>::Iterator itr = mi.arguments.begin();
|
||||
for (int i = 0; i < p_arg_names.size(); ++itr, ++i) {
|
||||
|
|
@ -1891,7 +2020,7 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
|
|||
|
||||
if (classes[p_class].virtual_methods_map.has(p_method.name)) {
|
||||
// overloading not supported
|
||||
ERR_FAIL_MSG("Virtual method already bound '" + String(p_class) + "::" + p_method.name + "'.");
|
||||
ERR_FAIL_MSG(vformat("Virtual method already bound '%s::%s'.", String(p_class), p_method.name));
|
||||
}
|
||||
classes[p_class].virtual_methods.push_back(mi);
|
||||
classes[p_class].virtual_methods_map[p_method.name] = mi;
|
||||
|
|
@ -1899,8 +2028,24 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
|
|||
#endif
|
||||
}
|
||||
|
||||
void ClassDB::add_virtual_compatibility_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual, const Vector<String> &p_arg_names, bool p_object_core) {
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
|
||||
|
||||
OBJTYPE_WLOCK;
|
||||
|
||||
HashMap<StringName, Vector<uint32_t>> &virtual_methods_compat = classes[p_class].virtual_methods_compat;
|
||||
|
||||
Vector<uint32_t> *compat_hashes = virtual_methods_compat.getptr(p_method.name);
|
||||
if (!compat_hashes) {
|
||||
virtual_methods_compat[p_method.name] = Vector<uint32_t>();
|
||||
compat_hashes = &virtual_methods_compat[p_method.name];
|
||||
}
|
||||
|
||||
compat_hashes->push_back(p_method.get_compatibility_hash());
|
||||
}
|
||||
|
||||
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 + "'.");
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
|
||||
|
|
@ -1920,8 +2065,27 @@ void ClassDB::get_virtual_methods(const StringName &p_class, List<MethodInfo> *p
|
|||
#endif
|
||||
}
|
||||
|
||||
Vector<uint32_t> ClassDB::get_virtual_method_compatibility_hashes(const StringName &p_class, const StringName &p_name) {
|
||||
OBJTYPE_RLOCK;
|
||||
|
||||
ClassInfo *type = classes.getptr(p_class);
|
||||
|
||||
while (type) {
|
||||
if (type->virtual_methods_compat.has(p_name)) {
|
||||
Vector<uint32_t> *compat_hashes = type->virtual_methods_compat.getptr(p_name);
|
||||
if (compat_hashes) {
|
||||
return *compat_hashes;
|
||||
}
|
||||
break;
|
||||
}
|
||||
type = type->inherits_ptr;
|
||||
}
|
||||
|
||||
return Vector<uint32_t>();
|
||||
}
|
||||
|
||||
void ClassDB::add_extension_class_virtual_method(const StringName &p_class, const GDExtensionClassVirtualMethodInfo *p_method_info) {
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'.");
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
PackedStringArray arg_names;
|
||||
|
|
@ -1945,7 +2109,7 @@ void ClassDB::add_extension_class_virtual_method(const StringName &p_class, cons
|
|||
void ClassDB::set_class_enabled(const StringName &p_class, bool p_enable) {
|
||||
OBJTYPE_WLOCK;
|
||||
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_class), "Request for nonexistent class '" + p_class + "'.");
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
|
||||
classes[p_class].disabled = !p_enable;
|
||||
}
|
||||
|
||||
|
|
@ -1959,7 +2123,7 @@ bool ClassDB::is_class_enabled(const StringName &p_class) {
|
|||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_NULL_V_MSG(ti, false, "Cannot get class '" + String(p_class) + "'.");
|
||||
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
return !ti->disabled;
|
||||
}
|
||||
|
||||
|
|
@ -1967,7 +2131,7 @@ bool ClassDB::is_class_exposed(const StringName &p_class) {
|
|||
OBJTYPE_RLOCK;
|
||||
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
ERR_FAIL_NULL_V_MSG(ti, false, "Cannot get class '" + String(p_class) + "'.");
|
||||
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
return ti->exposed;
|
||||
}
|
||||
|
||||
|
|
@ -1975,7 +2139,7 @@ bool ClassDB::is_class_reloadable(const StringName &p_class) {
|
|||
OBJTYPE_RLOCK;
|
||||
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
ERR_FAIL_NULL_V_MSG(ti, false, "Cannot get class '" + String(p_class) + "'.");
|
||||
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
return ti->reloadable;
|
||||
}
|
||||
|
||||
|
|
@ -1983,7 +2147,7 @@ bool ClassDB::is_class_runtime(const StringName &p_class) {
|
|||
OBJTYPE_RLOCK;
|
||||
|
||||
ClassInfo *ti = classes.getptr(p_class);
|
||||
ERR_FAIL_NULL_V_MSG(ti, false, "Cannot get class '" + String(p_class) + "'.");
|
||||
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
|
||||
return ti->is_runtime;
|
||||
}
|
||||
|
||||
|
|
@ -2093,14 +2257,14 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
|
|||
void ClassDB::register_extension_class(ObjectGDExtension *p_extension) {
|
||||
GLOBAL_LOCK_FUNCTION;
|
||||
|
||||
ERR_FAIL_COND_MSG(classes.has(p_extension->class_name), "Class already registered: " + String(p_extension->class_name));
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_extension->parent_class_name), "Parent class name for extension class not found: " + String(p_extension->parent_class_name));
|
||||
ERR_FAIL_COND_MSG(classes.has(p_extension->class_name), vformat("Class already registered: '%s'.", String(p_extension->class_name)));
|
||||
ERR_FAIL_COND_MSG(!classes.has(p_extension->parent_class_name), vformat("Parent class name for extension class not found: '%s'.", String(p_extension->parent_class_name)));
|
||||
|
||||
ClassInfo *parent = classes.getptr(p_extension->parent_class_name);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
// @todo This is a limitation of the current implementation, but it should be possible to remove.
|
||||
ERR_FAIL_COND_MSG(p_extension->is_runtime && parent->gdextension && !parent->is_runtime, "Extension runtime class " + String(p_extension->class_name) + " cannot descend from " + parent->name + " which isn't also a runtime class");
|
||||
ERR_FAIL_COND_MSG(p_extension->is_runtime && parent->gdextension && !parent->is_runtime, vformat("Extension runtime class '%s' cannot descend from '%s' which isn't also a runtime class.", String(p_extension->class_name), parent->name));
|
||||
#endif
|
||||
|
||||
ClassInfo c;
|
||||
|
|
@ -2116,7 +2280,7 @@ void ClassDB::register_extension_class(ObjectGDExtension *p_extension) {
|
|||
concrete_ancestor->gdextension != nullptr) {
|
||||
concrete_ancestor = concrete_ancestor->inherits_ptr;
|
||||
}
|
||||
ERR_FAIL_NULL_MSG(concrete_ancestor->creation_func, "Extension class " + String(p_extension->class_name) + " cannot extend native abstract class " + String(concrete_ancestor->name));
|
||||
ERR_FAIL_NULL_MSG(concrete_ancestor->creation_func, vformat("Extension class '%s' cannot extend native abstract class '%s'.", String(p_extension->class_name), String(concrete_ancestor->name)));
|
||||
c.creation_func = concrete_ancestor->creation_func;
|
||||
}
|
||||
c.inherits = parent->name;
|
||||
|
|
@ -2140,7 +2304,7 @@ void ClassDB::register_extension_class(ObjectGDExtension *p_extension) {
|
|||
|
||||
void ClassDB::unregister_extension_class(const StringName &p_class, bool p_free_method_binds) {
|
||||
ClassInfo *c = classes.getptr(p_class);
|
||||
ERR_FAIL_NULL_MSG(c, "Class '" + String(p_class) + "' does not exist.");
|
||||
ERR_FAIL_NULL_MSG(c, vformat("Class '%s' does not exist.", String(p_class)));
|
||||
if (p_free_method_binds) {
|
||||
for (KeyValue<StringName, MethodBind *> &F : c->method_map) {
|
||||
memdelete(F.value);
|
||||
|
|
@ -2207,4 +2371,11 @@ void ClassDB::cleanup() {
|
|||
native_structs.clear();
|
||||
}
|
||||
|
||||
// Array to use in optional parameters on methods and the DEFVAL_ARRAY macro.
|
||||
Array ClassDB::default_array_arg = Array::create_read_only();
|
||||
|
||||
bool ClassDB::is_default_array_arg(const Array &p_array) {
|
||||
return p_array.is_same_instance(default_array_arg);
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue