2014-02-09 22:10:30 -03:00
/**************************************************************************/
2017-01-16 08:04:19 +01:00
/* class_db.cpp */
2014-02-09 22:10:30 -03:00
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2017-01-16 08:04:19 +01:00
# include "class_db.h"
2020-11-07 19:33:38 -03:00
# include "core/config/engine.h"
2023-05-23 09:25:34 -07:00
# include "core/io/resource_loader.h"
2022-10-19 01:58:13 -05:00
# include "core/object/script_language.h"
2025-01-08 20:01:55 +08:00
# include "core/templates/sort_array.h"
2018-09-11 18:13:45 +02:00
# include "core/version.h"
2014-02-09 22:10:30 -03:00
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2022-04-05 20:40:07 -03:00
2022-04-27 12:52:18 +02:00
MethodDefinition D_METHODP ( const char * p_name , const char * const * * p_args , uint32_t p_argcount ) {
2014-02-09 22:10:30 -03:00
MethodDefinition md ;
2025-04-03 22:09:35 +02:00
md . name = StringName ( p_name ) ;
2022-04-27 12:52:18 +02:00
md . args . resize ( p_argcount ) ;
for ( uint32_t i = 0 ; i < p_argcount ; i + + ) {
2025-04-03 22:09:35 +02:00
md . args . write [ i ] = StringName ( * p_args [ i ] ) ;
2022-04-27 12:52:18 +02:00
}
2018-01-20 16:18:51 +01:00
return md ;
}
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2022-04-05 20:40:07 -03:00
2017-01-02 23:03:46 -03:00
ClassDB : : APIType ClassDB : : current_api = API_CORE ;
2023-06-23 16:39:51 +02:00
HashMap < ClassDB : : APIType , uint32_t > ClassDB : : api_hashes_cache ;
2016-09-14 19:37:37 -03:00
2017-01-02 23:03:46 -03:00
void ClassDB : : set_current_api ( APIType p_api ) {
2023-04-26 10:44:03 +02:00
DEV_ASSERT ( ! api_hashes_cache . has ( p_api ) ) ; // This API type may not be suitable for caching of hash if it can change later.
2016-09-14 19:37:37 -03:00
current_api = p_api ;
}
2019-04-06 16:12:59 +02:00
ClassDB : : APIType ClassDB : : get_current_api ( ) {
return current_api ;
}
2018-07-02 15:08:35 -03:00
HashMap < StringName , ClassDB : : ClassInfo > ClassDB : : classes ;
HashMap < StringName , StringName > ClassDB : : resource_base_extensions ;
HashMap < StringName , StringName > ClassDB : : compat_classes ;
2014-02-09 22:10:30 -03:00
2024-01-02 14:10:54 -06:00
# ifdef TOOLS_ENABLED
HashMap < StringName , ObjectGDExtension > ClassDB : : placeholder_extensions ;
class PlaceholderExtensionInstance {
StringName class_name ;
HashMap < StringName , Variant > properties ;
2024-07-08 10:29:01 -05:00
// Checks if a property is from a runtime class, and not a non-runtime base class.
bool is_runtime_property ( const StringName & p_property_name ) {
StringName current_class_name = class_name ;
while ( ClassDB : : is_class_runtime ( current_class_name ) ) {
if ( ClassDB : : has_property ( current_class_name , p_property_name , true ) ) {
return true ;
}
current_class_name = ClassDB : : get_parent_class ( current_class_name ) ;
}
return false ;
}
2024-01-02 14:10:54 -06:00
public :
PlaceholderExtensionInstance ( const StringName & p_class_name ) {
class_name = p_class_name ;
}
2024-07-08 10:29:01 -05:00
void set ( const StringName & p_name , const Variant & p_value , bool & r_valid ) {
r_valid = is_runtime_property ( p_name ) ;
if ( r_valid ) {
2024-01-02 14:10:54 -06:00
properties [ p_name ] = p_value ;
}
}
2024-07-08 10:29:01 -05:00
Variant get ( const StringName & p_name , bool & r_valid ) {
2024-01-02 14:10:54 -06:00
const Variant * value = properties . getptr ( p_name ) ;
Variant ret ;
if ( value ) {
ret = * value ;
2024-07-08 10:29:01 -05:00
r_valid = true ;
2024-01-02 14:10:54 -06:00
} else {
2024-07-08 10:29:01 -05:00
r_valid = is_runtime_property ( p_name ) ;
if ( r_valid ) {
ret = ClassDB : : class_get_default_property_value ( class_name , p_name ) ;
2024-01-02 14:10:54 -06:00
}
}
return ret ;
}
static GDExtensionBool placeholder_instance_set ( GDExtensionClassInstancePtr p_instance , GDExtensionConstStringNamePtr p_name , GDExtensionConstVariantPtr p_value ) {
PlaceholderExtensionInstance * self = ( PlaceholderExtensionInstance * ) p_instance ;
const StringName & name = * ( StringName * ) p_name ;
const Variant & value = * ( const Variant * ) p_value ;
2024-07-08 10:29:01 -05:00
bool valid = false ;
self - > set ( name , value , valid ) ;
2024-01-02 14:10:54 -06:00
2024-07-08 10:29:01 -05:00
return valid ;
2024-01-02 14:10:54 -06:00
}
static GDExtensionBool placeholder_instance_get ( GDExtensionClassInstancePtr p_instance , GDExtensionConstStringNamePtr p_name , GDExtensionVariantPtr r_ret ) {
PlaceholderExtensionInstance * self = ( PlaceholderExtensionInstance * ) p_instance ;
const StringName & name = * ( StringName * ) p_name ;
Variant * value = ( Variant * ) r_ret ;
2024-07-08 10:29:01 -05:00
bool valid = false ;
* value = self - > get ( name , valid ) ;
2024-01-02 14:10:54 -06:00
2024-07-08 10:29:01 -05:00
return valid ;
2024-01-02 14:10:54 -06:00
}
static const GDExtensionPropertyInfo * placeholder_instance_get_property_list ( GDExtensionClassInstancePtr p_instance , uint32_t * r_count ) {
* r_count = 0 ;
return nullptr ;
}
2024-04-25 22:19:19 +02:00
static void placeholder_instance_free_property_list ( GDExtensionClassInstancePtr p_instance , const GDExtensionPropertyInfo * p_list , uint32_t p_count ) {
2024-01-02 14:10:54 -06:00
}
static GDExtensionBool placeholder_instance_property_can_revert ( GDExtensionClassInstancePtr p_instance , GDExtensionConstStringNamePtr p_name ) {
return false ;
}
static GDExtensionBool placeholder_instance_property_get_revert ( GDExtensionClassInstancePtr p_instance , GDExtensionConstStringNamePtr p_name , GDExtensionVariantPtr r_ret ) {
return false ;
}
static GDExtensionBool placeholder_instance_validate_property ( GDExtensionClassInstancePtr p_instance , GDExtensionPropertyInfo * p_property ) {
return false ;
}
static void placeholder_instance_notification ( GDExtensionClassInstancePtr p_instance , int32_t p_what , GDExtensionBool p_reversed ) {
}
static void placeholder_instance_to_string ( GDExtensionClassInstancePtr p_instance , GDExtensionBool * r_is_valid , GDExtensionStringPtr p_out ) {
* r_is_valid = true ;
}
static void placeholder_instance_reference ( GDExtensionClassInstancePtr p_instance ) {
}
static void placeholder_instance_unreference ( GDExtensionClassInstancePtr p_instance ) {
}
static uint64_t placeholder_instance_get_rid ( GDExtensionClassInstancePtr p_instance ) {
return 0 ;
}
2024-08-31 21:48:16 +02:00
static GDExtensionObjectPtr placeholder_class_create_instance ( void * p_class_userdata , GDExtensionBool p_notify_postinitialize ) {
2024-01-02 14:10:54 -06:00
ClassDB : : ClassInfo * ti = ( ClassDB : : ClassInfo * ) p_class_userdata ;
2024-07-08 10:29:01 -05:00
// Find the closest native parent, that isn't a runtime class.
2024-01-02 14:10:54 -06:00
ClassDB : : ClassInfo * native_parent = ti - > inherits_ptr ;
2024-07-08 10:29:01 -05:00
while ( native_parent - > gdextension | | native_parent - > is_runtime ) {
2024-01-02 14:10:54 -06:00
native_parent = native_parent - > inherits_ptr ;
}
2024-02-21 17:56:50 -06:00
ERR_FAIL_NULL_V ( native_parent - > creation_func , nullptr ) ;
2024-01-02 14:10:54 -06:00
// Construct a placeholder.
2024-08-31 21:48:16 +02:00
Object * obj = native_parent - > creation_func ( static_cast < bool > ( p_notify_postinitialize ) ) ;
2024-04-09 13:40:33 -05:00
// 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
// done in a different way to support placeholders) will also be done here.
2024-01-02 14:10:54 -06:00
obj - > _extension = ClassDB : : get_placeholder_extension ( ti - > name ) ;
obj - > _extension_instance = memnew ( PlaceholderExtensionInstance ( ti - > name ) ) ;
2024-04-09 13:40:33 -05:00
2025-10-06 22:35:40 +02:00
obj - > _reset_gdtype ( ) ;
2024-04-09 13:40:33 -05:00
# ifdef TOOLS_ENABLED
if ( obj - > _extension - > track_instance ) {
obj - > _extension - > track_instance ( obj - > _extension - > tracking_userdata , obj ) ;
}
# endif
2024-01-02 14:10:54 -06:00
return obj ;
}
static GDExtensionObjectPtr placeholder_class_recreate_instance ( void * p_class_userdata , GDExtensionObjectPtr p_object ) {
ClassDB : : ClassInfo * ti = ( ClassDB : : ClassInfo * ) p_class_userdata ;
return memnew ( PlaceholderExtensionInstance ( ti - > name ) ) ;
}
static void placeholder_class_free_instance ( void * p_class_userdata , GDExtensionClassInstancePtr p_instance ) {
PlaceholderExtensionInstance * instance = ( PlaceholderExtensionInstance * ) p_instance ;
memdelete ( instance ) ;
}
2024-12-20 17:10:46 -06:00
static GDExtensionClassCallVirtual placeholder_class_get_virtual ( void * p_class_userdata , GDExtensionConstStringNamePtr p_name , uint32_t p_hash ) {
2024-01-02 14:10:54 -06:00
return nullptr ;
}
} ;
# endif
2020-11-01 00:44:15 -07:00
bool ClassDB : : _is_parent_class ( const StringName & p_class , const StringName & p_inherits ) {
2024-08-08 13:16:42 -04:00
ClassInfo * c = classes . getptr ( p_class ) ;
while ( c ) {
if ( c - > name = = p_inherits ) {
2014-02-09 22:10:30 -03:00
return true ;
2020-05-14 16:41:43 +02:00
}
2024-08-08 13:16:42 -04:00
c = c - > inherits_ptr ;
2014-02-09 22:10:30 -03:00
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
return false ;
}
2020-05-14 14:29:06 +02:00
2020-11-01 00:44:15 -07:00
bool ClassDB : : is_parent_class ( const StringName & p_class , const StringName & p_inherits ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2020-11-01 00:44:15 -07:00
return _is_parent_class ( p_class , p_inherits ) ;
}
2025-01-08 20:01:55 +08:00
// This function only sorts items added by this function.
// If `p_classes` is not empty before calling and a global sort is needed, caller must handle that separately.
void ClassDB : : get_class_list ( LocalVector < StringName > & p_classes ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2016-03-09 00:00:52 +01:00
2025-01-08 20:01:55 +08:00
if ( classes . is_empty ( ) ) {
return ;
}
p_classes . reserve ( p_classes . size ( ) + classes . size ( ) ) ;
for ( const KeyValue < StringName , ClassInfo > & cls : classes ) {
p_classes . push_back ( cls . key ) ;
2014-02-09 22:10:30 -03:00
}
2016-03-09 00:00:52 +01:00
2026-02-05 22:44:38 +02:00
SortArray < StringName , StringName : : AlphCompare > sorter ;
2025-01-08 20:01:55 +08:00
sorter . sort ( & p_classes [ p_classes . size ( ) - classes . size ( ) ] , classes . size ( ) ) ;
2014-02-09 22:10:30 -03:00
}
2023-10-31 18:27:17 +01:00
# ifdef TOOLS_ENABLED
2025-01-08 20:01:55 +08:00
// This function only sorts items added by this function.
// If `p_classes` is not empty before calling and a global sort is needed, caller must handle that separately.
void ClassDB : : get_extensions_class_list ( LocalVector < StringName > & p_classes ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2023-10-31 18:27:17 +01:00
2025-01-08 20:01:55 +08:00
uint32_t original_size = p_classes . size ( ) ;
2023-10-31 18:27:17 +01:00
for ( const KeyValue < StringName , ClassInfo > & E : classes ) {
if ( E . value . api ! = API_EXTENSION & & E . value . api ! = API_EDITOR_EXTENSION ) {
continue ;
}
2025-01-08 20:01:55 +08:00
p_classes . push_back ( E . key ) ;
}
// Nothing appended.
if ( p_classes . size ( ) = = original_size ) {
return ;
2024-07-05 10:16:36 -04:00
}
2026-02-05 22:44:38 +02:00
SortArray < StringName , StringName : : AlphCompare > sorter ;
2025-01-08 20:01:55 +08:00
sorter . sort ( & p_classes [ original_size ] , p_classes . size ( ) - original_size ) ;
2024-07-05 10:16:36 -04:00
}
void ClassDB : : get_extension_class_list ( const Ref < GDExtension > & p_extension , List < StringName > * p_classes ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2024-07-05 10:16:36 -04:00
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 ) ;
2023-10-31 18:27:17 +01:00
}
p_classes - > sort_custom < StringName : : AlphCompare > ( ) ;
}
# endif
2025-01-08 20:21:08 +08:00
void ClassDB : : get_inheriters_from_class ( const StringName & p_class , LocalVector < StringName > & p_classes ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2016-03-09 00:00:52 +01:00
2022-05-08 10:09:19 +02:00
for ( const KeyValue < StringName , ClassInfo > & E : classes ) {
if ( E . key ! = p_class & & _is_parent_class ( E . key , p_class ) ) {
2025-01-08 20:21:08 +08:00
p_classes . push_back ( E . key ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
}
2019-04-08 19:18:03 -03:00
void ClassDB : : get_direct_inheriters_from_class ( const StringName & p_class , List < StringName > * p_classes ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2019-04-08 19:18:03 -03:00
2022-05-08 10:09:19 +02:00
for ( const KeyValue < StringName , ClassInfo > & E : classes ) {
2025-03-19 17:05:10 +08:00
if ( E . value . inherits = = p_class ) {
2022-05-08 10:09:19 +02:00
p_classes - > push_back ( E . key ) ;
2020-05-14 16:41:43 +02:00
}
2019-04-08 19:18:03 -03:00
}
}
2017-01-11 18:29:59 -03:00
StringName ClassDB : : get_parent_class_nocheck ( const StringName & p_class ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-01-11 18:29:59 -03:00
ClassInfo * ti = classes . getptr ( p_class ) ;
2020-05-14 16:41:43 +02:00
if ( ! ti ) {
2017-01-11 18:29:59 -03:00
return StringName ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-01-11 18:29:59 -03:00
return ti - > inherits ;
}
2024-06-24 10:09:20 -04:00
bool ClassDB : : get_inheritance_chain_nocheck ( const StringName & p_class , Vector < StringName > & r_result ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2024-06-24 10:09:20 -04:00
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 ;
}
2019-10-03 17:39:08 -03:00
StringName ClassDB : : get_compatibility_remapped_class ( const StringName & p_class ) {
if ( classes . has ( p_class ) ) {
return p_class ;
}
if ( compat_classes . has ( p_class ) ) {
return compat_classes [ p_class ] ;
}
return p_class ;
}
2020-11-01 00:44:15 -07:00
StringName ClassDB : : _get_parent_class ( const StringName & p_class ) {
2017-01-02 23:03:46 -03:00
ClassInfo * ti = classes . getptr ( p_class ) ;
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_V_MSG ( ti , StringName ( ) , vformat ( " Cannot get class '%s'. " , String ( p_class ) ) ) ;
2014-02-09 22:10:30 -03:00
return ti - > inherits ;
}
2020-11-01 00:44:15 -07:00
StringName ClassDB : : get_parent_class ( const StringName & p_class ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2020-11-01 00:44:15 -07:00
return _get_parent_class ( p_class ) ;
}
2017-01-02 23:03:46 -03:00
ClassDB : : APIType ClassDB : : get_api_type ( const StringName & p_class ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2016-09-14 19:37:37 -03:00
2017-01-02 23:03:46 -03:00
ClassInfo * ti = classes . getptr ( p_class ) ;
2017-01-11 18:29:59 -03:00
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_V_MSG ( ti , API_NONE , vformat ( " Cannot get class '%s'. " , String ( p_class ) ) ) ;
2016-09-14 19:37:37 -03:00
return ti - > api ;
}
2023-06-23 16:39:51 +02:00
uint32_t ClassDB : : get_api_hash ( APIType p_api ) {
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2016-09-14 19:37:37 -03:00
2023-04-25 11:40:56 +02:00
if ( api_hashes_cache . has ( p_api ) ) {
return api_hashes_cache [ p_api ] ;
}
2025-03-03 22:27:29 -08:00
uint64_t hash = hash_murmur3_one_64 ( HashMapHasherDefault : : hash ( GODOT_VERSION_FULL_CONFIG ) ) ;
2016-09-14 19:37:37 -03:00
2022-05-08 10:09:19 +02:00
List < StringName > class_list ;
2023-10-20 22:14:04 +02:00
for ( const KeyValue < StringName , ClassInfo > & E : classes ) {
class_list . push_back ( E . key ) ;
}
2022-05-08 10:09:19 +02:00
// Must be alphabetically sorted for hash to compute.
class_list . sort_custom < StringName : : AlphCompare > ( ) ;
2016-09-14 19:37:37 -03:00
2022-05-08 10:09:19 +02:00
for ( const StringName & E : class_list ) {
2021-07-15 23:45:57 -04:00
ClassInfo * t = classes . getptr ( E ) ;
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_V_MSG ( t , 0 , vformat ( " Cannot get class '%s'. " , String ( E ) ) ) ;
2020-05-14 16:41:43 +02:00
if ( t - > api ! = p_api | | ! t - > exposed ) {
2016-09-14 19:37:37 -03:00
continue ;
2020-05-14 16:41:43 +02:00
}
2022-06-18 16:20:55 +02:00
hash = hash_murmur3_one_64 ( t - > name . hash ( ) , hash ) ;
hash = hash_murmur3_one_64 ( t - > inherits . hash ( ) , hash ) ;
2016-09-14 19:37:37 -03:00
{ //methods
List < StringName > snames ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < StringName , MethodBind * > & F : t - > method_map ) {
String name = F . key . operator String ( ) ;
2020-01-07 00:08:46 +01:00
2020-12-15 12:04:21 +00:00
ERR_CONTINUE ( name . is_empty ( ) ) ;
2020-01-07 00:08:46 +01:00
2020-05-14 16:41:43 +02:00
if ( name [ 0 ] = = ' _ ' ) {
2020-01-07 00:08:46 +01:00
continue ; // Ignore non-virtual methods that start with an underscore
2020-05-14 16:41:43 +02:00
}
2020-01-07 00:08:46 +01:00
2022-05-08 10:09:19 +02:00
snames . push_back ( F . key ) ;
2016-09-14 19:37:37 -03:00
}
snames . sort_custom < StringName : : AlphCompare > ( ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & F : snames ) {
2021-07-15 23:45:57 -04:00
MethodBind * mb = t - > method_map [ F ] ;
2022-06-18 16:20:55 +02:00
hash = hash_murmur3_one_64 ( mb - > get_name ( ) . hash ( ) , hash ) ;
hash = hash_murmur3_one_64 ( mb - > get_argument_count ( ) , hash ) ;
hash = hash_murmur3_one_64 ( mb - > get_argument_type ( - 1 ) , hash ) ; //return
2017-03-05 16:44:50 +01:00
2016-09-14 19:37:37 -03:00
for ( int i = 0 ; i < mb - > get_argument_count ( ) ; i + + ) {
2017-12-16 15:47:36 +01:00
const PropertyInfo info = mb - > get_argument_info ( i ) ;
2022-06-18 16:20:55 +02:00
hash = hash_murmur3_one_64 ( info . type , hash ) ;
hash = hash_murmur3_one_64 ( info . name . hash ( ) , hash ) ;
hash = hash_murmur3_one_64 ( info . hint , hash ) ;
hash = hash_murmur3_one_64 ( info . hint_string . hash ( ) , hash ) ;
2016-09-14 19:37:37 -03:00
}
2022-06-18 16:20:55 +02:00
hash = hash_murmur3_one_64 ( mb - > get_default_argument_count ( ) , hash ) ;
2016-09-14 19:37:37 -03:00
2023-09-10 12:36:44 -05:00
for ( int i = 0 ; i < mb - > get_argument_count ( ) ; i + + ) {
if ( mb - > has_default_argument ( i ) ) {
Variant da = mb - > get_default_argument ( i ) ;
hash = hash_murmur3_one_64 ( da . hash ( ) , hash ) ;
}
2016-09-14 19:37:37 -03:00
}
2022-06-18 16:20:55 +02:00
hash = hash_murmur3_one_64 ( mb - > get_hint_flags ( ) , hash ) ;
2016-09-14 19:37:37 -03:00
}
}
{ //constants
List < StringName > snames ;
2022-05-09 12:47:10 +03:00
for ( const KeyValue < StringName , int64_t > & F : t - > constant_map ) {
2022-05-08 10:09:19 +02:00
snames . push_back ( F . key ) ;
2016-09-14 19:37:37 -03:00
}
snames . sort_custom < StringName : : AlphCompare > ( ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & F : snames ) {
2022-06-18 16:20:55 +02:00
hash = hash_murmur3_one_64 ( F . hash ( ) , hash ) ;
2024-12-14 02:17:09 +01:00
hash = hash_murmur3_one_64 ( uint64_t ( t - > constant_map [ F ] ) , hash ) ;
2016-09-14 19:37:37 -03:00
}
}
{ //signals
List < StringName > snames ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < StringName , MethodInfo > & F : t - > signal_map ) {
snames . push_back ( F . key ) ;
2016-09-14 19:37:37 -03:00
}
snames . sort_custom < StringName : : AlphCompare > ( ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & F : snames ) {
2021-07-15 23:45:57 -04:00
MethodInfo & mi = t - > signal_map [ F ] ;
2022-06-18 16:20:55 +02:00
hash = hash_murmur3_one_64 ( F . hash ( ) , hash ) ;
2024-04-15 15:18:34 +02:00
for ( const PropertyInfo & pi : mi . arguments ) {
hash = hash_murmur3_one_64 ( pi . type , hash ) ;
2016-09-14 19:37:37 -03:00
}
}
}
{ //properties
List < StringName > snames ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < StringName , PropertySetGet > & F : t - > property_setget ) {
snames . push_back ( F . key ) ;
2016-09-14 19:37:37 -03:00
}
snames . sort_custom < StringName : : AlphCompare > ( ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & F : snames ) {
2021-07-15 23:45:57 -04:00
PropertySetGet * psg = t - > property_setget . getptr ( F ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL_V ( psg , 0 ) ;
2016-09-14 19:37:37 -03:00
2022-06-18 16:20:55 +02:00
hash = hash_murmur3_one_64 ( F . hash ( ) , hash ) ;
hash = hash_murmur3_one_64 ( psg - > setter . hash ( ) , hash ) ;
hash = hash_murmur3_one_64 ( psg - > getter . hash ( ) , hash ) ;
2016-09-14 19:37:37 -03:00
}
}
//property list
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & F : t - > property_list ) {
2022-06-18 16:20:55 +02:00
hash = hash_murmur3_one_64 ( F . name . hash ( ) , hash ) ;
hash = hash_murmur3_one_64 ( F . type , hash ) ;
hash = hash_murmur3_one_64 ( F . hint , hash ) ;
hash = hash_murmur3_one_64 ( F . hint_string . hash ( ) , hash ) ;
hash = hash_murmur3_one_64 ( F . usage , hash ) ;
2016-09-14 19:37:37 -03:00
}
}
2023-04-25 11:40:56 +02:00
hash = hash_fmix32 ( hash ) ;
2023-04-26 10:44:03 +02:00
// Extension API changes at runtime; let's just not cache them by now.
if ( p_api ! = API_EXTENSION & & p_api ! = API_EDITOR_EXTENSION ) {
api_hashes_cache [ p_api ] = hash ;
}
2023-04-25 11:40:56 +02:00
return hash ;
2016-09-14 19:37:37 -03:00
# else
return 0 ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2016-09-14 19:37:37 -03:00
}
2017-01-02 23:03:46 -03:00
bool ClassDB : : class_exists ( const StringName & p_class ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-01-02 23:03:46 -03:00
return classes . has ( p_class ) ;
2014-02-09 22:10:30 -03:00
}
2017-01-02 23:03:46 -03:00
void ClassDB : : add_compatibility_class ( const StringName & p_class , const StringName & p_fallback ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2017-01-02 23:03:46 -03:00
compat_classes [ p_class ] = p_fallback ;
2015-01-03 16:52:37 -03:00
}
2022-07-14 14:18:18 +02:00
StringName ClassDB : : get_compatibility_class ( const StringName & p_class ) {
if ( compat_classes . has ( p_class ) ) {
return compat_classes [ p_class ] ;
}
return StringName ( ) ;
}
2025-04-02 14:48:26 +08:00
Object * ClassDB : : _instantiate_internal ( const StringName & p_class , bool p_require_real_class , bool p_notify_postinitialize , bool p_exposed_only ) {
2017-01-02 23:03:46 -03:00
ClassInfo * ti ;
2014-02-09 22:10:30 -03:00
{
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-01-02 23:03:46 -03:00
ti = classes . getptr ( p_class ) ;
2025-04-02 14:48:26 +08:00
if ( ! _can_instantiate ( ti , p_exposed_only ) ) {
2017-01-02 23:03:46 -03:00
if ( compat_classes . has ( p_class ) ) {
ti = classes . getptr ( compat_classes [ p_class ] ) ;
2015-01-03 16:52:37 -03:00
}
}
2024-10-11 16:17:49 +02:00
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 ) ) ) ;
2025-09-30 14:34:46 -05:00
# ifndef DISABLE_DEPRECATED
// Force legacy unexposed classes to skip the exposed check to preserve backcompat.
if ( ti - > gdextension & & ti - > gdextension - > legacy_unexposed_class ) {
p_exposed_only = false ;
}
# endif // DISABLE_DEPRECATED
2025-04-02 14:48:26 +08:00
if ( p_exposed_only ) {
ERR_FAIL_COND_V_MSG ( ! ti - > exposed , nullptr , vformat ( " Class '%s' isn't exposed. " , String ( p_class ) ) ) ;
}
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_V_MSG ( ti - > creation_func , nullptr , vformat ( " Class '%s' or its base class cannot be instantiated. " , String ( p_class ) ) ) ;
2014-02-09 22:10:30 -03:00
}
2024-04-22 22:34:44 +08:00
2018-09-06 21:07:46 -03:00
# ifdef TOOLS_ENABLED
2024-05-25 00:23:12 +02:00
if ( ( ti - > api = = API_EDITOR | | ti - > api = = API_EDITOR_EXTENSION ) & & ! Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2024-10-11 16:17:49 +02:00
ERR_PRINT ( vformat ( " Class '%s' can only be instantiated by editor. " , String ( p_class ) ) ) ;
2020-04-02 01:20:12 +02:00
return nullptr ;
2018-09-06 21:07:46 -03:00
}
# endif
2024-04-22 22:34:44 +08:00
2024-02-21 17:56:50 -06:00
# ifdef TOOLS_ENABLED
2024-04-22 22:34:44 +08:00
// 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 ;
2024-02-21 17:56:50 -06:00
}
2024-04-22 22:34:44 +08:00
# 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 ;
2024-02-21 17:56:50 -06:00
}
2024-04-22 22:34:44 +08:00
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 ) ;
}
}
2025-04-02 14:48:26 +08:00
bool ClassDB : : _can_instantiate ( ClassInfo * p_class_info , bool p_exposed_only ) {
2024-04-22 22:34:44 +08:00
if ( ! p_class_info ) {
return false ;
}
2025-09-30 14:34:46 -05:00
# ifndef DISABLE_DEPRECATED
// Force legacy unexposed classes to skip the exposed check to preserve backcompat.
if ( p_class_info - > gdextension & & p_class_info - > gdextension - > legacy_unexposed_class ) {
p_exposed_only = false ;
}
# endif // DISABLE_DEPRECATED
2025-04-02 14:48:26 +08:00
if ( p_exposed_only & & ! p_class_info - > exposed ) {
return false ;
}
if ( p_class_info - > disabled | | ! p_class_info - > creation_func ) {
2024-04-22 22:34:44 +08:00
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 ;
2021-06-04 14:33:48 -03:00
}
2024-04-22 22:34:44 +08:00
# endif // DISABLE_DEPRECATED
return false ;
2014-02-09 22:10:30 -03:00
}
2020-05-14 14:29:06 +02:00
2024-01-02 14:10:54 -06:00
Object * ClassDB : : instantiate ( const StringName & p_class ) {
return _instantiate_internal ( p_class ) ;
}
Object * ClassDB : : instantiate_no_placeholders ( const StringName & p_class ) {
return _instantiate_internal ( p_class , true ) ;
}
2024-04-22 22:34:44 +08:00
Object * ClassDB : : instantiate_without_postinitialization ( const StringName & p_class ) {
return _instantiate_internal ( p_class , true , false ) ;
}
2024-01-02 14:10:54 -06:00
# ifdef TOOLS_ENABLED
ObjectGDExtension * ClassDB : : get_placeholder_extension ( const StringName & p_class ) {
ObjectGDExtension * placeholder_extension = placeholder_extensions . getptr ( p_class ) ;
if ( placeholder_extension ) {
return placeholder_extension ;
}
ClassInfo * ti ;
{
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2024-01-02 14:10:54 -06:00
ti = classes . getptr ( p_class ) ;
2024-04-22 22:34:44 +08:00
if ( ! _can_instantiate ( ti ) ) {
2024-01-02 14:10:54 -06:00
if ( compat_classes . has ( p_class ) ) {
ti = classes . getptr ( compat_classes [ p_class ] ) ;
}
}
2024-10-11 16:17:49 +02:00
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 ) ) ) ;
2024-01-02 14:10:54 -06:00
}
2024-02-21 17:56:50 -06:00
// Make a "fake" extension to act as a placeholder.
2024-01-02 14:10:54 -06:00
placeholder_extensions [ p_class ] = ObjectGDExtension ( ) ;
placeholder_extension = placeholder_extensions . getptr ( p_class ) ;
placeholder_extension - > is_runtime = true ;
placeholder_extension - > is_placeholder = true ;
2024-02-21 17:56:50 -06:00
if ( ti - > gdextension ) {
placeholder_extension - > library = ti - > gdextension - > library ;
placeholder_extension - > parent = ti - > gdextension - > parent ;
placeholder_extension - > children = ti - > gdextension - > children ;
placeholder_extension - > parent_class_name = ti - > gdextension - > parent_class_name ;
placeholder_extension - > class_name = ti - > gdextension - > class_name ;
placeholder_extension - > editor_class = ti - > gdextension - > editor_class ;
placeholder_extension - > reloadable = ti - > gdextension - > reloadable ;
placeholder_extension - > is_virtual = ti - > gdextension - > is_virtual ;
placeholder_extension - > is_abstract = ti - > gdextension - > is_abstract ;
placeholder_extension - > is_exposed = ti - > gdextension - > is_exposed ;
placeholder_extension - > tracking_userdata = ti - > gdextension - > tracking_userdata ;
placeholder_extension - > track_instance = ti - > gdextension - > track_instance ;
placeholder_extension - > untrack_instance = ti - > gdextension - > untrack_instance ;
} else {
placeholder_extension - > library = nullptr ;
placeholder_extension - > parent = nullptr ;
placeholder_extension - > parent_class_name = ti - > inherits ;
placeholder_extension - > class_name = ti - > name ;
placeholder_extension - > editor_class = ti - > api = = API_EDITOR ;
placeholder_extension - > reloadable = false ;
placeholder_extension - > is_virtual = ti - > is_virtual ;
placeholder_extension - > is_abstract = false ;
placeholder_extension - > is_exposed = ti - > exposed ;
}
2024-01-02 14:10:54 -06:00
placeholder_extension - > set = & PlaceholderExtensionInstance : : placeholder_instance_set ;
placeholder_extension - > get = & PlaceholderExtensionInstance : : placeholder_instance_get ;
placeholder_extension - > get_property_list = & PlaceholderExtensionInstance : : placeholder_instance_get_property_list ;
2024-04-25 22:19:19 +02:00
placeholder_extension - > free_property_list2 = & PlaceholderExtensionInstance : : placeholder_instance_free_property_list ;
2024-01-02 14:10:54 -06:00
placeholder_extension - > property_can_revert = & PlaceholderExtensionInstance : : placeholder_instance_property_can_revert ;
placeholder_extension - > property_get_revert = & PlaceholderExtensionInstance : : placeholder_instance_property_get_revert ;
placeholder_extension - > validate_property = & PlaceholderExtensionInstance : : placeholder_instance_validate_property ;
2024-02-28 05:09:29 -08:00
# ifndef DISABLE_DEPRECATED
2024-01-02 14:10:54 -06:00
placeholder_extension - > notification = nullptr ;
2024-04-25 22:19:19 +02:00
placeholder_extension - > free_property_list = nullptr ;
2024-02-28 05:09:29 -08:00
# endif // DISABLE_DEPRECATED
2024-01-02 14:10:54 -06:00
placeholder_extension - > notification2 = & PlaceholderExtensionInstance : : placeholder_instance_notification ;
placeholder_extension - > to_string = & PlaceholderExtensionInstance : : placeholder_instance_to_string ;
placeholder_extension - > reference = & PlaceholderExtensionInstance : : placeholder_instance_reference ;
placeholder_extension - > unreference = & PlaceholderExtensionInstance : : placeholder_instance_unreference ;
placeholder_extension - > get_rid = & PlaceholderExtensionInstance : : placeholder_instance_get_rid ;
placeholder_extension - > class_userdata = ti ;
2024-04-22 22:34:44 +08:00
# ifndef DISABLE_DEPRECATED
placeholder_extension - > create_instance = nullptr ;
# endif // DISABLE_DEPRECATED
placeholder_extension - > create_instance2 = & PlaceholderExtensionInstance : : placeholder_class_create_instance ;
2024-01-02 14:10:54 -06:00
placeholder_extension - > free_instance = & PlaceholderExtensionInstance : : placeholder_class_free_instance ;
2024-12-20 17:10:46 -06:00
# ifndef DISABLE_DEPRECATED
placeholder_extension - > get_virtual = nullptr ;
2024-01-02 14:10:54 -06:00
placeholder_extension - > get_virtual_call_data = nullptr ;
2024-12-20 17:10:46 -06:00
# endif // DISABLE_DEPRECATED
placeholder_extension - > get_virtual2 = & PlaceholderExtensionInstance : : placeholder_class_get_virtual ;
placeholder_extension - > get_virtual_call_data2 = nullptr ;
2024-01-02 14:10:54 -06:00
placeholder_extension - > call_virtual_with_data = nullptr ;
placeholder_extension - > recreate_instance = & PlaceholderExtensionInstance : : placeholder_class_recreate_instance ;
2025-10-06 22:35:40 +02:00
placeholder_extension - > create_gdtype ( ) ;
2024-01-02 14:10:54 -06:00
return placeholder_extension ;
}
# endif
2025-10-06 22:35:40 +02:00
const GDType * ClassDB : : get_gdtype ( const StringName & p_class ) {
Locker : : Lock lock ( Locker : : STATE_READ ) ;
ClassInfo * type = classes . getptr ( p_class ) ;
ERR_FAIL_NULL_V ( type , nullptr ) ;
return type - > gdtype ;
}
2021-11-24 10:22:12 +01:00
void ClassDB : : set_object_extension_instance ( Object * p_object , const StringName & p_class , GDExtensionClassInstancePtr p_instance ) {
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( p_object ) ;
2021-11-24 10:22:12 +01:00
ClassInfo * ti ;
{
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2021-11-24 10:22:12 +01:00
ti = classes . getptr ( p_class ) ;
2024-04-22 22:34:44 +08:00
if ( ! _can_instantiate ( ti ) ) {
2021-11-24 10:22:12 +01:00
if ( compat_classes . has ( p_class ) ) {
ti = classes . getptr ( compat_classes [ p_class ] ) ;
}
}
2024-10-11 16:17:49 +02:00
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 ) ) ) ;
2021-09-22 18:33:29 +02:00
}
2021-11-24 10:22:12 +01:00
2022-12-07 12:11:28 +01:00
p_object - > _extension = ti - > gdextension ;
2021-11-24 10:22:12 +01:00
p_object - > _extension_instance = p_instance ;
2024-04-09 13:40:33 -05:00
2025-10-06 22:35:40 +02:00
p_object - > _reset_gdtype ( ) ;
2024-04-09 13:40:33 -05:00
# ifdef TOOLS_ENABLED
if ( p_object - > _extension - > track_instance ) {
p_object - > _extension - > track_instance ( p_object - > _extension - > tracking_userdata , p_object ) ;
}
# endif
2021-09-21 03:54:50 +02:00
}
2021-06-17 16:03:09 -06:00
bool ClassDB : : can_instantiate ( const StringName & p_class ) {
2024-11-08 15:01:52 +01:00
String script_path ;
{
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2016-03-09 00:00:52 +01:00
2024-11-08 15:01:52 +01:00
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.
2023-05-23 09:25:34 -07:00
}
2019-06-01 16:42:22 +03:00
# ifdef TOOLS_ENABLED
2024-11-08 15:01:52 +01:00
if ( ( ti - > api = = API_EDITOR | | ti - > api = = API_EDITOR_EXTENSION ) & & ! Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
return false ;
}
2019-06-01 16:42:22 +03:00
# endif
2024-11-08 15:01:52 +01:00
return _can_instantiate ( ti ) ;
}
use_script :
Ref < Script > scr = ResourceLoader : : load ( script_path ) ;
return scr . is_valid ( ) & & scr - > is_valid ( ) & & ! scr - > is_abstract ( ) ;
2014-02-09 22:10:30 -03:00
}
2023-02-26 19:42:55 -08:00
bool ClassDB : : is_abstract ( const StringName & p_class ) {
2024-11-08 15:01:52 +01:00
String script_path ;
{
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2023-02-26 19:42:55 -08:00
2024-11-08 15:01:52 +01:00
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.
2023-02-26 19:42:55 -08:00
}
2024-04-22 22:34:44 +08:00
2024-11-08 15:01:52 +01:00
if ( ti - > creation_func ! = nullptr ) {
return false ;
}
if ( ! ti - > gdextension ) {
return true ;
}
2024-04-22 22:34:44 +08:00
# ifndef DISABLE_DEPRECATED
2024-11-08 15:01:52 +01:00
return ti - > gdextension - > create_instance2 = = nullptr & & ti - > gdextension - > create_instance = = nullptr ;
2024-04-22 22:34:44 +08:00
# else
2024-11-08 15:01:52 +01:00
return ti - > gdextension - > create_instance2 = = nullptr ;
2024-04-22 22:34:44 +08:00
# endif // DISABLE_DEPRECATED
2024-11-08 15:01:52 +01:00
}
use_script :
Ref < Script > scr = ResourceLoader : : load ( script_path ) ;
return scr . is_valid ( ) & & scr - > is_valid ( ) & & scr - > is_abstract ( ) ;
2023-02-26 19:42:55 -08:00
}
2022-03-10 08:17:38 +01:00
bool ClassDB : : is_virtual ( const StringName & p_class ) {
2024-11-08 15:01:52 +01:00
String script_path ;
{
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2022-03-10 08:17:38 +01:00
2024-11-08 15:01:52 +01:00
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.
2022-10-19 01:58:13 -05:00
}
2022-03-10 08:17:38 +01:00
# ifdef TOOLS_ENABLED
2024-11-08 15:01:52 +01:00
if ( ( ti - > api = = API_EDITOR | | ti - > api = = API_EDITOR_EXTENSION ) & & ! Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
return false ;
}
2022-03-10 08:17:38 +01:00
# endif
2024-11-08 15:01:52 +01:00
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 ( ) ;
2022-03-10 08:17:38 +01:00
}
2025-10-06 22:35:40 +02:00
void ClassDB : : _add_class ( const GDType & p_class , const GDType * p_inherits ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2014-02-09 22:10:30 -03:00
2025-10-06 22:35:40 +02:00
const StringName & name = p_class . get_name ( ) ;
2014-02-09 22:10:30 -03:00
2025-10-06 22:35:40 +02:00
ERR_FAIL_COND_MSG ( classes . has ( name ) , vformat ( " Class '%s' already exists. " , name ) ) ;
2014-02-09 22:10:30 -03:00
2017-01-02 23:03:46 -03:00
classes [ name ] = ClassInfo ( ) ;
ClassInfo & ti = classes [ name ] ;
2014-02-09 22:10:30 -03:00
ti . name = name ;
2025-10-06 22:35:40 +02:00
ti . gdtype = & p_class ;
if ( p_inherits ) {
ti . inherits = p_inherits - > get_name ( ) ;
}
2016-09-14 19:37:37 -03:00
ti . api = current_api ;
2014-02-09 22:10:30 -03:00
if ( ti . inherits ) {
2017-01-02 23:03:46 -03:00
ERR_FAIL_COND ( ! classes . has ( ti . inherits ) ) ; //it MUST be registered.
ti . inherits_ptr = & classes [ ti . inherits ] ;
2014-02-09 22:10:30 -03:00
} else {
2020-04-02 01:20:12 +02:00
ti . inherits_ptr = nullptr ;
2014-02-09 22:10:30 -03:00
}
}
2020-06-10 18:13:25 -03:00
static MethodInfo info_from_bind ( MethodBind * p_method ) {
MethodInfo minfo ;
minfo . name = p_method - > get_name ( ) ;
minfo . id = p_method - > get_method_id ( ) ;
for ( int i = 0 ; i < p_method - > get_argument_count ( ) ; i + + ) {
minfo . arguments . push_back ( p_method - > get_argument_info ( i ) ) ;
}
minfo . return_val = p_method - > get_return_info ( ) ;
minfo . flags = p_method - > get_hint_flags ( ) ;
for ( int i = 0 ; i < p_method - > get_argument_count ( ) ; i + + ) {
if ( p_method - > has_default_argument ( i ) ) {
minfo . default_arguments . push_back ( p_method - > get_default_argument ( i ) ) ;
}
}
return minfo ;
}
2021-07-19 19:25:15 +02:00
void ClassDB : : get_method_list ( const StringName & p_class , List < MethodInfo > * p_methods , bool p_no_inheritance , bool p_exclude_from_properties ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2016-03-09 00:00:52 +01:00
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
while ( type ) {
if ( type - > disabled ) {
2020-05-14 16:41:43 +02:00
if ( p_no_inheritance ) {
2014-02-09 22:10:30 -03:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
type = type - > inherits_ptr ;
continue ;
}
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2021-07-24 15:46:25 +02:00
for ( const MethodInfo & E : type - > virtual_methods ) {
2021-07-15 23:45:57 -04:00
p_methods - > push_back ( E ) ;
2014-02-09 22:10:30 -03:00
}
2021-07-24 15:46:25 +02:00
for ( const StringName & E : type - > method_order ) {
2021-07-15 23:45:57 -04:00
if ( p_exclude_from_properties & & type - > methods_in_properties . has ( E ) ) {
2017-06-23 15:10:46 -03:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-06-23 15:10:46 -03:00
2021-07-15 23:45:57 -04:00
MethodBind * method = type - > method_map . get ( E ) ;
2020-06-10 18:13:25 -03:00
MethodInfo minfo = info_from_bind ( method ) ;
2017-08-29 18:11:39 +02:00
2014-02-09 22:10:30 -03:00
p_methods - > push_back ( minfo ) ;
}
# else
2022-05-08 10:09:19 +02:00
for ( KeyValue < StringName , MethodBind * > & E : type - > method_map ) {
MethodBind * m = E . value ;
2021-10-07 15:18:52 -03:00
MethodInfo minfo = info_from_bind ( m ) ;
p_methods - > push_back ( minfo ) ;
2014-02-09 22:10:30 -03:00
}
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2023-05-20 13:28:40 +02:00
if ( p_no_inheritance ) {
break ;
}
type = type - > inherits_ptr ;
}
}
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 ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2023-05-20 13:28:40 +02:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
if ( type - > disabled ) {
if ( p_no_inheritance ) {
break ;
}
type = type - > inherits_ptr ;
continue ;
}
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2023-05-20 13:28:40 +02:00
for ( const MethodInfo & E : type - > virtual_methods ) {
2024-12-20 17:10:46 -06:00
Pair < MethodInfo , uint32_t > pair ( E , E . get_compatibility_hash ( ) ) ;
2023-05-20 13:28:40 +02:00
p_methods - > push_back ( pair ) ;
}
for ( const StringName & E : type - > method_order ) {
if ( p_exclude_from_properties & & type - > methods_in_properties . has ( E ) ) {
continue ;
}
MethodBind * method = type - > method_map . get ( E ) ;
MethodInfo minfo = info_from_bind ( method ) ;
Pair < MethodInfo , uint32_t > pair ( minfo , method - > get_hash ( ) ) ;
p_methods - > push_back ( pair ) ;
}
# else
for ( KeyValue < StringName , MethodBind * > & E : type - > method_map ) {
MethodBind * method = E . value ;
MethodInfo minfo = info_from_bind ( method ) ;
2014-02-09 22:10:30 -03:00
2023-05-20 13:28:40 +02:00
Pair < MethodInfo , uint32_t > pair ( minfo , method - > get_hash ( ) ) ;
p_methods - > push_back ( pair ) ;
}
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2016-03-09 00:00:52 +01:00
2023-05-20 13:28:40 +02:00
for ( const KeyValue < StringName , LocalVector < MethodBind * , unsigned int , false , false > > & E : type - > method_map_compatibility ) {
LocalVector < MethodBind * > compat = E . value ;
for ( MethodBind * method : compat ) {
MethodInfo minfo = info_from_bind ( method ) ;
Pair < MethodInfo , uint32_t > pair ( minfo , method - > get_hash ( ) ) ;
p_methods - > push_back ( pair ) ;
}
}
2020-05-14 16:41:43 +02:00
if ( p_no_inheritance ) {
2014-02-09 22:10:30 -03:00
break ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
type = type - > inherits_ptr ;
}
}
2021-07-19 19:25:15 +02:00
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 ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2020-06-10 18:13:25 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
if ( type - > disabled ) {
if ( p_no_inheritance ) {
break ;
}
type = type - > inherits_ptr ;
continue ;
}
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2020-06-10 18:13:25 -03:00
MethodBind * * method = type - > method_map . getptr ( p_method ) ;
if ( method & & * method ) {
if ( r_info ! = nullptr ) {
MethodInfo minfo = info_from_bind ( * method ) ;
* r_info = minfo ;
}
return true ;
} else if ( type - > virtual_methods_map . has ( p_method ) ) {
if ( r_info ) {
* r_info = type - > virtual_methods_map [ p_method ] ;
}
return true ;
}
# else
if ( type - > method_map . has ( p_method ) ) {
if ( r_info ) {
MethodBind * m = type - > method_map [ p_method ] ;
2021-10-07 15:18:52 -03:00
MethodInfo minfo = info_from_bind ( m ) ;
* r_info = minfo ;
2020-06-10 18:13:25 -03:00
}
return true ;
}
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2020-06-10 18:13:25 -03:00
if ( p_no_inheritance ) {
break ;
}
type = type - > inherits_ptr ;
}
return false ;
}
2021-07-19 19:25:15 +02:00
MethodBind * ClassDB : : get_method ( const StringName & p_class , const StringName & p_name ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2016-03-09 00:00:52 +01:00
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
while ( type ) {
MethodBind * * method = type - > method_map . getptr ( p_name ) ;
2020-05-14 16:41:43 +02:00
if ( method & & * method ) {
2014-02-09 22:10:30 -03:00
return * method ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
type = type - > inherits_ptr ;
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2014-02-09 22:10:30 -03:00
}
2023-04-25 20:53:07 +02:00
Vector < uint32_t > ClassDB : : get_method_compatibility_hashes ( const StringName & p_class , const StringName & p_name ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2023-04-25 20:53:07 +02:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
if ( type - > method_map_compatibility . has ( p_name ) ) {
LocalVector < MethodBind * > * c = type - > method_map_compatibility . getptr ( p_name ) ;
Vector < uint32_t > ret ;
for ( uint32_t i = 0 ; i < c - > size ( ) ; i + + ) {
ret . push_back ( ( * c ) [ i ] - > get_hash ( ) ) ;
}
return ret ;
}
type = type - > inherits_ptr ;
}
return Vector < uint32_t > ( ) ;
}
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 ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2023-04-25 20:53:07 +02:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
MethodBind * * method = type - > method_map . getptr ( p_name ) ;
if ( method & & * method ) {
if ( r_method_exists ) {
* r_method_exists = true ;
}
if ( ( * method ) - > get_hash ( ) = = p_hash ) {
return * method ;
}
}
LocalVector < MethodBind * > * compat = type - > method_map_compatibility . getptr ( p_name ) ;
if ( compat ) {
if ( r_method_exists ) {
* r_method_exists = true ;
}
for ( uint32_t i = 0 ; i < compat - > size ( ) ; i + + ) {
if ( ( * compat ) [ i ] - > get_hash ( ) = = p_hash ) {
if ( r_is_deprecated ) {
* r_is_deprecated = true ;
}
return ( * compat ) [ i ] ;
}
}
}
type = type - > inherits_ptr ;
}
return nullptr ;
}
2022-06-24 11:16:37 +02:00
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 ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2016-03-09 00:00:52 +01:00
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2014-02-09 22:10:30 -03:00
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( type ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
if ( type - > constant_map . has ( p_name ) ) {
ERR_FAIL ( ) ;
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
type - > constant_map [ p_name ] = p_constant ;
2017-08-20 17:45:01 +02:00
2017-08-24 00:06:56 -03:00
String enum_name = p_enum ;
2021-12-09 03:42:46 -06:00
if ( ! enum_name . is_empty ( ) ) {
2024-12-05 17:56:08 +01:00
if ( enum_name . contains_char ( ' . ' ) ) {
2017-08-27 14:16:32 +02:00
enum_name = enum_name . get_slicec ( ' . ' , 1 ) ;
2017-08-24 00:06:56 -03:00
}
2022-06-24 11:16:37 +02:00
ClassInfo : : EnumInfo * constants_list = type - > enum_map . getptr ( enum_name ) ;
2017-08-24 00:06:56 -03:00
if ( constants_list ) {
2022-06-24 11:16:37 +02:00
constants_list - > constants . push_back ( p_name ) ;
constants_list - > is_bitfield = p_is_bitfield ;
2017-08-24 00:06:56 -03:00
} else {
2022-06-24 11:16:37 +02:00
ClassInfo : : EnumInfo new_list ;
new_list . is_bitfield = p_is_bitfield ;
new_list . constants . push_back ( p_name ) ;
2017-08-24 00:06:56 -03:00
type - > enum_map [ enum_name ] = new_list ;
}
2017-08-20 17:45:01 +02:00
}
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
type - > constant_order . push_back ( p_name ) ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
}
2017-01-02 23:03:46 -03:00
void ClassDB : : get_integer_constant_list ( const StringName & p_class , List < String > * p_constants , bool p_no_inheritance ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2016-03-09 00:00:52 +01:00
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
while ( type ) {
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2021-07-24 15:46:25 +02:00
for ( const StringName & E : type - > constant_order ) {
2021-07-15 23:45:57 -04:00
p_constants - > push_back ( E ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
# else
2022-05-09 12:47:10 +03:00
for ( const KeyValue < StringName , int64_t > & E : type - > constant_map ) {
2022-05-08 10:09:19 +02:00
p_constants - > push_back ( E . key ) ;
2014-02-09 22:10:30 -03:00
}
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2020-05-14 16:41:43 +02:00
if ( p_no_inheritance ) {
2014-02-09 22:10:30 -03:00
break ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
type = type - > inherits_ptr ;
}
}
2022-05-09 12:47:10 +03:00
int64_t ClassDB : : get_integer_constant ( const StringName & p_class , const StringName & p_name , bool * p_success ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2016-03-09 00:00:52 +01:00
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
while ( type ) {
2022-05-09 12:47:10 +03:00
int64_t * constant = type - > constant_map . getptr ( p_name ) ;
2014-02-09 22:10:30 -03:00
if ( constant ) {
2020-05-14 16:41:43 +02:00
if ( p_success ) {
2014-02-09 22:10:30 -03:00
* p_success = true ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
return * constant ;
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
type = type - > inherits_ptr ;
}
2016-03-09 00:00:52 +01:00
2020-05-14 16:41:43 +02:00
if ( p_success ) {
2016-03-09 00:00:52 +01:00
* p_success = false ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2016-03-09 00:00:52 +01:00
return 0 ;
2014-02-09 22:10:30 -03:00
}
2020-06-10 18:13:25 -03:00
bool ClassDB : : has_integer_constant ( const StringName & p_class , const StringName & p_name , bool p_no_inheritance ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2020-06-10 18:13:25 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
if ( type - > constant_map . has ( p_name ) ) {
return true ;
}
if ( p_no_inheritance ) {
return false ;
}
type = type - > inherits_ptr ;
}
return false ;
}
2017-08-20 17:45:01 +02:00
StringName ClassDB : : get_integer_constant_enum ( const StringName & p_class , const StringName & p_name , bool p_no_inheritance ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-08-20 17:45:01 +02:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
2022-06-24 11:16:37 +02:00
for ( KeyValue < StringName , ClassInfo : : EnumInfo > & E : type - > enum_map ) {
List < StringName > & constants_list = E . value . constants ;
2017-08-20 17:45:01 +02:00
const List < StringName > : : Element * found = constants_list . find ( p_name ) ;
2020-05-14 16:41:43 +02:00
if ( found ) {
2022-05-08 10:09:19 +02:00
return E . key ;
2020-05-14 16:41:43 +02:00
}
2017-08-20 17:45:01 +02:00
}
2020-05-14 16:41:43 +02:00
if ( p_no_inheritance ) {
2017-08-20 17:45:01 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2017-08-20 17:45:01 +02:00
type = type - > inherits_ptr ;
}
return StringName ( ) ;
}
void ClassDB : : get_enum_list ( const StringName & p_class , List < StringName > * p_enums , bool p_no_inheritance ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-08-20 17:45:01 +02:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
2022-06-24 11:16:37 +02:00
for ( KeyValue < StringName , ClassInfo : : EnumInfo > & E : type - > enum_map ) {
2022-05-08 10:09:19 +02:00
p_enums - > push_back ( E . key ) ;
2017-08-20 17:45:01 +02:00
}
2020-05-14 16:41:43 +02:00
if ( p_no_inheritance ) {
2017-08-20 17:45:01 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2017-08-20 17:45:01 +02:00
type = type - > inherits_ptr ;
}
}
void ClassDB : : get_enum_constants ( const StringName & p_class , const StringName & p_enum , List < StringName > * p_constants , bool p_no_inheritance ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-08-20 17:45:01 +02:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
2022-06-24 11:16:37 +02:00
const ClassInfo : : EnumInfo * constants = type - > enum_map . getptr ( p_enum ) ;
2017-08-20 17:45:01 +02:00
if ( constants ) {
2022-06-24 11:16:37 +02:00
for ( const List < StringName > : : Element * E = constants - > constants . front ( ) ; E ; E = E - > next ( ) ) {
2017-08-20 17:45:01 +02:00
p_constants - > push_back ( E - > get ( ) ) ;
}
}
2020-05-14 16:41:43 +02:00
if ( p_no_inheritance ) {
2017-08-20 17:45:01 +02:00
break ;
2020-05-14 16:41:43 +02:00
}
2017-08-20 17:45:01 +02:00
type = type - > inherits_ptr ;
}
}
2021-08-24 15:16:25 -03:00
void ClassDB : : set_method_error_return_values ( const StringName & p_class , const StringName & p_method , const Vector < Error > & p_values ) {
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2021-08-24 15:16:25 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( type ) ;
2021-08-24 15:16:25 -03:00
type - > method_error_values [ p_method ] = p_values ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2021-08-24 15:16:25 -03:00
}
Vector < Error > ClassDB : : get_method_error_return_values ( const StringName & p_class , const StringName & p_method ) {
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2021-08-24 15:16:25 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL_V ( type , Vector < Error > ( ) ) ;
2021-08-24 15:16:25 -03:00
if ( ! type - > method_error_values . has ( p_method ) ) {
return Vector < Error > ( ) ;
}
return type - > method_error_values [ p_method ] ;
# else
return Vector < Error > ( ) ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2021-08-24 15:16:25 -03:00
}
2020-06-10 18:13:25 -03:00
bool ClassDB : : has_enum ( const StringName & p_class , const StringName & p_name , bool p_no_inheritance ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2020-06-10 18:13:25 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
if ( type - > enum_map . has ( p_name ) ) {
return true ;
}
if ( p_no_inheritance ) {
return false ;
}
type = type - > inherits_ptr ;
}
return false ;
}
2022-06-24 11:16:37 +02:00
bool ClassDB : : is_enum_bitfield ( const StringName & p_class , const StringName & p_name , bool p_no_inheritance ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2022-06-24 11:16:37 +02:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
if ( type - > enum_map . has ( p_name ) & & type - > enum_map [ p_name ] . is_bitfield ) {
return true ;
}
if ( p_no_inheritance ) {
return false ;
}
type = type - > inherits_ptr ;
}
return false ;
}
2021-07-19 19:25:15 +02:00
void ClassDB : : add_signal ( const StringName & p_class , const MethodInfo & p_signal ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2017-01-07 18:25:37 -03:00
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( type ) ;
2014-02-09 22:10:30 -03:00
StringName sname = p_signal . name ;
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2018-10-03 16:13:34 +02:00
ClassInfo * check = type ;
2014-02-09 22:10:30 -03:00
while ( check ) {
2024-10-11 16:17:49 +02:00
ERR_FAIL_COND_MSG ( check - > signal_map . has ( sname ) , vformat ( " Class '%s' already has signal '%s'. " , String ( p_class ) , String ( sname ) ) ) ;
2014-02-09 22:10:30 -03:00
check = check - > inherits_ptr ;
}
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
type - > signal_map [ sname ] = p_signal ;
}
2021-07-19 19:25:15 +02:00
void ClassDB : : get_signal_list ( const StringName & p_class , List < MethodInfo > * p_signals , bool p_no_inheritance ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-01-07 18:25:37 -03:00
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( type ) ;
2014-02-09 22:10:30 -03:00
2017-01-02 23:03:46 -03:00
ClassInfo * check = type ;
2014-02-09 22:10:30 -03:00
while ( check ) {
2022-05-08 10:09:19 +02:00
for ( KeyValue < StringName , MethodInfo > & E : check - > signal_map ) {
p_signals - > push_back ( E . value ) ;
2014-02-09 22:10:30 -03:00
}
2020-05-14 16:41:43 +02:00
if ( p_no_inheritance ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
check = check - > inherits_ptr ;
}
}
2021-07-19 19:25:15 +02:00
bool ClassDB : : has_signal ( const StringName & p_class , const StringName & p_signal , bool p_no_inheritance ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
2014-02-09 22:10:30 -03:00
while ( check ) {
2020-05-14 16:41:43 +02:00
if ( check - > signal_map . has ( p_signal ) ) {
2014-02-09 22:10:30 -03:00
return true ;
2020-05-14 16:41:43 +02:00
}
2020-06-10 18:13:25 -03:00
if ( p_no_inheritance ) {
return false ;
}
2014-02-09 22:10:30 -03:00
check = check - > inherits_ptr ;
}
return false ;
}
2021-07-19 19:25:15 +02:00
bool ClassDB : : get_signal ( const StringName & p_class , const StringName & p_signal , MethodInfo * r_signal ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
2016-08-07 19:22:33 -03:00
while ( check ) {
if ( check - > signal_map . has ( p_signal ) ) {
if ( r_signal ) {
* r_signal = check - > signal_map [ p_signal ] ;
}
return true ;
}
check = check - > inherits_ptr ;
}
return false ;
}
2021-11-08 23:53:41 +03:00
void ClassDB : : add_property_group ( const StringName & p_class , const String & p_name , const String & p_prefix , int p_indent_depth ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2017-01-03 00:38:16 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( type ) ;
2017-01-03 00:38:16 -03:00
2021-11-08 23:53:41 +03:00
String prefix = p_prefix ;
if ( p_indent_depth > 0 ) {
prefix = vformat ( " %s,%d " , p_prefix , p_indent_depth ) ;
}
type - > property_list . push_back ( PropertyInfo ( Variant : : NIL , p_name , PROPERTY_HINT_NONE , prefix , PROPERTY_USAGE_GROUP ) ) ;
2017-01-03 00:38:16 -03:00
}
2021-11-08 23:53:41 +03:00
void ClassDB : : add_property_subgroup ( const StringName & p_class , const String & p_name , const String & p_prefix , int p_indent_depth ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2020-04-07 22:51:52 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( type ) ;
2020-04-07 22:51:52 -03:00
2021-11-08 23:53:41 +03:00
String prefix = p_prefix ;
if ( p_indent_depth > 0 ) {
prefix = vformat ( " %s,%d " , p_prefix , p_indent_depth ) ;
}
type - > property_list . push_back ( PropertyInfo ( Variant : : NIL , p_name , PROPERTY_HINT_NONE , prefix , PROPERTY_USAGE_SUBGROUP ) ) ;
2020-04-07 22:51:52 -03:00
}
2021-08-31 10:48:45 +02:00
void ClassDB : : add_property_array_count ( const StringName & p_class , const String & p_label , const StringName & p_count_property , const StringName & p_count_setter , const StringName & p_count_getter , const String & p_array_element_prefix , uint32_t p_count_usage ) {
add_property ( p_class , PropertyInfo ( Variant : : INT , p_count_property , PROPERTY_HINT_NONE , " " , p_count_usage | PROPERTY_USAGE_ARRAY , vformat ( " %s,%s " , p_label , p_array_element_prefix ) ) , p_count_setter , p_count_getter ) ;
}
void ClassDB : : add_property_array ( const StringName & p_class , const StringName & p_path , const String & p_array_element_prefix ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2021-08-31 10:48:45 +02:00
ClassInfo * type = classes . getptr ( p_class ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( type ) ;
2021-08-31 10:48:45 +02:00
type - > property_list . push_back ( PropertyInfo ( Variant : : NIL , p_path , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY , p_array_element_prefix ) ) ;
}
2020-11-28 01:34:13 +01:00
// NOTE: For implementation simplicity reasons, this method doesn't allow setters to have optional arguments at the end.
2021-07-19 19:25:15 +02:00
void ClassDB : : add_property ( const StringName & p_class , const PropertyInfo & p_pinfo , const StringName & p_setter , const StringName & p_getter , int p_index ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
2017-01-07 18:25:37 -03:00
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( type ) ;
2014-02-09 22:10:30 -03:00
2020-04-02 01:20:12 +02:00
MethodBind * mb_set = nullptr ;
2014-02-09 22:10:30 -03:00
if ( p_setter ) {
2017-01-02 23:03:46 -03:00
mb_set = get_method ( p_class , p_setter ) ;
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2019-08-14 20:57:49 -06:00
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_MSG ( mb_set , vformat ( " Invalid setter '%s::%s' for property '%s'. " , p_class , p_setter , p_pinfo . name ) ) ;
2019-08-14 20:57:49 -06:00
int exp_args = 1 + ( p_index > = 0 ? 1 : 0 ) ;
2024-10-11 16:17:49 +02:00
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 ) ) ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
}
2020-04-02 01:20:12 +02:00
MethodBind * mb_get = nullptr ;
2014-02-09 22:10:30 -03:00
if ( p_getter ) {
2017-08-28 00:03:34 -03:00
mb_get = get_method ( p_class , p_getter ) ;
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_MSG ( mb_get , vformat ( " Invalid getter '%s::%s' for property '%s'. " , p_class , p_getter , p_pinfo . name ) ) ;
2014-02-09 22:10:30 -03:00
2019-08-14 20:57:49 -06:00
int exp_args = 0 + ( p_index > = 0 ? 1 : 0 ) ;
2024-10-11 16:17:49 +02:00
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 ) ) ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
}
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2024-10-11 16:17:49 +02:00
ERR_FAIL_COND_MSG ( type - > property_setget . has ( p_pinfo . name ) , vformat ( " Object '%s' already has property '%s'. " , p_class , p_pinfo . name ) ) ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2017-01-07 18:25:37 -03:00
2014-02-09 22:10:30 -03:00
type - > property_list . push_back ( p_pinfo ) ;
2020-06-10 18:13:25 -03:00
type - > property_map [ p_pinfo . name ] = p_pinfo ;
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2017-06-23 15:10:46 -03:00
if ( mb_get ) {
type - > methods_in_properties . insert ( p_getter ) ;
}
if ( mb_set ) {
type - > methods_in_properties . insert ( p_setter ) ;
}
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
PropertySetGet psg ;
psg . setter = p_setter ;
psg . getter = p_getter ;
psg . _setptr = mb_set ;
psg . _getptr = mb_get ;
psg . index = p_index ;
2015-12-05 14:18:22 -03:00
psg . type = p_pinfo . type ;
2017-03-05 16:44:50 +01:00
2014-02-09 22:10:30 -03:00
type - > property_setget [ p_pinfo . name ] = psg ;
}
2021-07-19 19:25:15 +02:00
void ClassDB : : set_property_default_value ( const StringName & p_class , const StringName & p_name , const Variant & p_default ) {
2019-06-01 16:42:22 +03:00
if ( ! default_values . has ( p_class ) ) {
default_values [ p_class ] = HashMap < StringName , Variant > ( ) ;
}
default_values [ p_class ] [ p_name ] = p_default ;
}
2021-08-12 11:26:47 -07:00
void ClassDB : : add_linked_property ( const StringName & p_class , const String & p_property , const String & p_linked_property ) {
# ifdef TOOLS_ENABLED
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2021-08-12 11:26:47 -07:00
ClassInfo * type = classes . getptr ( p_class ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( type ) ;
2021-08-12 11:26:47 -07:00
ERR_FAIL_COND ( ! type - > property_map . has ( p_property ) ) ;
ERR_FAIL_COND ( ! type - > property_map . has ( p_linked_property ) ) ;
2022-07-21 01:18:14 +02:00
if ( ! type - > linked_properties . has ( p_property ) ) {
type - > linked_properties . insert ( p_property , List < StringName > ( ) ) ;
}
type - > linked_properties [ p_property ] . push_back ( p_linked_property ) ;
2021-08-12 11:26:47 -07:00
# endif
}
2021-07-19 19:25:15 +02:00
void ClassDB : : get_property_list ( const StringName & p_class , List < PropertyInfo > * p_list , bool p_no_inheritance , const Object * p_validator ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-01-07 18:25:37 -03:00
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
2014-02-09 22:10:30 -03:00
while ( check ) {
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & pi : check - > property_list ) {
2025-07-10 17:06:13 -07:00
p_list - > push_back ( pi ) ;
2016-05-14 23:48:23 -03:00
if ( p_validator ) {
2025-07-10 17:06:13 -07:00
p_validator - > validate_property ( p_list - > back ( ) - > get ( ) ) ;
2016-05-14 23:48:23 -03:00
}
2014-02-09 22:10:30 -03:00
}
2020-05-14 16:41:43 +02:00
if ( p_no_inheritance ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
check = check - > inherits_ptr ;
}
}
2020-05-14 14:29:06 +02:00
2022-07-21 01:18:14 +02:00
void ClassDB : : get_linked_properties_info ( const StringName & p_class , const StringName & p_property , List < StringName > * r_properties , bool p_no_inheritance ) {
# ifdef TOOLS_ENABLED
ClassInfo * check = classes . getptr ( p_class ) ;
while ( check ) {
if ( ! check - > linked_properties . has ( p_property ) ) {
return ;
}
for ( const StringName & E : check - > linked_properties [ p_property ] ) {
r_properties - > push_back ( E ) ;
}
if ( p_no_inheritance ) {
break ;
}
check = check - > inherits_ptr ;
}
# endif
}
2021-07-19 19:25:15 +02:00
bool ClassDB : : get_property_info ( const StringName & p_class , const StringName & p_property , PropertyInfo * r_info , bool p_no_inheritance , const Object * p_validator ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2020-06-10 18:13:25 -03:00
ClassInfo * check = classes . getptr ( p_class ) ;
while ( check ) {
if ( check - > property_map . has ( p_property ) ) {
PropertyInfo pinfo = check - > property_map [ p_property ] ;
if ( p_validator ) {
2022-08-12 23:57:11 +03:00
p_validator - > validate_property ( pinfo ) ;
2020-06-10 18:13:25 -03:00
}
if ( r_info ) {
* r_info = pinfo ;
}
return true ;
}
if ( p_no_inheritance ) {
break ;
}
check = check - > inherits_ptr ;
}
return false ;
}
2017-01-02 23:03:46 -03:00
bool ClassDB : : set_property ( Object * p_object , const StringName & p_property , const Variant & p_value , bool * r_valid ) {
2021-04-02 20:05:01 +02:00
ERR_FAIL_NULL_V ( p_object , false ) ;
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_object - > get_class_name ( ) ) ;
ClassInfo * check = type ;
2014-02-09 22:10:30 -03:00
while ( check ) {
const PropertySetGet * psg = check - > property_setget . getptr ( p_property ) ;
if ( psg ) {
2015-12-05 14:18:22 -03:00
if ( ! psg - > setter ) {
2020-05-14 16:41:43 +02:00
if ( r_valid ) {
2015-12-05 14:18:22 -03:00
* r_valid = false ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
return true ; //return true but do nothing
2015-12-05 14:18:22 -03:00
}
2020-02-19 16:27:19 -03:00
Callable : : CallError ce ;
2014-02-09 22:10:30 -03:00
if ( psg - > index > = 0 ) {
Variant index = psg - > index ;
const Variant * arg [ 2 ] = { & index , & p_value } ;
2017-01-14 12:26:56 +01:00
//p_object->call(psg->setter,arg,2,ce);
2015-06-29 00:29:49 -03:00
if ( psg - > _setptr ) {
psg - > _setptr - > call ( p_object , arg , 2 , ce ) ;
} else {
2022-03-09 14:58:40 +01:00
p_object - > callp ( psg - > setter , arg , 2 , ce ) ;
2015-06-29 00:29:49 -03:00
}
2014-02-09 22:10:30 -03:00
} else {
const Variant * arg [ 1 ] = { & p_value } ;
if ( psg - > _setptr ) {
psg - > _setptr - > call ( p_object , arg , 1 , ce ) ;
} else {
2022-03-09 14:58:40 +01:00
p_object - > callp ( psg - > setter , arg , 1 , ce ) ;
2014-02-09 22:10:30 -03:00
}
}
2015-12-05 14:18:22 -03:00
2020-05-14 16:41:43 +02:00
if ( r_valid ) {
2020-02-19 16:27:19 -03:00
* r_valid = ce . error = = Callable : : CallError : : CALL_OK ;
2020-05-14 16:41:43 +02:00
}
2015-12-05 14:18:22 -03:00
2014-02-09 22:10:30 -03:00
return true ;
}
check = check - > inherits_ptr ;
}
return false ;
}
2020-05-14 14:29:06 +02:00
2017-01-02 23:03:46 -03:00
bool ClassDB : : get_property ( Object * p_object , const StringName & p_property , Variant & r_value ) {
2021-04-02 20:05:01 +02:00
ERR_FAIL_NULL_V ( p_object , false ) ;
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_object - > get_class_name ( ) ) ;
ClassInfo * check = type ;
2014-02-09 22:10:30 -03:00
while ( check ) {
const PropertySetGet * psg = check - > property_setget . getptr ( p_property ) ;
if ( psg ) {
2020-05-14 16:41:43 +02:00
if ( ! psg - > getter ) {
2014-02-09 22:10:30 -03:00
return true ; //return true but do nothing
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
if ( psg - > index > = 0 ) {
Variant index = psg - > index ;
const Variant * arg [ 1 ] = { & index } ;
2020-02-19 16:27:19 -03:00
Callable : : CallError ce ;
2024-08-30 21:09:30 +03:00
const Variant value = p_object - > callp ( psg - > getter , arg , 1 , ce ) ;
r_value = ( ce . error = = Callable : : CallError : : CALL_OK ) ? value : Variant ( ) ;
2014-02-09 22:10:30 -03:00
} else {
2020-02-19 16:27:19 -03:00
Callable : : CallError ce ;
2014-02-09 22:10:30 -03:00
if ( psg - > _getptr ) {
2020-04-02 01:20:12 +02:00
r_value = psg - > _getptr - > call ( p_object , nullptr , 0 , ce ) ;
2014-02-09 22:10:30 -03:00
} else {
2024-08-30 21:09:30 +03:00
const Variant value = p_object - > callp ( psg - > getter , nullptr , 0 , ce ) ;
r_value = ( ce . error = = Callable : : CallError : : CALL_OK ) ? value : Variant ( ) ;
2014-02-09 22:10:30 -03:00
}
}
return true ;
}
2022-05-09 12:47:10 +03:00
const int64_t * c = check - > constant_map . getptr ( p_property ) ; //constants count
2014-02-09 22:10:30 -03:00
if ( c ) {
r_value = * c ;
return true ;
}
2020-02-19 16:27:19 -03:00
if ( check - > method_map . has ( p_property ) ) { //methods count
r_value = Callable ( p_object , p_property ) ;
return true ;
}
if ( check - > signal_map . has ( p_property ) ) { //signals count
r_value = Signal ( p_object , p_property ) ;
return true ;
}
2014-02-09 22:10:30 -03:00
check = check - > inherits_ptr ;
}
2024-01-17 11:27:40 -03:00
// The "free()" method is special, so we assume it exists and return a Callable.
2023-09-04 17:01:33 +02:00
if ( p_property = = CoreStringName ( free_ ) ) {
2024-01-17 11:27:40 -03:00
r_value = Callable ( p_object , p_property ) ;
return true ;
}
2014-02-09 22:10:30 -03:00
return false ;
}
2017-08-06 02:04:10 +02:00
int ClassDB : : get_property_index ( const StringName & p_class , const StringName & p_property , bool * r_is_valid ) {
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
while ( check ) {
const PropertySetGet * psg = check - > property_setget . getptr ( p_property ) ;
if ( psg ) {
2020-05-14 16:41:43 +02:00
if ( r_is_valid ) {
2017-08-06 02:04:10 +02:00
* r_is_valid = true ;
2020-05-14 16:41:43 +02:00
}
2017-08-06 02:04:10 +02:00
return psg - > index ;
}
check = check - > inherits_ptr ;
}
2020-05-14 16:41:43 +02:00
if ( r_is_valid ) {
2017-08-06 02:04:10 +02:00
* r_is_valid = false ;
2020-05-14 16:41:43 +02:00
}
2017-08-06 02:04:10 +02:00
return - 1 ;
}
2017-01-02 23:03:46 -03:00
Variant : : Type ClassDB : : get_property_type ( const StringName & p_class , const StringName & p_property , bool * r_is_valid ) {
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
2015-12-05 14:18:22 -03:00
while ( check ) {
const PropertySetGet * psg = check - > property_setget . getptr ( p_property ) ;
if ( psg ) {
2020-05-14 16:41:43 +02:00
if ( r_is_valid ) {
2015-12-05 14:18:22 -03:00
* r_is_valid = true ;
2020-05-14 16:41:43 +02:00
}
2015-12-05 14:18:22 -03:00
return psg - > type ;
}
check = check - > inherits_ptr ;
}
2020-05-14 16:41:43 +02:00
if ( r_is_valid ) {
2015-12-05 14:18:22 -03:00
* r_is_valid = false ;
2020-05-14 16:41:43 +02:00
}
2015-12-05 14:18:22 -03:00
return Variant : : NIL ;
}
2021-07-19 19:25:15 +02:00
StringName ClassDB : : get_property_setter ( const StringName & p_class , const StringName & p_property ) {
2017-01-04 01:16:14 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
while ( check ) {
const PropertySetGet * psg = check - > property_setget . getptr ( p_property ) ;
if ( psg ) {
return psg - > setter ;
}
check = check - > inherits_ptr ;
}
return StringName ( ) ;
}
2021-07-19 19:25:15 +02:00
StringName ClassDB : : get_property_getter ( const StringName & p_class , const StringName & p_property ) {
2017-01-04 01:16:14 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
while ( check ) {
const PropertySetGet * psg = check - > property_setget . getptr ( p_property ) ;
if ( psg ) {
return psg - > getter ;
}
check = check - > inherits_ptr ;
}
return StringName ( ) ;
}
2017-01-04 17:37:45 -03:00
bool ClassDB : : has_property ( const StringName & p_class , const StringName & p_property , bool p_no_inheritance ) {
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
while ( check ) {
2020-05-14 16:41:43 +02:00
if ( check - > property_setget . has ( p_property ) ) {
2017-01-04 17:37:45 -03:00
return true ;
2020-05-14 16:41:43 +02:00
}
2017-01-04 17:37:45 -03:00
2020-05-14 16:41:43 +02:00
if ( p_no_inheritance ) {
2017-01-04 17:37:45 -03:00
break ;
2020-05-14 16:41:43 +02:00
}
2017-01-04 17:37:45 -03:00
check = check - > inherits_ptr ;
}
return false ;
}
2014-02-09 22:10:30 -03:00
2021-07-19 19:25:15 +02:00
void ClassDB : : set_method_flags ( const StringName & p_class , const StringName & p_method , int p_flags ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL ( check ) ;
2014-02-09 22:10:30 -03:00
ERR_FAIL_COND ( ! check - > method_map . has ( p_method ) ) ;
check - > method_map [ p_method ] - > set_hint_flags ( p_flags ) ;
}
2021-07-19 19:25:15 +02:00
bool ClassDB : : has_method ( const StringName & p_class , const StringName & p_method , bool p_no_inheritance ) {
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
2014-02-09 22:10:30 -03:00
while ( check ) {
2020-05-14 16:41:43 +02:00
if ( check - > method_map . has ( p_method ) ) {
2014-02-09 22:10:30 -03:00
return true ;
2020-05-14 16:41:43 +02:00
}
if ( p_no_inheritance ) {
2014-02-09 22:10:30 -03:00
return false ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
check = check - > inherits_ptr ;
}
return false ;
}
2024-01-28 15:16:09 +01:00
int ClassDB : : get_method_argument_count ( const StringName & p_class , const StringName & p_method , bool * r_is_valid , bool p_no_inheritance ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2024-01-28 15:16:09 +01:00
ClassInfo * type = classes . getptr ( p_class ) ;
while ( type ) {
MethodBind * * method = type - > method_map . getptr ( p_method ) ;
if ( method & & * method ) {
if ( r_is_valid ) {
* r_is_valid = true ;
}
return ( * method ) - > get_argument_count ( ) ;
}
if ( p_no_inheritance ) {
break ;
}
type = type - > inherits_ptr ;
}
if ( r_is_valid ) {
* r_is_valid = false ;
}
return 0 ;
}
2021-06-04 14:33:48 -03:00
void ClassDB : : bind_method_custom ( const StringName & p_class , MethodBind * p_method ) {
2023-04-25 20:53:07 +02:00
_bind_method_custom ( p_class , p_method , false ) ;
}
void ClassDB : : bind_compatibility_method_custom ( const StringName & p_class , MethodBind * p_method ) {
_bind_method_custom ( p_class , p_method , true ) ;
}
void ClassDB : : _bind_compatibility ( ClassInfo * type , MethodBind * p_method ) {
if ( ! type - > method_map_compatibility . has ( p_method - > get_name ( ) ) ) {
type - > method_map_compatibility . insert ( p_method - > get_name ( ) , LocalVector < MethodBind * > ( ) ) ;
}
type - > method_map_compatibility [ p_method - > get_name ( ) ] . push_back ( p_method ) ;
}
void ClassDB : : _bind_method_custom ( const StringName & p_class , MethodBind * p_method , bool p_compatibility ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2023-10-20 22:14:04 +02:00
2025-01-28 10:53:43 -06:00
StringName method_name = p_method - > get_name ( ) ;
2021-06-04 14:33:48 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
if ( ! type ) {
2025-01-28 10:53:43 -06:00
memdelete ( p_method ) ;
ERR_FAIL_MSG ( vformat ( " Couldn't bind custom method '%s' for instance '%s'. " , method_name , p_class ) ) ;
2021-06-04 14:33:48 -03:00
}
2023-04-25 20:53:07 +02:00
if ( p_compatibility ) {
_bind_compatibility ( type , p_method ) ;
return ;
}
2025-01-28 10:53:43 -06:00
if ( type - > method_map . has ( method_name ) ) {
2021-06-04 14:33:48 -03:00
// overloading not supported
2025-01-28 10:53:43 -06:00
memdelete ( p_method ) ;
ERR_FAIL_MSG ( vformat ( " Method already bound '%s::%s'. " , p_class , method_name ) ) ;
2021-06-04 14:33:48 -03:00
}
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2025-01-28 10:53:43 -06:00
type - > method_order . push_back ( method_name ) ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2021-06-04 14:33:48 -03:00
2025-01-28 10:53:43 -06:00
type - > method_map [ method_name ] = p_method ;
2021-06-04 14:33:48 -03:00
}
2023-04-25 20:53:07 +02:00
MethodBind * ClassDB : : _bind_vararg_method ( MethodBind * p_bind , const StringName & p_name , const Vector < Variant > & p_default_args , bool p_compatibility ) {
MethodBind * bind = p_bind ;
bind - > set_name ( p_name ) ;
bind - > set_default_arguments ( p_default_args ) ;
String instance_type = bind - > get_instance_class ( ) ;
ClassInfo * type = classes . getptr ( instance_type ) ;
if ( ! type ) {
memdelete ( bind ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL_V ( type , nullptr ) ;
2023-04-25 20:53:07 +02:00
}
if ( p_compatibility ) {
_bind_compatibility ( type , bind ) ;
return bind ;
}
if ( type - > method_map . has ( p_name ) ) {
memdelete ( bind ) ;
// Overloading not supported
2024-10-11 16:17:49 +02:00
ERR_FAIL_V_MSG ( nullptr , vformat ( " Method already bound: '%s::%s'. " , instance_type , p_name ) ) ;
2023-04-25 20:53:07 +02:00
}
type - > method_map [ p_name ] = bind ;
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2023-04-25 20:53:07 +02:00
// FIXME: <reduz> set_return_type is no longer in MethodBind, so I guess it should be moved to vararg method bind
//bind->set_return_type("Variant");
type - > method_order . push_back ( p_name ) ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2023-04-25 20:53:07 +02:00
return bind ;
}
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2023-04-25 20:53:07 +02:00
MethodBind * ClassDB : : bind_methodfi ( uint32_t p_flags , MethodBind * p_bind , bool p_compatibility , const MethodDefinition & method_name , const Variant * * p_defs , int p_defcount ) {
2014-02-09 22:10:30 -03:00
StringName mdname = method_name . name ;
2022-04-05 20:40:07 -03:00
# else
2023-04-25 20:53:07 +02:00
MethodBind * ClassDB : : bind_methodfi ( uint32_t p_flags , MethodBind * p_bind , bool p_compatibility , const char * method_name , const Variant * * p_defs , int p_defcount ) {
2025-04-03 22:09:35 +02:00
StringName mdname = StringName ( method_name ) ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2023-09-09 16:11:33 +02:00
ERR_FAIL_NULL_V ( p_bind , nullptr ) ;
2014-02-09 22:10:30 -03:00
p_bind - > set_name ( mdname ) ;
2017-01-02 23:03:46 -03:00
String instance_type = p_bind - > get_instance_class ( ) ;
2014-02-09 22:10:30 -03:00
2017-01-14 11:07:57 -03:00
# ifdef DEBUG_ENABLED
2024-10-11 16:17:49 +02:00
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 ) ) ) ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2017-01-14 11:07:57 -03:00
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( instance_type ) ;
2014-02-09 22:10:30 -03:00
if ( ! type ) {
memdelete ( p_bind ) ;
2024-10-11 16:17:49 +02:00
ERR_FAIL_V_MSG ( nullptr , vformat ( " Couldn't bind method '%s' for instance '%s'. " , mdname , instance_type ) ) ;
2014-02-09 22:10:30 -03:00
}
2023-04-25 20:53:07 +02:00
if ( ! p_compatibility & & type - > method_map . has ( mdname ) ) {
2014-02-09 22:10:30 -03:00
memdelete ( p_bind ) ;
// overloading not supported
2024-10-11 16:17:49 +02:00
ERR_FAIL_V_MSG ( nullptr , vformat ( " Method already bound '%s::%s'. " , instance_type , mdname ) ) ;
2014-02-09 22:10:30 -03:00
}
2017-08-09 11:54:27 +02:00
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2017-08-09 11:54:27 +02:00
if ( method_name . args . size ( ) > p_bind - > get_argument_count ( ) ) {
memdelete ( p_bind ) ;
2024-10-11 16:17:49 +02:00
ERR_FAIL_V_MSG ( nullptr , vformat ( " Method definition provides more arguments than the method actually has '%s::%s'. " , instance_type , mdname ) ) ;
2017-08-09 11:54:27 +02:00
}
2025-01-10 16:29:39 -06:00
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 ) ) ;
}
2014-02-09 22:10:30 -03:00
p_bind - > set_argument_names ( method_name . args ) ;
2017-08-09 11:54:27 +02:00
2023-04-25 20:53:07 +02:00
if ( ! p_compatibility ) {
type - > method_order . push_back ( mdname ) ;
}
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2017-08-09 11:54:27 +02:00
2023-04-25 20:53:07 +02:00
if ( p_compatibility ) {
_bind_compatibility ( type , p_bind ) ;
} else {
type - > method_map [ mdname ] = p_bind ;
}
2014-02-09 22:10:30 -03:00
Vector < Variant > defvals ;
defvals . resize ( p_defcount ) ;
for ( int i = 0 ; i < p_defcount ; i + + ) {
2020-10-15 12:29:59 -03:00
defvals . write [ i ] = * p_defs [ i ] ;
2014-02-09 22:10:30 -03:00
}
p_bind - > set_default_arguments ( defvals ) ;
p_bind - > set_hint_flags ( p_flags ) ;
return p_bind ;
}
2021-08-21 22:52:44 -03:00
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 ) {
2024-10-11 16:17:49 +02:00
ERR_FAIL_COND_MSG ( ! classes . has ( p_class ) , vformat ( " Request for nonexistent class '%s'. " , p_class ) ) ;
2014-02-09 22:10:30 -03:00
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2017-01-07 18:25:37 -03:00
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
MethodInfo mi = p_method ;
2020-05-14 16:41:43 +02:00
if ( p_virtual ) {
2015-04-12 22:22:44 -03:00
mi . flags | = METHOD_FLAG_VIRTUAL ;
2020-05-14 16:41:43 +02:00
}
2021-08-21 22:52:44 -03:00
if ( p_object_core ) {
mi . flags | = METHOD_FLAG_OBJECT_CORE ;
}
2022-03-26 16:48:43 +01:00
if ( ! p_object_core ) {
2021-08-21 22:52:44 -03:00
if ( p_arg_names . size ( ) ! = mi . arguments . size ( ) ) {
2024-10-11 16:17:49 +02:00
WARN_PRINT ( vformat ( " Mismatch argument name count for virtual method: '%s::%s'. " , String ( p_class ) , p_method . name ) ) ;
2021-08-21 22:52:44 -03:00
} else {
2024-05-07 12:48:51 +02:00
for ( int64_t i = 0 ; i < p_arg_names . size ( ) ; + + i ) {
mi . arguments . write [ i ] . name = p_arg_names [ i ] ;
2021-08-21 22:52:44 -03:00
}
}
}
2022-03-26 16:48:43 +01:00
if ( classes [ p_class ] . virtual_methods_map . has ( p_method . name ) ) {
// overloading not supported
2024-10-11 16:17:49 +02:00
ERR_FAIL_MSG ( vformat ( " Virtual method already bound '%s::%s'. " , String ( p_class ) , p_method . name ) ) ;
2022-03-26 16:48:43 +01:00
}
2017-01-02 23:03:46 -03:00
classes [ p_class ] . virtual_methods . push_back ( mi ) ;
2020-06-10 18:13:25 -03:00
classes [ p_class ] . virtual_methods_map [ p_method . name ] = mi ;
2014-02-09 22:10:30 -03:00
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
}
2024-12-20 17:10:46 -06:00
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 ) ) ;
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2024-12-20 17:10:46 -06:00
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 ( ) ) ;
}
2017-01-02 23:03:46 -03:00
void ClassDB : : get_virtual_methods ( const StringName & p_class , List < MethodInfo > * p_methods , bool p_no_inheritance ) {
2024-10-11 16:17:49 +02:00
ERR_FAIL_COND_MSG ( ! classes . has ( p_class ) , vformat ( " Request for nonexistent class '%s'. " , p_class ) ) ;
2014-02-09 22:10:30 -03:00
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2014-12-18 00:56:33 -03:00
2017-01-02 23:03:46 -03:00
ClassInfo * type = classes . getptr ( p_class ) ;
ClassInfo * check = type ;
2014-12-18 00:56:33 -03:00
while ( check ) {
2021-07-24 15:46:25 +02:00
for ( const MethodInfo & E : check - > virtual_methods ) {
2021-07-15 23:45:57 -04:00
p_methods - > push_back ( E ) ;
2014-12-18 00:56:33 -03:00
}
2020-05-14 16:41:43 +02:00
if ( p_no_inheritance ) {
2014-12-18 00:56:33 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-12-18 00:56:33 -03:00
check = check - > inherits_ptr ;
}
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
}
2024-12-20 17:10:46 -06:00
Vector < uint32_t > ClassDB : : get_virtual_method_compatibility_hashes ( const StringName & p_class , const StringName & p_name ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2024-12-20 17:10:46 -06:00
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 > ( ) ;
}
2024-01-20 19:40:43 -06:00
void ClassDB : : add_extension_class_virtual_method ( const StringName & p_class , const GDExtensionClassVirtualMethodInfo * p_method_info ) {
2024-10-11 16:17:49 +02:00
ERR_FAIL_COND_MSG ( ! classes . has ( p_class ) , vformat ( " Request for nonexistent class '%s'. " , p_class ) ) ;
2024-01-20 19:40:43 -06:00
2025-05-15 13:09:41 -05:00
# ifdef DEBUG_ENABLED
2024-01-20 19:40:43 -06:00
PackedStringArray arg_names ;
MethodInfo mi ;
mi . name = * reinterpret_cast < StringName * > ( p_method_info - > name ) ;
mi . return_val = PropertyInfo ( p_method_info - > return_value ) ;
mi . return_val_metadata = p_method_info - > return_value_metadata ;
mi . flags = p_method_info - > method_flags ;
for ( int i = 0 ; i < ( int ) p_method_info - > argument_count ; i + + ) {
PropertyInfo arg ( p_method_info - > arguments [ i ] ) ;
mi . arguments . push_back ( arg ) ;
mi . arguments_metadata . push_back ( p_method_info - > arguments_metadata [ i ] ) ;
arg_names . push_back ( arg . name ) ;
}
add_virtual_method ( p_class , mi , true , arg_names ) ;
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2024-01-20 19:40:43 -06:00
}
2021-07-19 19:25:15 +02:00
void ClassDB : : set_class_enabled ( const StringName & p_class , bool p_enable ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
2017-01-07 18:25:37 -03:00
2024-10-11 16:17:49 +02:00
ERR_FAIL_COND_MSG ( ! classes . has ( p_class ) , vformat ( " Request for nonexistent class '%s'. " , p_class ) ) ;
2017-01-02 23:03:46 -03:00
classes [ p_class ] . disabled = ! p_enable ;
2014-02-09 22:10:30 -03:00
}
2021-07-19 19:25:15 +02:00
bool ClassDB : : is_class_enabled ( const StringName & p_class ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-01-07 18:25:37 -03:00
2017-01-02 23:03:46 -03:00
ClassInfo * ti = classes . getptr ( p_class ) ;
2015-01-13 11:22:56 -03:00
if ( ! ti | | ! ti - > creation_func ) {
2017-01-02 23:03:46 -03:00
if ( compat_classes . has ( p_class ) ) {
ti = classes . getptr ( compat_classes [ p_class ] ) ;
2015-01-13 11:22:56 -03:00
}
}
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_V_MSG ( ti , false , vformat ( " Cannot get class '%s'. " , String ( p_class ) ) ) ;
2015-01-13 11:22:56 -03:00
return ! ti - > disabled ;
2014-02-09 22:10:30 -03:00
}
2021-07-19 19:25:15 +02:00
bool ClassDB : : is_class_exposed ( const StringName & p_class ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2017-10-09 23:49:17 +02:00
ClassInfo * ti = classes . getptr ( p_class ) ;
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_V_MSG ( ti , false , vformat ( " Cannot get class '%s'. " , String ( p_class ) ) ) ;
2017-10-09 23:49:17 +02:00
return ti - > exposed ;
}
2023-08-04 20:34:14 -05:00
bool ClassDB : : is_class_reloadable ( const StringName & p_class ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2023-08-04 20:34:14 -05:00
ClassInfo * ti = classes . getptr ( p_class ) ;
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_V_MSG ( ti , false , vformat ( " Cannot get class '%s'. " , String ( p_class ) ) ) ;
2023-08-04 20:34:14 -05:00
return ti - > reloadable ;
}
2024-07-08 10:29:01 -05:00
bool ClassDB : : is_class_runtime ( const StringName & p_class ) {
2025-02-05 09:33:05 +01:00
Locker : : Lock lock ( Locker : : STATE_READ ) ;
2024-07-08 10:29:01 -05:00
ClassInfo * ti = classes . getptr ( p_class ) ;
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_V_MSG ( ti , false , vformat ( " Cannot get class '%s'. " , String ( p_class ) ) ) ;
2024-07-08 10:29:01 -05:00
return ti - > is_runtime ;
}
2025-03-06 15:42:10 -03:00
# ifdef TOOLS_ENABLED
void ClassDB : : add_class_dependency ( const StringName & p_class , const StringName & p_dependency ) {
Locker : : Lock lock ( Locker : : STATE_WRITE ) ;
ERR_FAIL_COND_MSG ( ! classes . has ( p_class ) , vformat ( " Request for nonexistent class '%s'. " , p_class ) ) ;
if ( classes [ p_class ] . dependency_list . find ( p_dependency ) ) {
ERR_FAIL ( ) ;
}
classes [ p_class ] . dependency_list . push_back ( p_dependency ) ;
}
void ClassDB : : get_class_dependencies ( const StringName & p_class , List < StringName > * r_rependencies ) {
Locker : : Lock lock ( Locker : : STATE_READ ) ;
ClassInfo * ti = classes . getptr ( p_class ) ;
ERR_FAIL_NULL_MSG ( ti , vformat ( " Cannot get class '%s'. " , String ( p_class ) ) ) ;
for ( const StringName & dep : ti - > dependency_list ) {
r_rependencies - > push_back ( dep ) ;
}
}
# endif // TOOLS_ENABLED
2017-01-02 23:03:46 -03:00
void ClassDB : : add_resource_base_extension ( const StringName & p_extension , const StringName & p_class ) {
2020-05-14 16:41:43 +02:00
if ( resource_base_extensions . has ( p_extension ) ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2017-01-02 23:03:46 -03:00
resource_base_extensions [ p_extension ] = p_class ;
2014-02-09 22:10:30 -03:00
}
2017-01-02 23:03:46 -03:00
void ClassDB : : get_resource_base_extensions ( List < String > * p_extensions ) {
2022-05-08 10:09:19 +02:00
for ( const KeyValue < StringName , StringName > & E : resource_base_extensions ) {
p_extensions - > push_back ( E . key ) ;
2014-02-09 22:10:30 -03:00
}
}
2021-07-23 16:01:18 -03:00
bool ClassDB : : is_resource_extension ( const StringName & p_extension ) {
return resource_base_extensions . has ( p_extension ) ;
}
2017-01-02 23:03:46 -03:00
void ClassDB : : get_extensions_for_type ( const StringName & p_class , List < String > * p_extensions ) {
2022-05-08 10:09:19 +02:00
for ( const KeyValue < StringName , StringName > & E : resource_base_extensions ) {
if ( is_parent_class ( p_class , E . value ) | | is_parent_class ( E . value , p_class ) ) {
p_extensions - > push_back ( E . key ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
}
2020-03-17 07:33:00 +01:00
HashMap < StringName , HashMap < StringName , Variant > > ClassDB : : default_values ;
2022-05-19 17:00:06 +02:00
HashSet < StringName > ClassDB : : default_values_cached ;
2018-11-08 11:30:02 -03:00
2019-06-29 15:51:33 +03:00
Variant ClassDB : : class_get_default_property_value ( const StringName & p_class , const StringName & p_property , bool * r_valid ) {
2019-06-01 16:42:22 +03:00
if ( ! default_values_cached . has ( p_class ) ) {
if ( ! default_values . has ( p_class ) ) {
default_values [ p_class ] = HashMap < StringName , Variant > ( ) ;
}
2018-11-08 11:30:02 -03:00
2020-04-02 01:20:12 +02:00
Object * c = nullptr ;
2019-06-01 16:42:22 +03:00
bool cleanup_c = false ;
if ( Engine : : get_singleton ( ) - > has_singleton ( p_class ) ) {
c = Engine : : get_singleton ( ) - > get_singleton_object ( p_class ) ;
cleanup_c = false ;
2022-11-09 01:59:49 -06:00
} else if ( ClassDB : : can_instantiate ( p_class ) & & ! ClassDB : : is_virtual ( p_class ) ) { // Keep this condition in sync with doc_tools.cpp get_documentation_default_value.
2024-01-02 14:10:54 -06:00
c = ClassDB : : instantiate_no_placeholders ( p_class ) ;
2020-02-19 09:14:39 -03:00
cleanup_c = true ;
2019-06-01 16:42:22 +03:00
}
if ( c ) {
2018-11-08 11:30:02 -03:00
List < PropertyInfo > plist ;
c - > get_property_list ( & plist ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : plist ) {
2021-07-15 23:45:57 -04:00
if ( E . usage & ( PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR ) ) {
if ( ! default_values [ p_class ] . has ( E . name ) ) {
Variant v = c - > get ( E . name ) ;
default_values [ p_class ] [ E . name ] = v ;
2019-06-01 16:42:22 +03:00
}
2018-11-08 11:30:02 -03:00
}
}
2019-06-01 16:42:22 +03:00
if ( cleanup_c ) {
memdelete ( c ) ;
}
2018-11-08 11:30:02 -03:00
}
2019-06-01 16:42:22 +03:00
default_values_cached . insert ( p_class ) ;
2018-11-08 11:30:02 -03:00
}
if ( ! default_values . has ( p_class ) ) {
2020-05-14 16:41:43 +02:00
if ( r_valid ! = nullptr ) {
2020-04-02 01:20:12 +02:00
* r_valid = false ;
2020-05-14 16:41:43 +02:00
}
2018-11-08 11:30:02 -03:00
return Variant ( ) ;
}
if ( ! default_values [ p_class ] . has ( p_property ) ) {
2020-05-14 16:41:43 +02:00
if ( r_valid ! = nullptr ) {
2020-04-02 01:20:12 +02:00
* r_valid = false ;
2020-05-14 16:41:43 +02:00
}
2018-11-08 11:30:02 -03:00
return Variant ( ) ;
}
2020-05-14 16:41:43 +02:00
if ( r_valid ! = nullptr ) {
2020-04-02 01:20:12 +02:00
* r_valid = true ;
2020-05-14 16:41:43 +02:00
}
2020-06-12 13:16:14 +02:00
Variant var = default_values [ p_class ] [ p_property ] ;
# ifdef DEBUG_ENABLED
// Some properties may have an instantiated Object as default value,
// (like Path2D's `curve` used to have), but that's not a good practice.
// Instead, those properties should use PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT
2020-10-22 22:02:57 +03:00
// to be auto-instantiated when created in the editor with the following method:
// EditorNode::get_editor_data().instantiate_object_properties(obj);
2020-06-12 13:16:14 +02:00
if ( var . get_type ( ) = = Variant : : OBJECT ) {
Object * obj = var . get_validated_object ( ) ;
if ( obj ) {
WARN_PRINT ( vformat ( " Instantiated %s used as default value for %s's \" %s \" property. " , obj - > get_class ( ) , p_class , p_property ) ) ;
}
}
2025-05-15 13:09:41 -05:00
# endif // DEBUG_ENABLED
2020-06-12 13:16:14 +02:00
return var ;
2018-11-08 11:30:02 -03:00
}
2022-12-07 12:11:28 +01:00
void ClassDB : : register_extension_class ( ObjectGDExtension * p_extension ) {
2021-06-04 14:33:48 -03:00
GLOBAL_LOCK_FUNCTION ;
2024-10-11 16:17:49 +02:00
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 ) ) ) ;
2021-06-04 14:33:48 -03:00
ClassInfo * parent = classes . getptr ( p_extension - > parent_class_name ) ;
2024-07-08 10:29:01 -05:00
# ifdef TOOLS_ENABLED
// @todo This is a limitation of the current implementation, but it should be possible to remove.
2024-10-11 16:17:49 +02:00
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 ) ) ;
2024-07-08 10:29:01 -05:00
# endif
2021-06-04 14:33:48 -03:00
ClassInfo c ;
c . api = p_extension - > editor_class ? API_EDITOR_EXTENSION : API_EXTENSION ;
2022-12-07 12:11:28 +01:00
c . gdextension = p_extension ;
2021-06-04 14:33:48 -03:00
c . name = p_extension - > class_name ;
2022-10-15 12:01:04 +02:00
c . is_virtual = p_extension - > is_virtual ;
if ( ! p_extension - > is_abstract ) {
2022-10-17 00:22:10 +02:00
// Find the closest ancestor which is either non-abstract or native (or both).
ClassInfo * concrete_ancestor = parent ;
while ( concrete_ancestor - > creation_func = = nullptr & &
concrete_ancestor - > inherits_ptr ! = nullptr & &
concrete_ancestor - > gdextension ! = nullptr ) {
concrete_ancestor = concrete_ancestor - > inherits_ptr ;
}
2024-10-11 16:17:49 +02:00
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 ) ) ) ;
2022-10-17 00:22:10 +02:00
c . creation_func = concrete_ancestor - > creation_func ;
2022-10-15 12:01:04 +02:00
}
2021-06-04 14:33:48 -03:00
c . inherits = parent - > name ;
c . class_ptr = parent - > class_ptr ;
c . inherits_ptr = parent ;
2022-12-20 11:36:25 +08:00
c . exposed = p_extension - > is_exposed ;
if ( c . exposed ) {
// The parent classes should be exposed if it has an exposed child class.
while ( parent & & ! parent - > exposed ) {
parent - > exposed = true ;
parent = classes . getptr ( parent - > name ) ;
}
}
2023-08-04 20:34:14 -05:00
c . reloadable = p_extension - > reloadable ;
2024-02-21 17:56:50 -06:00
# ifdef TOOLS_ENABLED
c . is_runtime = p_extension - > is_runtime ;
# endif
2021-06-04 14:33:48 -03:00
2025-10-06 22:35:40 +02:00
c . gdtype = p_extension - > gdtype ;
2021-06-04 14:33:48 -03:00
classes [ p_extension - > class_name ] = c ;
}
2023-08-04 20:34:14 -05:00
void ClassDB : : unregister_extension_class ( const StringName & p_class , bool p_free_method_binds ) {
2022-10-05 11:46:00 -05:00
ClassInfo * c = classes . getptr ( p_class ) ;
2024-10-11 16:17:49 +02:00
ERR_FAIL_NULL_MSG ( c , vformat ( " Class '%s' does not exist. " , String ( p_class ) ) ) ;
2023-08-04 20:34:14 -05:00
if ( p_free_method_binds ) {
for ( KeyValue < StringName , MethodBind * > & F : c - > method_map ) {
memdelete ( F . value ) ;
}
2022-10-05 11:46:00 -05:00
}
2021-06-19 12:58:49 -03:00
classes . erase ( p_class ) ;
2024-01-02 14:10:54 -06:00
default_values_cached . erase ( p_class ) ;
default_values . erase ( p_class ) ;
# ifdef TOOLS_ENABLED
placeholder_extensions . erase ( p_class ) ;
# endif
2021-06-19 12:58:49 -03:00
}
2022-05-13 15:04:37 +02:00
HashMap < StringName , ClassDB : : NativeStruct > ClassDB : : native_structs ;
2022-03-14 15:52:03 +01:00
void ClassDB : : register_native_struct ( const StringName & p_name , const String & p_code , uint64_t p_current_size ) {
NativeStruct ns ;
ns . ccode = p_code ;
ns . struct_size = p_current_size ;
native_structs [ p_name ] = ns ;
}
void ClassDB : : get_native_struct_list ( List < StringName > * r_names ) {
for ( const KeyValue < StringName , NativeStruct > & E : native_structs ) {
r_names - > push_back ( E . key ) ;
}
}
String ClassDB : : get_native_struct_code ( const StringName & p_name ) {
ERR_FAIL_COND_V ( ! native_structs . has ( p_name ) , String ( ) ) ;
return native_structs [ p_name ] . ccode ;
}
uint64_t ClassDB : : get_native_struct_size ( const StringName & p_name ) {
ERR_FAIL_COND_V ( ! native_structs . has ( p_name ) , 0 ) ;
return native_structs [ p_name ] . struct_size ;
}
2025-04-02 14:48:26 +08:00
Object * ClassDB : : _instantiate_allow_unexposed ( const StringName & p_class ) {
return _instantiate_internal ( p_class , false , true , false ) ;
}
2019-06-01 16:42:22 +03:00
void ClassDB : : cleanup_defaults ( ) {
default_values . clear ( ) ;
default_values_cached . clear ( ) ;
}
2026-01-09 13:46:28 +01:00
LocalVector < GDType * * > ClassDB : : gdtype_autorelease_pool ;
2017-01-02 23:03:46 -03:00
void ClassDB : : cleanup ( ) {
2014-02-09 22:10:30 -03:00
//OBJTYPE_LOCK; hah not here
2016-03-09 00:00:52 +01:00
2022-05-08 10:09:19 +02:00
for ( KeyValue < StringName , ClassInfo > & E : classes ) {
ClassInfo & ti = E . value ;
2016-03-09 00:00:52 +01:00
2022-05-08 10:09:19 +02:00
for ( KeyValue < StringName , MethodBind * > & F : ti . method_map ) {
memdelete ( F . value ) ;
2014-02-09 22:10:30 -03:00
}
2023-04-25 20:53:07 +02:00
for ( KeyValue < StringName , LocalVector < MethodBind * > > & F : ti . method_map_compatibility ) {
for ( uint32_t i = 0 ; i < F . value . size ( ) ; i + + ) {
memdelete ( F . value [ i ] ) ;
}
}
2016-03-09 00:00:52 +01:00
}
2023-04-25 20:53:07 +02:00
2017-01-02 23:03:46 -03:00
classes . clear ( ) ;
2014-02-09 22:10:30 -03:00
resource_base_extensions . clear ( ) ;
2017-01-02 23:03:46 -03:00
compat_classes . clear ( ) ;
2022-03-14 15:52:03 +01:00
native_structs . clear ( ) ;
2026-01-09 13:46:28 +01:00
for ( GDType * * type : gdtype_autorelease_pool ) {
if ( ! type ) {
WARN_PRINT ( " GDType in autorelease pool was cleaned up before being auto-released. Ignoring. " ) ;
}
memdelete ( * type ) ;
* type = nullptr ;
}
gdtype_autorelease_pool . clear ( ) ;
2014-02-09 22:10:30 -03:00
}
2024-06-07 19:55:58 -04:00
// 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 ) ;
}
2014-02-09 22:10:30 -03:00
//
2025-02-05 09:33:05 +01:00
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 ;
}
}