feat: modules moved and engine moved to submodule

This commit is contained in:
Jan van der Weide 2025-04-12 18:40:44 +02:00
parent dfb5e645cd
commit c33d2130cc
5136 changed files with 225275 additions and 64485 deletions

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CALLABLE_METHOD_POINTER_H
#define CALLABLE_METHOD_POINTER_H
#pragma once
#include "core/object/object.h"
#include "core/variant/binder_common.h"
@ -82,8 +81,7 @@ class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
uint64_t object_id;
R(T::*method)
(P...);
R (T::*method)(P...);
} data;
public:
@ -152,8 +150,7 @@ class CallableCustomMethodPointerC : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
uint64_t object_id;
R(T::*method)
(P...) const;
R (T::*method)(P...) const;
} data;
public:
@ -226,8 +223,7 @@ Callable create_custom_callable_function_pointer(T *p_instance,
template <typename R, typename... P>
class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
R(*method)
(P...);
R (*method)(P...);
} data;
public:
@ -292,5 +288,3 @@ Callable create_custom_callable_static_function_pointer(
#else
#define callable_mp_static(M) create_custom_callable_static_function_pointer(M)
#endif
#endif // CALLABLE_METHOD_POINTER_H

View file

@ -35,9 +35,6 @@
#include "core/object/script_language.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_METHODP(const char *p_name, const char *const **p_args, uint32_t p_argcount) {
@ -238,13 +235,13 @@ bool ClassDB::_is_parent_class(const StringName &p_class, const StringName &p_in
}
bool ClassDB::is_parent_class(const StringName &p_class, const StringName &p_inherits) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
return _is_parent_class(p_class, p_inherits);
}
void ClassDB::get_class_list(List<StringName> *p_classes) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
for (const KeyValue<StringName, ClassInfo> &E : classes) {
p_classes->push_back(E.key);
@ -255,7 +252,7 @@ void ClassDB::get_class_list(List<StringName> *p_classes) {
#ifdef TOOLS_ENABLED
void ClassDB::get_extensions_class_list(List<StringName> *p_classes) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
for (const KeyValue<StringName, ClassInfo> &E : classes) {
if (E.value.api != API_EXTENSION && E.value.api != API_EDITOR_EXTENSION) {
@ -268,7 +265,7 @@ void ClassDB::get_extensions_class_list(List<StringName> *p_classes) {
}
void ClassDB::get_extension_class_list(const Ref<GDExtension> &p_extension, List<StringName> *p_classes) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
for (const KeyValue<StringName, ClassInfo> &E : classes) {
if (E.value.api != API_EXTENSION && E.value.api != API_EDITOR_EXTENSION) {
@ -284,28 +281,28 @@ void ClassDB::get_extension_class_list(const Ref<GDExtension> &p_extension, List
}
#endif
void ClassDB::get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
OBJTYPE_RLOCK;
void ClassDB::get_inheriters_from_class(const StringName &p_class, LocalVector<StringName> &p_classes) {
Locker::Lock lock(Locker::STATE_READ);
for (const KeyValue<StringName, ClassInfo> &E : classes) {
if (E.key != p_class && _is_parent_class(E.key, p_class)) {
p_classes->push_back(E.key);
p_classes.push_back(E.key);
}
}
}
void ClassDB::get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
for (const KeyValue<StringName, ClassInfo> &E : classes) {
if (E.key != p_class && _get_parent_class(E.key) == p_class) {
if (E.value.inherits == p_class) {
p_classes->push_back(E.key);
}
}
}
StringName ClassDB::get_parent_class_nocheck(const StringName &p_class) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *ti = classes.getptr(p_class);
if (!ti) {
@ -315,7 +312,7 @@ StringName ClassDB::get_parent_class_nocheck(const StringName &p_class) {
}
bool ClassDB::get_inheritance_chain_nocheck(const StringName &p_class, Vector<StringName> &r_result) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *start = classes.getptr(p_class);
if (!start) {
@ -356,13 +353,13 @@ StringName ClassDB::_get_parent_class(const StringName &p_class) {
}
StringName ClassDB::get_parent_class(const StringName &p_class) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
return _get_parent_class(p_class);
}
ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *ti = classes.getptr(p_class);
@ -372,13 +369,13 @@ ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) {
uint32_t ClassDB::get_api_hash(APIType p_api) {
#ifdef DEBUG_METHODS_ENABLED
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
if (api_hashes_cache.has(p_api)) {
return api_hashes_cache[p_api];
}
uint64_t hash = hash_murmur3_one_64(HashMapHasherDefault::hash(VERSION_FULL_CONFIG));
uint64_t hash = hash_murmur3_one_64(HashMapHasherDefault::hash(GODOT_VERSION_FULL_CONFIG));
List<StringName> class_list;
for (const KeyValue<StringName, ClassInfo> &E : classes) {
@ -520,12 +517,12 @@ uint32_t ClassDB::get_api_hash(APIType p_api) {
}
bool ClassDB::class_exists(const StringName &p_class) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
return classes.has(p_class);
}
void ClassDB::add_compatibility_class(const StringName &p_class, const StringName &p_fallback) {
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
compat_classes[p_class] = p_fallback;
}
@ -536,18 +533,21 @@ StringName ClassDB::get_compatibility_class(const StringName &p_class) {
return StringName();
}
Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require_real_class, bool p_notify_postinitialize) {
Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require_real_class, bool p_notify_postinitialize, bool p_exposed_only) {
ClassInfo *ti;
{
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ti = classes.getptr(p_class);
if (!_can_instantiate(ti)) {
if (!_can_instantiate(ti, p_exposed_only)) {
if (compat_classes.has(p_class)) {
ti = classes.getptr(compat_classes[p_class]);
}
}
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)));
if (p_exposed_only) {
ERR_FAIL_COND_V_MSG(!ti->exposed, nullptr, vformat("Class '%s' isn't exposed.", 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)));
}
@ -599,11 +599,15 @@ Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require
}
}
bool ClassDB::_can_instantiate(ClassInfo *p_class_info) {
bool ClassDB::_can_instantiate(ClassInfo *p_class_info, bool p_exposed_only) {
if (!p_class_info) {
return false;
}
if (p_exposed_only && !p_class_info->exposed) {
return false;
}
if (p_class_info->disabled || !p_class_info->creation_func) {
return false;
}
@ -645,7 +649,7 @@ ObjectGDExtension *ClassDB::get_placeholder_extension(const StringName &p_class)
ClassInfo *ti;
{
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ti = classes.getptr(p_class);
if (!_can_instantiate(ti)) {
if (compat_classes.has(p_class)) {
@ -730,7 +734,7 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName &
ERR_FAIL_NULL(p_object);
ClassInfo *ti;
{
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ti = classes.getptr(p_class);
if (!_can_instantiate(ti)) {
if (compat_classes.has(p_class)) {
@ -755,7 +759,7 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName &
bool ClassDB::can_instantiate(const StringName &p_class) {
String script_path;
{
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *ti = classes.getptr(p_class);
if (!ti) {
@ -781,7 +785,7 @@ use_script:
bool ClassDB::is_abstract(const StringName &p_class) {
String script_path;
{
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *ti = classes.getptr(p_class);
if (!ti) {
@ -813,7 +817,7 @@ use_script:
bool ClassDB::is_virtual(const StringName &p_class) {
String script_path;
{
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *ti = classes.getptr(p_class);
if (!ti) {
@ -836,8 +840,8 @@ use_script:
return scr.is_valid() && scr->is_valid() && scr->is_abstract();
}
void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) {
OBJTYPE_WLOCK;
void ClassDB::_add_class(const StringName &p_class, const StringName &p_inherits) {
Locker::Lock lock(Locker::STATE_WRITE);
const StringName &name = p_class;
@ -880,7 +884,7 @@ static MethodInfo info_from_bind(MethodBind *p_method) {
}
void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -926,7 +930,7 @@ void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_met
}
void ClassDB::get_method_list_with_compatibility(const StringName &p_class, List<Pair<MethodInfo, uint32_t>> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -986,7 +990,7 @@ void ClassDB::get_method_list_with_compatibility(const StringName &p_class, List
}
bool ClassDB::get_method_info(const StringName &p_class, const StringName &p_method, MethodInfo *r_info, bool p_no_inheritance, bool p_exclude_from_properties) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1036,7 +1040,7 @@ bool ClassDB::get_method_info(const StringName &p_class, const StringName &p_met
}
MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_name) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1051,7 +1055,7 @@ MethodBind *ClassDB::get_method(const StringName &p_class, const StringName &p_n
}
Vector<uint32_t> ClassDB::get_method_compatibility_hashes(const StringName &p_class, const StringName &p_name) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1070,7 +1074,7 @@ Vector<uint32_t> ClassDB::get_method_compatibility_hashes(const StringName &p_cl
}
MethodBind *ClassDB::get_method_with_compatibility(const StringName &p_class, const StringName &p_name, uint64_t p_hash, bool *r_method_exists, bool *r_is_deprecated) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1105,7 +1109,7 @@ MethodBind *ClassDB::get_method_with_compatibility(const StringName &p_class, co
}
void ClassDB::bind_integer_constant(const StringName &p_class, const StringName &p_enum, const StringName &p_name, int64_t p_constant, bool p_is_bitfield) {
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
ClassInfo *type = classes.getptr(p_class);
@ -1142,7 +1146,7 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName
}
void ClassDB::get_integer_constant_list(const StringName &p_class, List<String> *p_constants, bool p_no_inheritance) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1167,7 +1171,7 @@ void ClassDB::get_integer_constant_list(const StringName &p_class, List<String>
}
int64_t ClassDB::get_integer_constant(const StringName &p_class, const StringName &p_name, bool *p_success) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1191,7 +1195,7 @@ int64_t ClassDB::get_integer_constant(const StringName &p_class, const StringNam
}
bool ClassDB::has_integer_constant(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1210,7 +1214,7 @@ bool ClassDB::has_integer_constant(const StringName &p_class, const StringName &
}
StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1234,7 +1238,7 @@ StringName ClassDB::get_integer_constant_enum(const StringName &p_class, const S
}
void ClassDB::get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1252,7 +1256,7 @@ void ClassDB::get_enum_list(const StringName &p_class, List<StringName> *p_enums
}
void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1275,7 +1279,7 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_
void ClassDB::set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values) {
#ifdef DEBUG_METHODS_ENABLED
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL(type);
@ -1286,7 +1290,7 @@ void ClassDB::set_method_error_return_values(const StringName &p_class, const St
Vector<Error> ClassDB::get_method_error_return_values(const StringName &p_class, const StringName &p_method) {
#ifdef DEBUG_METHODS_ENABLED
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL_V(type, Vector<Error>());
@ -1301,7 +1305,7 @@ Vector<Error> ClassDB::get_method_error_return_values(const StringName &p_class,
}
bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1320,7 +1324,7 @@ bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool
}
bool ClassDB::is_enum_bitfield(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1339,7 +1343,7 @@ bool ClassDB::is_enum_bitfield(const StringName &p_class, const StringName &p_na
}
void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal) {
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL(type);
@ -1358,7 +1362,7 @@ void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal)
}
void ClassDB::get_signal_list(const StringName &p_class, List<MethodInfo> *p_signals, bool p_no_inheritance) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL(type);
@ -1379,7 +1383,7 @@ void ClassDB::get_signal_list(const StringName &p_class, List<MethodInfo> *p_sig
}
bool ClassDB::has_signal(const StringName &p_class, const StringName &p_signal, bool p_no_inheritance) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
while (check) {
@ -1396,7 +1400,7 @@ bool ClassDB::has_signal(const StringName &p_class, const StringName &p_signal,
}
bool ClassDB::get_signal(const StringName &p_class, const StringName &p_signal, MethodInfo *r_signal) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
while (check) {
@ -1413,7 +1417,7 @@ bool ClassDB::get_signal(const StringName &p_class, const StringName &p_signal,
}
void ClassDB::add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) {
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL(type);
@ -1426,7 +1430,7 @@ void ClassDB::add_property_group(const StringName &p_class, const String &p_name
}
void ClassDB::add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) {
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL(type);
@ -1443,7 +1447,7 @@ void ClassDB::add_property_array_count(const StringName &p_class, const String &
}
void ClassDB::add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix) {
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL(type);
@ -1452,9 +1456,9 @@ void ClassDB::add_property_array(const StringName &p_class, const StringName &p_
// NOTE: For implementation simplicity reasons, this method doesn't allow setters to have optional arguments at the end.
void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
lock.read_lock();
Locker::Lock lock(Locker::STATE_WRITE);
ClassInfo *type = classes.getptr(p_class);
lock.read_unlock();
ERR_FAIL_NULL(type);
@ -1486,8 +1490,6 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf
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
type->property_list.push_back(p_pinfo);
type->property_map[p_pinfo.name] = p_pinfo;
#ifdef DEBUG_METHODS_ENABLED
@ -1518,7 +1520,7 @@ void ClassDB::set_property_default_value(const StringName &p_class, const String
void ClassDB::add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property) {
#ifdef TOOLS_ENABLED
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_NULL(type);
@ -1534,7 +1536,7 @@ void ClassDB::add_linked_property(const StringName &p_class, const String &p_pro
}
void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
@ -1577,7 +1579,7 @@ void ClassDB::get_linked_properties_info(const StringName &p_class, const String
}
bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *check = classes.getptr(p_class);
while (check) {
@ -1800,7 +1802,7 @@ bool ClassDB::has_property(const StringName &p_class, const StringName &p_proper
}
void ClassDB::set_method_flags(const StringName &p_class, const StringName &p_method, int p_flags) {
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
ERR_FAIL_NULL(check);
@ -1825,7 +1827,7 @@ bool ClassDB::has_method(const StringName &p_class, const StringName &p_method,
}
int ClassDB::get_method_argument_count(const StringName &p_class, const StringName &p_method, bool *r_is_valid, bool p_no_inheritance) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -1864,7 +1866,7 @@ 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;
Locker::Lock lock(Locker::STATE_WRITE);
StringName method_name = p_method->get_name();
@ -1933,7 +1935,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, bool p_
StringName mdname = StaticCString::create(method_name);
#endif
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
ERR_FAIL_NULL_V(p_bind, nullptr);
p_bind->set_name(mdname);
@ -1996,7 +1998,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), vformat("Request for nonexistent class '%s'.", p_class));
OBJTYPE_WLOCK;
Locker::Lock lock(Locker::STATE_WRITE);
#ifdef DEBUG_METHODS_ENABLED
MethodInfo mi = p_method;
@ -2011,9 +2013,8 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
if (p_arg_names.size() != mi.arguments.size()) {
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) {
itr->name = p_arg_names[i];
for (int64_t i = 0; i < p_arg_names.size(); ++i) {
mi.arguments.write[i].name = p_arg_names[i];
}
}
}
@ -2031,7 +2032,7 @@ void ClassDB::add_virtual_method(const StringName &p_class, const MethodInfo &p_
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;
Locker::Lock lock(Locker::STATE_WRITE);
HashMap<StringName, Vector<uint32_t>> &virtual_methods_compat = classes[p_class].virtual_methods_compat;
@ -2066,7 +2067,7 @@ void ClassDB::get_virtual_methods(const StringName &p_class, List<MethodInfo> *p
}
Vector<uint32_t> ClassDB::get_virtual_method_compatibility_hashes(const StringName &p_class, const StringName &p_name) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *type = classes.getptr(p_class);
@ -2107,14 +2108,14 @@ 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;
Locker::Lock lock(Locker::STATE_WRITE);
ERR_FAIL_COND_MSG(!classes.has(p_class), vformat("Request for nonexistent class '%s'.", p_class));
classes[p_class].disabled = !p_enable;
}
bool ClassDB::is_class_enabled(const StringName &p_class) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *ti = classes.getptr(p_class);
if (!ti || !ti->creation_func) {
@ -2128,7 +2129,7 @@ bool ClassDB::is_class_enabled(const StringName &p_class) {
}
bool ClassDB::is_class_exposed(const StringName &p_class) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *ti = classes.getptr(p_class);
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
@ -2136,7 +2137,7 @@ bool ClassDB::is_class_exposed(const StringName &p_class) {
}
bool ClassDB::is_class_reloadable(const StringName &p_class) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *ti = classes.getptr(p_class);
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
@ -2144,7 +2145,7 @@ bool ClassDB::is_class_reloadable(const StringName &p_class) {
}
bool ClassDB::is_class_runtime(const StringName &p_class) {
OBJTYPE_RLOCK;
Locker::Lock lock(Locker::STATE_READ);
ClassInfo *ti = classes.getptr(p_class);
ERR_FAIL_NULL_V_MSG(ti, false, vformat("Cannot get class '%s'.", String(p_class)));
@ -2342,7 +2343,9 @@ uint64_t ClassDB::get_native_struct_size(const StringName &p_name) {
return native_structs[p_name].struct_size;
}
RWLock ClassDB::lock;
Object *ClassDB::_instantiate_allow_unexposed(const StringName &p_class) {
return _instantiate_internal(p_class, false, true, false);
}
void ClassDB::cleanup_defaults() {
default_values.clear();
@ -2379,3 +2382,32 @@ bool ClassDB::is_default_array_arg(const Array &p_array) {
}
//
ClassDB::Locker::Lock::Lock(Locker::State p_state) {
DEV_ASSERT(p_state != STATE_UNLOCKED);
if (p_state == STATE_READ) {
if (Locker::thread_state == STATE_UNLOCKED) {
state = STATE_READ;
Locker::thread_state = STATE_READ;
Locker::lock.read_lock();
}
} else if (p_state == STATE_WRITE) {
if (Locker::thread_state == STATE_UNLOCKED) {
state = STATE_WRITE;
Locker::thread_state = STATE_WRITE;
Locker::lock.write_lock();
} else if (Locker::thread_state == STATE_READ) {
CRASH_NOW_MSG("Lock can't be upgraded from read to write.");
}
}
}
ClassDB::Locker::Lock::~Lock() {
if (state == STATE_READ) {
Locker::lock.read_unlock();
Locker::thread_state = STATE_UNLOCKED;
} else if (state == STATE_WRITE) {
Locker::lock.write_unlock();
Locker::thread_state = STATE_UNLOCKED;
}
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CLASS_DB_H
#define CLASS_DB_H
#pragma once
#include "core/object/method_bind.h"
#include "core/object/object.h"
@ -79,6 +78,8 @@ MethodDefinition D_METHOD(const char *p_name, const VarArgs... p_args) {
#endif
class ClassDB {
friend class Object;
public:
enum APIType {
API_CORE,
@ -153,7 +154,30 @@ public:
return ret;
}
static RWLock lock;
// We need a recursive r/w lock because there are various code paths
// that may in turn invoke other entry points with require locking.
class Locker {
public:
enum State {
STATE_UNLOCKED,
STATE_READ,
STATE_WRITE,
};
private:
inline static RWLock lock;
inline thread_local static State thread_state = STATE_UNLOCKED;
public:
class Lock {
State state = STATE_UNLOCKED;
public:
explicit Lock(State p_state);
~Lock();
};
};
static HashMap<StringName, ClassInfo> classes;
static HashMap<StringName, StringName> resource_base_extensions;
static HashMap<StringName, StringName> compat_classes;
@ -171,7 +195,7 @@ public:
static APIType current_api;
static HashMap<APIType, uint32_t> api_hashes_cache;
static void _add_class2(const StringName &p_class, const StringName &p_inherits);
static void _add_class(const StringName &p_class, const StringName &p_inherits);
static HashMap<StringName, HashMap<StringName, Variant>> default_values;
static HashSet<StringName> default_values_cached;
@ -194,20 +218,14 @@ private:
static MethodBind *_bind_vararg_method(MethodBind *p_bind, const StringName &p_name, const Vector<Variant> &p_default_args, bool p_compatibility);
static void _bind_method_custom(const StringName &p_class, MethodBind *p_method, bool p_compatibility);
static Object *_instantiate_internal(const StringName &p_class, bool p_require_real_class = false, bool p_notify_postinitialize = true);
static Object *_instantiate_internal(const StringName &p_class, bool p_require_real_class = false, bool p_notify_postinitialize = true, bool p_exposed_only = true);
static bool _can_instantiate(ClassInfo *p_class_info);
static bool _can_instantiate(ClassInfo *p_class_info, bool p_exposed_only = true);
public:
// DO NOT USE THIS!!!!!! NEEDS TO BE PUBLIC BUT DO NOT USE NO MATTER WHAT!!!
template <typename T>
static void _add_class() {
_add_class2(T::get_class_static(), T::get_parent_class_static());
}
template <typename T>
static void register_class(bool p_virtual = false) {
GLOBAL_LOCK_FUNCTION;
Locker::Lock lock(Locker::STATE_WRITE);
static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
@ -222,7 +240,7 @@ public:
template <typename T>
static void register_abstract_class() {
GLOBAL_LOCK_FUNCTION;
Locker::Lock lock(Locker::STATE_WRITE);
static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
@ -235,7 +253,7 @@ public:
template <typename T>
static void register_internal_class() {
GLOBAL_LOCK_FUNCTION;
Locker::Lock lock(Locker::STATE_WRITE);
static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
@ -250,7 +268,7 @@ public:
template <typename T>
static void register_runtime_class() {
GLOBAL_LOCK_FUNCTION;
Locker::Lock lock(Locker::STATE_WRITE);
static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
@ -275,7 +293,7 @@ public:
template <typename T>
static void register_custom_instance_class() {
GLOBAL_LOCK_FUNCTION;
Locker::Lock lock(Locker::STATE_WRITE);
static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
@ -293,7 +311,7 @@ public:
static void get_extension_class_list(const Ref<GDExtension> &p_extension, List<StringName> *p_classes);
static ObjectGDExtension *get_placeholder_extension(const StringName &p_class);
#endif
static void get_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
static void get_inheriters_from_class(const StringName &p_class, LocalVector<StringName> &p_classes);
static void get_direct_inheriters_from_class(const StringName &p_class, List<StringName> *p_classes);
static StringName get_parent_class_nocheck(const StringName &p_class);
static bool get_inheritance_chain_nocheck(const StringName &p_class, Vector<StringName> &r_result);
@ -391,7 +409,7 @@ public:
template <typename M>
static MethodBind *bind_vararg_method(uint32_t p_flags, const StringName &p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const Vector<Variant> &p_default_args = Vector<Variant>(), bool p_return_nil_is_variant = true) {
GLOBAL_LOCK_FUNCTION;
Locker::Lock lock(Locker::STATE_WRITE);
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
ERR_FAIL_NULL_V(bind, nullptr);
@ -404,7 +422,7 @@ public:
template <typename M>
static MethodBind *bind_compatibility_vararg_method(uint32_t p_flags, const StringName &p_name, M p_method, const MethodInfo &p_info = MethodInfo(), const Vector<Variant> &p_default_args = Vector<Variant>(), bool p_return_nil_is_variant = true) {
GLOBAL_LOCK_FUNCTION;
Locker::Lock lock(Locker::STATE_WRITE);
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
ERR_FAIL_NULL_V(bind, nullptr);
@ -498,6 +516,8 @@ public:
static void get_native_struct_list(List<StringName> *r_names);
static String get_native_struct_code(const StringName &p_name);
static uint64_t get_native_struct_size(const StringName &p_name); // Used for asserting
static Object *_instantiate_allow_unexposed(const StringName &p_class); // Used to create unexposed classes from GDExtension, typically for unexposed EditorPlugin.
};
#define BIND_ENUM_CONSTANT(m_constant) \
@ -563,7 +583,3 @@ _FORCE_INLINE_ Vector<Error> errarray(P... p_args) {
}
#define GDREGISTER_NATIVE_STRUCT(m_class, m_code) ClassDB::register_native_struct(#m_class, m_code, sizeof(m_class))
#include "core/disabled_classes.gen.h"
#endif // CLASS_DB_H

View file

@ -15,57 +15,65 @@ script_has_method = """ScriptInstance *_script_instance = ((Object *)(this))->ge
}"""
proto = """#define GDVIRTUAL$VER($ALIAS $RET m_name $ARG)\\
StringName _gdvirtual_##$VARNAME##_sn = #m_name;\\
mutable bool _gdvirtual_##$VARNAME##_initialized = false;\\
mutable void *_gdvirtual_##$VARNAME = nullptr;\\
_FORCE_INLINE_ bool _gdvirtual_##$VARNAME##_call($CALLARGS) $CONST {\\
static const StringName _gdvirtual_##$VARNAME##_sn = _scs_create(#m_name, true);\\
$SCRIPTCALL\\
if (unlikely(_get_extension() && !_gdvirtual_##$VARNAME##_initialized)) {\\
MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\
uint32_t hash = mi.get_compatibility_hash();\\
_gdvirtual_##$VARNAME = nullptr;\\
if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\
_gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
} else if (_get_extension()->get_virtual2) {\\
_gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
if (_get_extension()) {\\
if (unlikely(!_gdvirtual_##$VARNAME)) {\\
MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\
uint32_t hash = mi.get_compatibility_hash();\\
_gdvirtual_##$VARNAME = nullptr;\\
if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\
_gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
} else if (_get_extension()->get_virtual2) {\\
_gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
}\\
_GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\
_GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME);\\
if (_gdvirtual_##$VARNAME == nullptr) {\\
_gdvirtual_##$VARNAME = reinterpret_cast<void*>(_INVALID_GDVIRTUAL_FUNC_ADDR);\\
}\\
}\\
_GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\
_GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_initialized);\\
_gdvirtual_##$VARNAME##_initialized = true;\\
}\\
if (_gdvirtual_##$VARNAME) {\\
$CALLPTRARGS\\
$CALLPTRRETDEF\\
if (_get_extension()->call_virtual_with_data) {\\
_get_extension()->call_virtual_with_data(_get_extension_instance(), &_gdvirtual_##$VARNAME##_sn, _gdvirtual_##$VARNAME, $CALLPTRARGPASS, $CALLPTRRETPASS);\\
$CALLPTRRET\\
} else {\\
((GDExtensionClassCallVirtual)_gdvirtual_##$VARNAME)(_get_extension_instance(), $CALLPTRARGPASS, $CALLPTRRETPASS);\\
$CALLPTRRET\\
if (_gdvirtual_##$VARNAME != reinterpret_cast<void*>(_INVALID_GDVIRTUAL_FUNC_ADDR)) {\\
$CALLPTRARGS\\
$CALLPTRRETDEF\\
if (_get_extension()->call_virtual_with_data) {\\
_get_extension()->call_virtual_with_data(_get_extension_instance(), &_gdvirtual_##$VARNAME##_sn, _gdvirtual_##$VARNAME, $CALLPTRARGPASS, $CALLPTRRETPASS);\\
$CALLPTRRET\\
} else {\\
((GDExtensionClassCallVirtual)_gdvirtual_##$VARNAME)(_get_extension_instance(), $CALLPTRARGPASS, $CALLPTRRETPASS);\\
$CALLPTRRET\\
}\\
return true;\\
}\\
return true;\\
}\\
$REQCHECK\\
$RVOID\\
return false;\\
}\\
_FORCE_INLINE_ bool _gdvirtual_##$VARNAME##_overridden() const {\\
static const StringName _gdvirtual_##$VARNAME##_sn = _scs_create(#m_name, true);\\
$SCRIPTHASMETHOD\\
if (unlikely(_get_extension() && !_gdvirtual_##$VARNAME##_initialized)) {\\
MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\
uint32_t hash = mi.get_compatibility_hash();\\
_gdvirtual_##$VARNAME = nullptr;\\
if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\
_gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
} else if (_get_extension()->get_virtual2) {\\
_gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
if (_get_extension()) {\\
if (unlikely(!_gdvirtual_##$VARNAME)) {\\
MethodInfo mi = _gdvirtual_##$VARNAME##_get_method_info();\\
uint32_t hash = mi.get_compatibility_hash();\\
_gdvirtual_##$VARNAME = nullptr;\\
if (_get_extension()->get_virtual_call_data2 && _get_extension()->call_virtual_with_data) {\\
_gdvirtual_##$VARNAME = _get_extension()->get_virtual_call_data2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
} else if (_get_extension()->get_virtual2) {\\
_gdvirtual_##$VARNAME = (void *)_get_extension()->get_virtual2(_get_extension()->class_userdata, &_gdvirtual_##$VARNAME##_sn, hash);\\
}\\
_GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\
_GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME);\\
if (_gdvirtual_##$VARNAME == nullptr) {\\
_gdvirtual_##$VARNAME = reinterpret_cast<void*>(_INVALID_GDVIRTUAL_FUNC_ADDR);\\
}\\
}\\
if (_gdvirtual_##$VARNAME != reinterpret_cast<void*>(_INVALID_GDVIRTUAL_FUNC_ADDR)) {\\
return true;\\
}\\
_GDVIRTUAL_GET_DEPRECATED(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_sn, $COMPAT)\\
_GDVIRTUAL_TRACK(_gdvirtual_##$VARNAME, _gdvirtual_##$VARNAME##_initialized);\\
_gdvirtual_##$VARNAME##_initialized = true;\\
}\\
if (_gdvirtual_##$VARNAME) {\\
return true;\\
}\\
return false;\\
}\\
@ -207,24 +215,22 @@ def run(target, source, env):
max_versions = 12
txt = """/* THIS FILE IS GENERATED DO NOT EDIT */
#ifndef GDVIRTUAL_GEN_H
#define GDVIRTUAL_GEN_H
#pragma once
#include "core/object/script_instance.h"
#include <utility>
inline constexpr uintptr_t _INVALID_GDVIRTUAL_FUNC_ADDR = static_cast<uintptr_t>(-1);
#ifdef TOOLS_ENABLED
#define _GDVIRTUAL_TRACK(m_virtual, m_initialized)\\
#define _GDVIRTUAL_TRACK(m_virtual)\\
if (_get_extension()->reloadable) {\\
VirtualMethodTracker *tracker = memnew(VirtualMethodTracker);\\
tracker->method = (void **)&m_virtual;\\
tracker->initialized = &m_initialized;\\
tracker->next = virtual_method_list;\\
virtual_method_list = tracker;\\
}
#else
#define _GDVIRTUAL_TRACK(m_virtual, m_initialized)
#define _GDVIRTUAL_TRACK(m_virtual)
#endif
#ifndef DISABLE_DEPRECATED
@ -257,7 +263,5 @@ def run(target, source, env):
txt += generate_version(i, True, False, False, True)
txt += generate_version(i, True, True, False, True)
txt += "#endif // GDVIRTUAL_GEN_H\n"
with open(str(target[0]), "w", encoding="utf-8", newline="\n") as f:
f.write(txt)

View file

@ -226,7 +226,7 @@ void CallQueue::_call_function(const Callable &p_callable, const Variant *p_args
Error CallQueue::flush() {
LOCK_MUTEX;
if (pages.size() == 0) {
if (pages.is_empty()) {
// Never allocated
UNLOCK_MUTEX;
return OK; // Do nothing.
@ -308,7 +308,7 @@ Error CallQueue::flush() {
void CallQueue::clear() {
LOCK_MUTEX;
if (pages.size() == 0) {
if (pages.is_empty()) {
UNLOCK_MUTEX;
return; // Nothing to clear.
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef MESSAGE_QUEUE_H
#define MESSAGE_QUEUE_H
#pragma once
#include "core/object/object_id.h"
#include "core/os/thread_safe.h"
@ -171,5 +170,3 @@ public:
MessageQueue();
~MessageQueue();
};
#endif // MESSAGE_QUEUE_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef METHOD_BIND_H
#define METHOD_BIND_H
#pragma once
#include "core/variant/binder_common.h"
@ -143,8 +142,7 @@ public:
template <typename Derived, typename T, typename R, bool should_returns>
class MethodBindVarArgBase : public MethodBind {
protected:
R(T::*method)
(const Variant **, int, Callable::CallError &);
R (T::*method)(const Variant **, int, Callable::CallError &);
MethodInfo method_info;
public:
@ -152,7 +150,7 @@ public:
if (p_arg < 0) {
return _gen_return_type_info();
} else if (p_arg < method_info.arguments.size()) {
return method_info.arguments.get(p_arg);
return method_info.arguments[p_arg];
} else {
return PropertyInfo(Variant::NIL, "arg_" + itos(p_arg), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
}
@ -193,11 +191,10 @@ public:
Vector<StringName> names;
names.resize(method_info.arguments.size());
#endif
int i = 0;
for (List<PropertyInfo>::ConstIterator itr = method_info.arguments.begin(); itr != method_info.arguments.end(); ++itr, ++i) {
at[i + 1] = itr->type;
for (int64_t i = 0; i < method_info.arguments.size(); ++i) {
at[i + 1] = method_info.arguments[i].type;
#ifdef DEBUG_METHODS_ENABLED
names.write[i] = itr->name;
names.write[i] = method_info.arguments[i].name;
#endif
}
@ -259,11 +256,8 @@ class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>,
friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
public:
#if defined(SANITIZERS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
// Workaround GH-66343 raised only with UBSAN, seems to be a false positive.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wmaybe-uninitialized") // Workaround GH-66343 raised only with UBSAN, seems to be a false positive.
virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override {
#ifdef TOOLS_ENABLED
ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == MethodBind::get_instance_class(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name()));
@ -271,9 +265,7 @@ public:
return (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)(p_args, p_arg_count, r_error);
}
#if defined(SANITIZERS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
GODOT_GCC_WARNING_POP
MethodBindVarArgTR(
R (T::*p_method)(const Variant **, int, Callable::CallError &),
@ -480,8 +472,7 @@ template <typename T, typename R, typename... P>
template <typename R, typename... P>
#endif
class MethodBindTR : public MethodBind {
R(MB_T::*method)
(P...);
R (MB_T::*method)(P...);
protected:
virtual Variant::Type _gen_argument_type(int p_arg) const override {
@ -576,8 +567,7 @@ template <typename T, typename R, typename... P>
template <typename R, typename... P>
#endif
class MethodBindTRC : public MethodBind {
R(MB_T::*method)
(P...) const;
R (MB_T::*method)(P...) const;
protected:
virtual Variant::Type _gen_argument_type(int p_arg) const override {
@ -728,8 +718,7 @@ MethodBind *create_static_method_bind(void (*p_method)(P...)) {
template <typename R, typename... P>
class MethodBindTRS : public MethodBind {
R(*function)
(P...);
R (*function)(P...);
protected:
virtual Variant::Type _gen_argument_type(int p_arg) const override {
@ -790,5 +779,3 @@ MethodBind *create_static_method_bind(R (*p_method)(P...)) {
MethodBind *a = memnew((MethodBindTRS<R, P...>)(p_method));
return a;
}
#endif // METHOD_BIND_H

View file

@ -115,10 +115,19 @@ TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list) {
return va;
}
TypedArray<Dictionary> convert_property_list(const Vector<PropertyInfo> &p_vector) {
TypedArray<Dictionary> va;
for (const PropertyInfo &E : p_vector) {
va.push_back(Dictionary(E));
}
return va;
}
MethodInfo::operator Dictionary() const {
Dictionary d;
d["name"] = name;
d["args"] = convert_property_list(&arguments);
d["args"] = convert_property_list(arguments);
Array da;
for (int i = 0; i < default_arguments.size(); i++) {
da.push_back(default_arguments[i]);
@ -240,21 +249,15 @@ void Object::cancel_free() {
}
void Object::_initialize() {
_class_name_ptr = _get_class_namev(); // Set the direct pointer, which is much faster to obtain, but can only happen after _initialize.
// Cache the class name in the object for quick reference.
_class_name_ptr = _get_class_namev();
_initialize_classv();
_class_name_ptr = nullptr; // May have been called from a constructor.
}
void Object::_postinitialize() {
notification(NOTIFICATION_POSTINITIALIZE);
}
void Object::get_valid_parents_static(List<String> *p_parents) {
}
void Object::_get_valid_parents_static(List<String> *p_parents) {
}
void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid) {
#ifdef TOOLS_ENABLED
@ -902,18 +905,14 @@ Variant Object::call_const(const StringName &p_method, const Variant **p_args, i
return ret;
}
void Object::notification(int p_notification, bool p_reversed) {
if (p_reversed) {
if (script_instance) {
script_instance->notification(p_notification, p_reversed);
}
} else {
_notificationv(p_notification, p_reversed);
}
void Object::_notification_forward(int p_notification) {
// Notify classes starting with Object and ending with most derived subclass.
// e.g. Object -> Node -> Node3D
_notification_forwardv(p_notification);
if (_extension) {
if (_extension->notification2) {
_extension->notification2(_extension_instance, p_notification, static_cast<GDExtensionBool>(p_reversed));
_extension->notification2(_extension_instance, p_notification, static_cast<GDExtensionBool>(false));
#ifndef DISABLE_DEPRECATED
} else if (_extension->notification) {
_extension->notification(_extension_instance, p_notification);
@ -921,13 +920,29 @@ void Object::notification(int p_notification, bool p_reversed) {
}
}
if (p_reversed) {
_notificationv(p_notification, p_reversed);
} else {
if (script_instance) {
script_instance->notification(p_notification, p_reversed);
if (script_instance) {
script_instance->notification(p_notification, false);
}
}
void Object::_notification_backward(int p_notification) {
if (script_instance) {
script_instance->notification(p_notification, true);
}
if (_extension) {
if (_extension->notification2) {
_extension->notification2(_extension_instance, p_notification, static_cast<GDExtensionBool>(true));
#ifndef DISABLE_DEPRECATED
} else if (_extension->notification) {
_extension->notification(_extension_instance, p_notification);
#endif // DISABLE_DEPRECATED
}
}
// Notify classes starting with most derived subclass and ending in Object.
// e.g. Node3D -> Node -> Object
_notification_backwardv(p_notification);
}
String Object::to_string() {
@ -1080,8 +1095,8 @@ TypedArray<Dictionary> Object::_get_method_list_bind() const {
get_method_list(&ml);
TypedArray<Dictionary> ret;
for (List<MethodInfo>::Element *E = ml.front(); E; E = E->next()) {
Dictionary d = E->get();
for (const MethodInfo &mi : ml) {
Dictionary d = mi;
//va.push_back(d);
ret.push_back(d);
}
@ -1575,7 +1590,7 @@ void Object::initialize_class() {
if (initialized) {
return;
}
ClassDB::_add_class<Object>();
_add_class_to_classdb(get_class_static(), StringName());
_bind_methods();
_bind_compatibility_methods();
initialized = true;
@ -1640,12 +1655,10 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) {
} break;
case Variant::DICTIONARY: {
Dictionary d = p_var;
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &E : keys) {
_clear_internal_resource_paths(E);
_clear_internal_resource_paths(d[E]);
for (const KeyValue<Variant, Variant> &kv : d) {
_clear_internal_resource_paths(kv.key);
_clear_internal_resource_paths(kv.value);
}
} break;
default: {
@ -1653,9 +1666,20 @@ void Object::_clear_internal_resource_paths(const Variant &p_var) {
}
}
void Object::_add_class_to_classdb(const StringName &p_class, const StringName &p_inherits) {
ClassDB::_add_class(p_class, p_inherits);
}
void Object::_get_property_list_from_classdb(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator) {
ClassDB::get_property_list(p_class, p_list, p_no_inheritance, p_validator);
}
#ifdef TOOLS_ENABLED
void Object::editor_set_section_unfold(const String &p_section, bool p_unfolded) {
set_edited(true);
void Object::editor_set_section_unfold(const String &p_section, bool p_unfolded, bool p_initializing) {
if (!p_initializing) {
set_edited(true);
}
if (p_unfolded) {
editor_section_folding.insert(p_section);
} else {
@ -1878,7 +1902,7 @@ Variant::Type Object::get_static_property_type(const StringName &p_property, boo
}
Variant::Type Object::get_static_property_type_indexed(const Vector<StringName> &p_path, bool *r_valid) const {
if (p_path.size() == 0) {
if (p_path.is_empty()) {
if (r_valid) {
*r_valid = false;
}
@ -1945,6 +1969,20 @@ uint32_t Object::get_edited_version() const {
}
#endif
const StringName &Object::get_class_name() const {
if (_extension) {
// Can't put inside the unlikely as constructor can run it.
return _extension->class_name;
}
if (unlikely(!_class_name_ptr)) {
// While class is initializing / deinitializing, constructors and destructors
// need access to the proper class at the proper stage.
return *_get_class_namev();
}
return *_class_name_ptr;
}
StringName Object::get_class_name_for_extension(const GDExtension *p_library) const {
#ifdef TOOLS_ENABLED
// If this is the library this extension comes from and it's a placeholder, we
@ -2092,7 +2130,6 @@ void Object::clear_internal_extension() {
// Clear the virtual methods.
while (virtual_method_list) {
(*virtual_method_list->method) = nullptr;
(*virtual_method_list->initialized) = false;
virtual_method_list = virtual_method_list->next;
}
}

View file

@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef OBJECT_H
#define OBJECT_H
#pragma once
#include "core/disabled_classes.gen.h"
#include "core/extension/gdextension_interface.h"
#include "core/object/message_queue.h"
#include "core/object/object_id.h"
@ -47,6 +47,9 @@
template <typename T>
class TypedArray;
template <typename T>
class Ref;
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,hide_slider][,radians_as_degrees][,degrees][,exp][,suffix:<keyword>] range.
@ -129,6 +132,9 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_NO_EDITOR = PROPERTY_USAGE_STORAGE,
};
// Respective values are defined by disabled_classes.gen.h
#define GD_IS_CLASS_ENABLED(m_class) m_class::_class_is_enabled
#define ADD_SIGNAL(m_signal) ::ClassDB::add_signal(get_class_static(), m_signal)
#define ADD_PROPERTY(m_property, m_setter, m_getter) ::ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter))
#define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ::ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter), m_index)
@ -209,6 +215,7 @@ struct PropertyInfo {
};
TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list);
TypedArray<Dictionary> convert_property_list(const Vector<PropertyInfo> &p_vector);
enum MethodFlags {
METHOD_FLAG_NORMAL = 1,
@ -227,7 +234,7 @@ struct MethodInfo {
PropertyInfo return_val;
uint32_t flags = METHOD_FLAGS_DEFAULT;
int id = 0;
List<PropertyInfo> arguments;
Vector<PropertyInfo> arguments;
Vector<Variant> default_arguments;
int return_val_metadata = 0;
Vector<int> arguments_metadata;
@ -256,8 +263,8 @@ struct MethodInfo {
return_val(PropertyInfo(pinfo.return_value)),
flags(pinfo.flags),
id(pinfo.id) {
for (uint32_t j = 0; j < pinfo.argument_count; j++) {
arguments.push_back(PropertyInfo(pinfo.arguments[j]));
for (uint32_t i = 0; i < pinfo.argument_count; i++) {
arguments.push_back(PropertyInfo(pinfo.arguments[i]));
}
const Variant *def_values = (const Variant *)pinfo.default_arguments;
for (uint32_t j = 0; j < pinfo.default_argument_count; j++) {
@ -265,22 +272,12 @@ struct MethodInfo {
}
}
void _push_params(const PropertyInfo &p_param) {
arguments.push_back(p_param);
}
template <typename... VarArgs>
void _push_params(const PropertyInfo &p_param, VarArgs... p_params) {
arguments.push_back(p_param);
_push_params(p_params...);
}
MethodInfo(const String &p_name) { name = p_name; }
template <typename... VarArgs>
MethodInfo(const String &p_name, VarArgs... p_params) {
name = p_name;
_push_params(p_params...);
arguments = Vector<PropertyInfo>{ p_params... };
}
MethodInfo(Variant::Type ret) { return_val.type = ret; }
@ -293,7 +290,7 @@ struct MethodInfo {
MethodInfo(Variant::Type ret, const String &p_name, VarArgs... p_params) {
name = p_name;
return_val.type = ret;
_push_params(p_params...);
arguments = Vector<PropertyInfo>{ p_params... };
}
MethodInfo(const PropertyInfo &p_ret, const String &p_name) {
@ -305,7 +302,7 @@ struct MethodInfo {
MethodInfo(const PropertyInfo &p_ret, const String &p_name, VarArgs... p_params) {
return_val = p_ret;
name = p_name;
_push_params(p_params...);
arguments = Vector<PropertyInfo>{ p_params... };
}
};
@ -396,57 +393,46 @@ struct ObjectGDExtension {
* much alone defines the object model.
*/
// This is a barebones version of GDCLASS,
// only intended for simple classes deriving from Object
// so that they can support the `Object::cast_to()` method.
#define GDSOFTCLASS(m_class, m_inherits) \
public: \
using self_type = m_class; \
using super_type = m_inherits; \
static _FORCE_INLINE_ void *get_class_ptr_static() { \
static int ptr; \
return &ptr; \
} \
virtual bool is_class_ptr(void *p_ptr) const override { \
return (p_ptr == get_class_ptr_static()) || m_inherits::is_class_ptr(p_ptr); \
} \
\
private:
#define GDCLASS(m_class, m_inherits) \
GDSOFTCLASS(m_class, m_inherits) \
private: \
void operator=(const m_class &p_rval) {} \
friend class ::ClassDB; \
\
public: \
typedef m_class self_type; \
static constexpr bool _class_is_enabled = !bool(GD_IS_DEFINED(ClassDB_Disable_##m_class)) && m_inherits::_class_is_enabled; \
virtual String get_class() const override { \
if (_get_extension()) { \
return _get_extension()->class_name.operator String(); \
} \
return String(#m_class); \
} \
virtual const StringName *_get_class_namev() const override { \
return &get_class_static(); \
} \
static const StringName &get_class_static() { \
static StringName _class_name_static; \
if (unlikely(!_class_name_static)) { \
StringName::assign_static_unique_class_name(&_class_name_static, #m_class); \
} \
return &_class_name_static; \
} \
static _FORCE_INLINE_ void *get_class_ptr_static() { \
static int ptr; \
return &ptr; \
} \
static _FORCE_INLINE_ String get_class_static() { \
return String(#m_class); \
} \
static _FORCE_INLINE_ String get_parent_class_static() { \
return m_inherits::get_class_static(); \
} \
static void get_inheritance_list_static(List<String> *p_inheritance_list) { \
m_inherits::get_inheritance_list_static(p_inheritance_list); \
p_inheritance_list->push_back(String(#m_class)); \
return _class_name_static; \
} \
virtual bool is_class(const String &p_class) const override { \
if (_get_extension() && _get_extension()->is_class(p_class)) { \
return true; \
} \
return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); \
} \
virtual bool is_class_ptr(void *p_ptr) const override { \
return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); \
} \
\
static void get_valid_parents_static(List<String> *p_parents) { \
if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \
m_class::_get_valid_parents_static(p_parents); \
} \
\
m_inherits::get_valid_parents_static(p_parents); \
} \
\
protected: \
@ -464,7 +450,7 @@ public:
return; \
} \
m_inherits::initialize_class(); \
::ClassDB::_add_class<m_class>(); \
_add_class_to_classdb(get_class_static(), super_type::get_class_static()); \
if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \
_bind_methods(); \
} \
@ -479,7 +465,7 @@ protected:
initialize_class(); \
} \
_FORCE_INLINE_ bool (Object::*_get_get() const)(const StringName &p_name, Variant &) const { \
return (bool(Object::*)(const StringName &, Variant &) const) & m_class::_get; \
return (bool (Object::*)(const StringName &, Variant &) const) & m_class::_get; \
} \
virtual bool _getv(const StringName &p_name, Variant &r_ret) const override { \
if (m_class::_get_get() != m_inherits::_get_get()) { \
@ -490,7 +476,7 @@ protected:
return m_inherits::_getv(p_name, r_ret); \
} \
_FORCE_INLINE_ bool (Object::*_get_set() const)(const StringName &p_name, const Variant &p_property) { \
return (bool(Object::*)(const StringName &, const Variant &)) & m_class::_set; \
return (bool (Object::*)(const StringName &, const Variant &)) & m_class::_set; \
} \
virtual bool _setv(const StringName &p_name, const Variant &p_property) override { \
if (m_inherits::_setv(p_name, p_property)) { \
@ -502,14 +488,14 @@ protected:
return false; \
} \
_FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> * p_list) const { \
return (void(Object::*)(List<PropertyInfo> *) const) & m_class::_get_property_list; \
return (void (Object::*)(List<PropertyInfo> *) const) & m_class::_get_property_list; \
} \
virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const override { \
if (!p_reversed) { \
m_inherits::_get_property_listv(p_list, p_reversed); \
} \
p_list->push_back(PropertyInfo(Variant::NIL, get_class_static(), PROPERTY_HINT_NONE, get_class_static(), PROPERTY_USAGE_CATEGORY)); \
::ClassDB::get_property_list(#m_class, p_list, true, this); \
_get_property_list_from_classdb(#m_class, p_list, true, this); \
if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \
_get_property_list(p_list); \
} \
@ -518,7 +504,7 @@ protected:
} \
} \
_FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo & p_property) const { \
return (void(Object::*)(PropertyInfo &) const) & m_class::_validate_property; \
return (void (Object::*)(PropertyInfo &) const) & m_class::_validate_property; \
} \
virtual void _validate_propertyv(PropertyInfo &p_property) const override { \
m_inherits::_validate_propertyv(p_property); \
@ -527,7 +513,7 @@ protected:
} \
} \
_FORCE_INLINE_ bool (Object::*_get_property_can_revert() const)(const StringName &p_name) const { \
return (bool(Object::*)(const StringName &) const) & m_class::_property_can_revert; \
return (bool (Object::*)(const StringName &) const) & m_class::_property_can_revert; \
} \
virtual bool _property_can_revertv(const StringName &p_name) const override { \
if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \
@ -538,7 +524,7 @@ protected:
return m_inherits::_property_can_revertv(p_name); \
} \
_FORCE_INLINE_ bool (Object::*_get_property_get_revert() const)(const StringName &p_name, Variant &) const { \
return (bool(Object::*)(const StringName &, Variant &) const) & m_class::_property_get_revert; \
return (bool (Object::*)(const StringName &, Variant &) const) & m_class::_property_get_revert; \
} \
virtual bool _property_get_revertv(const StringName &p_name, Variant &r_ret) const override { \
if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \
@ -549,18 +535,19 @@ protected:
return m_inherits::_property_get_revertv(p_name, r_ret); \
} \
_FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \
return (void(Object::*)(int)) & m_class::_notification; \
return (void (Object::*)(int)) & m_class::_notification; \
} \
virtual void _notificationv(int p_notification, bool p_reversed) override { \
if (!p_reversed) { \
m_inherits::_notificationv(p_notification, p_reversed); \
} \
virtual void _notification_forwardv(int p_notification) override { \
m_inherits::_notification_forwardv(p_notification); \
if (m_class::_get_notification() != m_inherits::_get_notification()) { \
_notification(p_notification); \
} \
if (p_reversed) { \
m_inherits::_notificationv(p_notification, p_reversed); \
} \
virtual void _notification_backwardv(int p_notification) override { \
if (m_class::_get_notification() != m_inherits::_get_notification()) { \
_notification(p_notification); \
} \
m_inherits::_notification_backwardv(p_notification); \
} \
\
private:
@ -704,7 +691,11 @@ protected:
virtual void _validate_propertyv(PropertyInfo &p_property) const {}
virtual bool _property_can_revertv(const StringName &p_name) const { return false; }
virtual bool _property_get_revertv(const StringName &p_name, Variant &r_property) const { return false; }
virtual void _notificationv(int p_notification, bool p_reversed) {}
void _notification_forward(int p_notification);
void _notification_backward(int p_notification);
virtual void _notification_forwardv(int p_notification) {}
virtual void _notification_backwardv(int p_notification) {}
static void _bind_methods();
static void _bind_compatibility_methods() {}
@ -743,18 +734,12 @@ protected:
_FORCE_INLINE_ void (Object::*_get_notification() const)(int) {
return &Object::_notification;
}
static void get_valid_parents_static(List<String> *p_parents);
static void _get_valid_parents_static(List<String> *p_parents);
Variant _call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
virtual const StringName *_get_class_namev() const {
static StringName _class_name_static;
if (unlikely(!_class_name_static)) {
StringName::assign_static_unique_class_name(&_class_name_static, "Object");
}
return &_class_name_static;
return &get_class_static();
}
TypedArray<StringName> _get_meta_list_bind() const;
@ -766,12 +751,14 @@ protected:
friend class ClassDB;
friend class PlaceholderExtensionInstance;
static void _add_class_to_classdb(const StringName &p_class, const StringName &p_inherits);
static void _get_property_list_from_classdb(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance, const Object *p_validator);
bool _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false);
#ifdef TOOLS_ENABLED
struct VirtualMethodTracker {
void **method;
bool *initialized;
VirtualMethodTracker *next;
};
@ -797,12 +784,18 @@ public:
template <typename T>
static T *cast_to(Object *p_object) {
return p_object ? dynamic_cast<T *>(p_object) : nullptr;
// This is like dynamic_cast, but faster.
// The reason is that we can assume no virtual and multiple inheritance.
static_assert(std::is_base_of_v<Object, T>, "T must be derived from Object");
static_assert(std::is_same_v<std::decay_t<T>, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS");
return p_object && p_object->is_class_ptr(T::get_class_ptr_static()) ? static_cast<T *>(p_object) : nullptr;
}
template <typename T>
static const T *cast_to(const Object *p_object) {
return p_object ? dynamic_cast<const T *>(p_object) : nullptr;
static_assert(std::is_base_of_v<Object, T>, "T must be derived from Object");
static_assert(std::is_same_v<std::decay_t<T>, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS");
return p_object && p_object->is_class_ptr(T::get_class_ptr_static()) ? static_cast<const T *>(p_object) : nullptr;
}
enum {
@ -814,17 +807,16 @@ public:
};
/* TYPE API */
static void get_inheritance_list_static(List<String> *p_inheritance_list) { p_inheritance_list->push_back("Object"); }
static String get_class_static() { return "Object"; }
static String get_parent_class_static() { return String(); }
virtual String get_class() const {
if (_extension) {
return _extension->class_name.operator String();
static const StringName &get_class_static() {
static StringName _class_name_static;
if (unlikely(!_class_name_static)) {
StringName::assign_static_unique_class_name(&_class_name_static, "Object");
}
return "Object";
return _class_name_static;
}
_FORCE_INLINE_ String get_class() const { return get_class_name(); }
virtual String get_save_class() const { return get_class(); } //class stored when saving
virtual bool is_class(const String &p_class) const {
@ -835,19 +827,7 @@ public:
}
virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; }
_FORCE_INLINE_ const StringName &get_class_name() const {
if (_extension) {
// Can't put inside the unlikely as constructor can run it
return _extension->class_name;
}
if (unlikely(!_class_name_ptr)) {
// While class is initializing / deinitializing, constructors and destructurs
// need access to the proper class at the proper stage.
return *_get_class_namev();
}
return *_class_name_ptr;
}
const StringName &get_class_name() const;
StringName get_class_name_for_extension(const GDExtension *p_library) const;
@ -882,7 +862,17 @@ public:
return (cerr.error == Callable::CallError::CALL_OK) ? ret : Variant();
}
void notification(int p_notification, bool p_reversed = false);
// Depending on the boolean, we call either the virtual function _notification_backward or _notification_forward.
// - Forward calls subclasses in descending order (e.g. Object -> Node -> Node3D -> extension -> script).
// Backward calls subclasses in descending order (e.g. script -> extension -> Node3D -> Node -> Object).
_FORCE_INLINE_ void notification(int p_notification, bool p_reversed = false) {
if (p_reversed) {
_notification_backward(p_notification);
} else {
_notification_forward(p_notification);
}
}
virtual String to_string();
// Used mainly by script, get and set all INCLUDING string.
@ -974,7 +964,7 @@ public:
#ifdef TOOLS_ENABLED
virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const;
void editor_set_section_unfold(const String &p_section, bool p_unfolded);
void editor_set_section_unfold(const String &p_section, bool p_unfolded, bool p_initializing = false);
bool editor_is_section_unfolded(const String &p_section);
const HashSet<String> &editor_get_section_folding() const { return editor_section_folding; }
void editor_clear_section_folding() { editor_section_folding.clear(); }
@ -1062,8 +1052,15 @@ public:
return object;
}
template <typename T>
_ALWAYS_INLINE_ static T *get_instance(ObjectID p_instance_id) {
return Object::cast_to<T>(get_instance(p_instance_id));
}
template <typename T>
_ALWAYS_INLINE_ static Ref<T> get_ref(ObjectID p_instance_id); // Defined in ref_counted.h
static void debug_objects(DebugFunc p_func);
static int get_object_count();
};
#endif // OBJECT_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef OBJECT_ID_H
#define OBJECT_ID_H
#pragma once
#include "core/typedefs.h"
@ -60,4 +59,5 @@ public:
_ALWAYS_INLINE_ explicit ObjectID(const int64_t p_id) { id = p_id; }
};
#endif // OBJECT_ID_H
template <>
struct is_zero_constructible<ObjectID> : std::true_type {};

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef REF_COUNTED_H
#define REF_COUNTED_H
#pragma once
#include "core/object/class_db.h"
#include "core/templates/safe_refcount.h"
@ -86,6 +85,10 @@ class Ref {
//virtual RefCounted * get_reference() const { return reference; }
public:
static _FORCE_INLINE_ String get_class_static() {
return T::get_class_static();
}
_FORCE_INLINE_ bool operator==(const T *p_ptr) const {
return reference == p_ptr;
}
@ -128,6 +131,15 @@ public:
ref(p_from);
}
void operator=(Ref &&p_from) {
if (reference == p_from.reference) {
return;
}
unref();
reference = p_from.reference;
p_from.reference = nullptr;
}
template <typename T_Other>
void operator=(const Ref<T_Other> &p_from) {
ref_pointer<false>(Object::cast_to<T>(p_from.ptr()));
@ -160,6 +172,11 @@ public:
this->operator=(p_from);
}
Ref(Ref &&p_from) {
reference = p_from.reference;
p_from.reference = nullptr;
}
template <typename T_Other>
Ref(const Ref<T_Other> &p_from) {
this->operator=(p_from);
@ -181,10 +198,15 @@ public:
// do a lot of referencing on references and stuff
// mutexes will avoid more crashes?
if (reference && reference->unreference()) {
memdelete(reference);
if (reference) {
// NOTE: `reinterpret_cast` is "safe" here because we know `T` has simple linear
// inheritance to `RefCounted`. This guarantees that `T * == `RefCounted *`, which
// allows us to declare `Ref<T>` with forward declared `T` types.
if (reinterpret_cast<RefCounted *>(reference)->unreference()) {
memdelete(reinterpret_cast<RefCounted *>(reference));
}
reference = nullptr;
}
reference = nullptr;
}
template <typename... VarArgs>
@ -233,19 +255,6 @@ struct PtrToArg<Ref<T>> {
}
};
template <typename T>
struct PtrToArg<const Ref<T> &> {
typedef Ref<T> EncodeT;
_FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) {
if (p_ptr == nullptr) {
return Ref<T>();
}
// p_ptr points to a RefCounted object
return Ref<T>(*((T *const *)p_ptr));
}
};
template <typename T>
struct GetTypeInfo<Ref<T>> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
@ -256,26 +265,17 @@ struct GetTypeInfo<Ref<T>> {
}
};
template <typename T>
struct GetTypeInfo<const Ref<T> &> {
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
static inline PropertyInfo get_class_info() {
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
}
};
template <typename T>
struct VariantInternalAccessor<Ref<T>> {
static _FORCE_INLINE_ Ref<T> get(const Variant *v) { return Ref<T>(*VariantInternal::get_object(v)); }
static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::object_assign(v, p_ref); }
};
// Zero-constructing Ref initializes reference to nullptr (and thus empty).
template <typename T>
struct VariantInternalAccessor<const Ref<T> &> {
static _FORCE_INLINE_ Ref<T> get(const Variant *v) { return Ref<T>(*VariantInternal::get_object(v)); }
static _FORCE_INLINE_ void set(Variant *v, const Ref<T> &p_ref) { VariantInternal::object_assign(v, p_ref); }
};
struct is_zero_constructible<Ref<T>> : std::true_type {};
#endif // REF_COUNTED_H
template <typename T>
Ref<T> ObjectDB::get_ref(ObjectID p_instance_id) {
return Ref<T>(get_instance(p_instance_id));
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SCRIPT_INSTANCE_H
#define SCRIPT_INSTANCE_H
#pragma once
#include "core/object/ref_counted.h"
@ -96,5 +95,3 @@ public:
virtual ScriptLanguage *get_language() = 0;
virtual ~ScriptInstance();
};
#endif // SCRIPT_INSTANCE_H

View file

@ -633,6 +633,7 @@ void ScriptLanguage::_bind_methods() {
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_PASCAL_CASE);
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_SNAKE_CASE);
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_KEBAB_CASE);
BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_CAMEL_CASE);
}
bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SCRIPT_LANGUAGE_H
#define SCRIPT_LANGUAGE_H
#pragma once
#include "core/doc_data.h"
#include "core/io/resource.h"
@ -247,6 +246,7 @@ public:
SCRIPT_NAME_CASING_PASCAL_CASE,
SCRIPT_NAME_CASING_SNAKE_CASE,
SCRIPT_NAME_CASING_KEBAB_CASE,
SCRIPT_NAME_CASING_CAMEL_CASE,
};
struct ScriptTemplate {
@ -505,5 +505,3 @@ public:
PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner);
~PlaceHolderScriptInstance();
};
#endif // SCRIPT_LANGUAGE_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SCRIPT_LANGUAGE_EXTENSION_H
#define SCRIPT_LANGUAGE_EXTENSION_H
#pragma once
#include "core/extension/ext_wrappers.gen.inc"
#include "core/object/gdvirtual.gen.inc"
@ -193,10 +192,8 @@ public:
virtual void get_constants(HashMap<StringName, Variant> *p_constants) override {
Dictionary constants;
GDVIRTUAL_CALL(_get_constants, constants);
List<Variant> keys;
constants.get_key_list(&keys);
for (const Variant &K : keys) {
p_constants->insert(K, constants[K]);
for (const KeyValue<Variant, Variant> &kv : constants) {
p_constants->insert(kv.key, kv.value);
}
}
GDVIRTUAL0RC_REQUIRED(TypedArray<StringName>, _get_members)
@ -516,7 +513,7 @@ public:
virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override {
Dictionary ret;
GDVIRTUAL_CALL(_debug_get_stack_level_locals, p_level, p_max_subitems, p_max_depth, ret);
if (ret.size() == 0) {
if (ret.is_empty()) {
return;
}
if (p_locals != nullptr && ret.has("locals")) {
@ -536,7 +533,7 @@ public:
virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override {
Dictionary ret;
GDVIRTUAL_CALL(_debug_get_stack_level_members, p_level, p_max_subitems, p_max_depth, ret);
if (ret.size() == 0) {
if (ret.is_empty()) {
return;
}
if (p_members != nullptr && ret.has("members")) {
@ -563,7 +560,7 @@ public:
virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override {
Dictionary ret;
GDVIRTUAL_CALL(_debug_get_globals, p_max_subitems, p_max_depth, ret);
if (ret.size() == 0) {
if (ret.is_empty()) {
return;
}
if (p_globals != nullptr && ret.has("globals")) {
@ -714,11 +711,7 @@ public:
GDExtensionScriptInstanceDataPtr instance = nullptr;
// There should not be warnings on explicit casts.
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
#endif
GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wignored-qualifiers") // There should not be warnings on explicit casts.
virtual bool set(const StringName &p_name, const Variant &p_value) override {
if (native_info->set_func) {
@ -966,9 +959,5 @@ public:
#endif // DISABLE_DEPRECATED
}
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic pop
#endif
GODOT_GCC_WARNING_POP
};
#endif // SCRIPT_LANGUAGE_EXTENSION_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef UNDO_REDO_H
#define UNDO_REDO_H
#pragma once
#include "core/object/class_db.h"
#include "core/object/ref_counted.h"
@ -151,5 +150,3 @@ public:
};
VARIANT_ENUM_CAST(UndoRedo::MergeMode);
#endif // UNDO_REDO_H

View file

@ -37,6 +37,8 @@
WorkerThreadPool::Task *const WorkerThreadPool::ThreadData::YIELDING = (Task *)1;
HashMap<StringName, WorkerThreadPool *> WorkerThreadPool::named_pools;
void WorkerThreadPool::Task::free_template_userdata() {
ERR_FAIL_NULL(template_userdata);
ERR_FAIL_NULL(native_func_userdata);
@ -184,26 +186,34 @@ void WorkerThreadPool::_thread_function(void *p_user) {
while (true) {
Task *task_to_process = nullptr;
{
MutexLock lock(singleton->task_mutex);
// Create the lock outside the inner loop so it isn't needlessly unlocked and relocked
// when no task was found to process, and the loop is re-entered.
MutexLock lock(thread_data->pool->task_mutex);
bool exit = singleton->_handle_runlevel(thread_data, lock);
if (unlikely(exit)) {
while (true) {
bool exit = thread_data->pool->_handle_runlevel(thread_data, lock);
if (unlikely(exit)) {
return;
}
thread_data->signaled = false;
if (!thread_data->pool->task_queue.first()) {
// There wasn't a task available yet.
// Let's wait for the next notification, then recheck.
thread_data->cond_var.wait(lock);
continue;
}
// Got a task to process! Remove it from the queue, then break into the task handling section.
task_to_process = thread_data->pool->task_queue.first()->self();
thread_data->pool->task_queue.remove(thread_data->pool->task_queue.first());
break;
}
thread_data->signaled = false;
if (singleton->task_queue.first()) {
task_to_process = singleton->task_queue.first()->self();
singleton->task_queue.remove(singleton->task_queue.first());
} else {
thread_data->cond_var.wait(lock);
}
}
if (task_to_process) {
singleton->_process_task(task_to_process);
}
DEV_ASSERT(task_to_process);
thread_data->pool->_process_task(task_to_process);
}
}
@ -211,7 +221,7 @@ void WorkerThreadPool::_post_tasks(Task **p_tasks, uint32_t p_count, bool p_high
// Fall back to processing on the calling thread if there are no worker threads.
// Separated into its own variable to make it easier to extend this logic
// in custom builds.
bool process_on_calling_thread = threads.size() == 0;
bool process_on_calling_thread = threads.is_empty();
if (process_on_calling_thread) {
p_lock.temp_unlock();
for (uint32_t i = 0; i < p_count; i++) {
@ -497,7 +507,7 @@ void WorkerThreadPool::_wait_collaboratively(ThreadData *p_caller_pool_thread, T
}
}
if (singleton->task_queue.first()) {
if (p_caller_pool_thread->pool->task_queue.first()) {
task_to_process = task_queue.first()->self();
task_queue.remove(task_queue.first());
}
@ -505,7 +515,9 @@ void WorkerThreadPool::_wait_collaboratively(ThreadData *p_caller_pool_thread, T
if (!task_to_process) {
p_caller_pool_thread->awaited_task = p_task;
_unlock_unlockable_mutexes();
if (this == singleton) {
_unlock_unlockable_mutexes();
}
relock_unlockables = true;
p_caller_pool_thread->cond_var.wait(lock);
@ -514,7 +526,7 @@ void WorkerThreadPool::_wait_collaboratively(ThreadData *p_caller_pool_thread, T
}
}
if (relock_unlockables) {
if (relock_unlockables && this == singleton) {
_lock_unlockable_mutexes();
}
@ -690,9 +702,13 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) {
{
Group *group = *groupp;
_unlock_unlockable_mutexes();
if (this == singleton) {
_unlock_unlockable_mutexes();
}
group->done_semaphore.wait();
_lock_unlockable_mutexes();
if (this == singleton) {
_lock_unlockable_mutexes();
}
uint32_t max_users = group->tasks_used + 1; // Add 1 because the thread waiting for it is also user. Read before to avoid another thread freeing task after increment.
uint32_t finished_users = group->finished.increment(); // fetch happens before inc, so increment later.
@ -709,15 +725,15 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) {
#endif
}
int WorkerThreadPool::get_thread_index() {
int WorkerThreadPool::get_thread_index() const {
Thread::ID tid = Thread::get_caller_id();
return singleton->thread_ids.has(tid) ? singleton->thread_ids[tid] : -1;
return thread_ids.has(tid) ? thread_ids[tid] : -1;
}
WorkerThreadPool::TaskID WorkerThreadPool::get_caller_task_id() {
WorkerThreadPool::TaskID WorkerThreadPool::get_caller_task_id() const {
int th_index = get_thread_index();
if (th_index != -1 && singleton->threads[th_index].current_task) {
return singleton->threads[th_index].current_task->self;
if (th_index != -1 && threads[th_index].current_task) {
return threads[th_index].current_task->self;
} else {
return INVALID_TASK_ID;
}
@ -764,15 +780,29 @@ void WorkerThreadPool::init(int p_thread_count, float p_low_priority_task_ratio)
threads.resize(p_thread_count);
Thread::Settings settings;
#ifdef __APPLE__
// The default stack size for new threads on Apple platforms is 512KiB.
// This is insufficient when using a library like SPIRV-Cross,
// which can generate deep stacks and result in a stack overflow.
#ifdef DEV_ENABLED
// Debug builds need an even larger stack size.
settings.stack_size = 2 * 1024 * 1024; // 2 MiB
#else
settings.stack_size = 1 * 1024 * 1024; // 1 MiB
#endif
#endif
for (uint32_t i = 0; i < threads.size(); i++) {
threads[i].index = i;
threads[i].thread.start(&WorkerThreadPool::_thread_function, &threads[i]);
threads[i].pool = this;
threads[i].thread.start(&WorkerThreadPool::_thread_function, &threads[i], settings);
thread_ids.insert(threads[i].thread.get_id(), i);
}
}
void WorkerThreadPool::exit_languages_threads() {
if (threads.size() == 0) {
if (threads.is_empty()) {
return;
}
@ -792,7 +822,7 @@ void WorkerThreadPool::exit_languages_threads() {
}
void WorkerThreadPool::finish() {
if (threads.size() == 0) {
if (threads.is_empty()) {
return;
}
@ -832,10 +862,33 @@ void WorkerThreadPool::_bind_methods() {
ClassDB::bind_method(D_METHOD("wait_for_group_task_completion", "group_id"), &WorkerThreadPool::wait_for_group_task_completion);
}
WorkerThreadPool::WorkerThreadPool() {
singleton = this;
WorkerThreadPool *WorkerThreadPool::get_named_pool(const StringName &p_name) {
WorkerThreadPool **pool_ptr = named_pools.getptr(p_name);
if (pool_ptr) {
return *pool_ptr;
} else {
WorkerThreadPool *pool = memnew(WorkerThreadPool(false));
pool->init();
named_pools[p_name] = pool;
return pool;
}
}
WorkerThreadPool::WorkerThreadPool(bool p_singleton) {
if (p_singleton) {
singleton = this;
}
}
WorkerThreadPool::~WorkerThreadPool() {
finish();
if (this == singleton) {
singleton = nullptr;
for (KeyValue<StringName, WorkerThreadPool *> &E : named_pools) {
E.value->finish();
memdelete(E.value);
}
named_pools.clear();
}
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef WORKER_THREAD_POOL_H
#define WORKER_THREAD_POOL_H
#pragma once
#include "core/os/condition_variable.h"
#include "core/os/memory.h"
@ -119,6 +118,7 @@ private:
Task *current_task = nullptr;
Task *awaited_task = nullptr; // Null if not awaiting the condition variable, or special value (YIELDING).
ConditionVariable cond_var;
WorkerThreadPool *pool = nullptr;
ThreadData() :
signaled(false),
@ -166,6 +166,8 @@ private:
uint64_t last_task = 1;
static HashMap<StringName, WorkerThreadPool *> named_pools;
static void _thread_function(void *p_user);
void _process_task(Task *task);
@ -266,9 +268,12 @@ public:
#endif
}
// Note: Do not use this unless you know what you are doing, and it is absolutely necessary. Main thread pool (`get_singleton()`) should be preferred instead.
static WorkerThreadPool *get_named_pool(const StringName &p_name);
static WorkerThreadPool *get_singleton() { return singleton; }
static int get_thread_index();
static TaskID get_caller_task_id();
int get_thread_index() const;
TaskID get_caller_task_id() const;
#ifdef THREADS_ENABLED
_ALWAYS_INLINE_ static uint32_t thread_enter_unlock_allowance_zone(const MutexLock<BinaryMutex> &p_lock) { return _thread_enter_unlock_allowance_zone(p_lock._get_lock()); }
@ -285,8 +290,6 @@ public:
void init(int p_thread_count = -1, float p_low_priority_task_ratio = 0.3);
void exit_languages_threads();
void finish();
WorkerThreadPool();
WorkerThreadPool(bool p_singleton = true);
~WorkerThreadPool();
};
#endif // WORKER_THREAD_POOL_H