2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* object.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2020-01-01 10:16:22 +00:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 01:10:30 +00:00
/* */
/* 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-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "object.h"
2017-01-16 07:04:19 +00:00
2018-09-11 16:13:45 +00:00
# include "core/class_db.h"
# include "core/core_string_names.h"
# include "core/message_queue.h"
2020-04-23 10:40:06 +00:00
# include "core/object_rc.h"
2018-09-11 16:13:45 +00:00
# include "core/os/os.h"
# include "core/print_string.h"
# include "core/resource.h"
# include "core/script_language.h"
# include "core/translation.h"
2014-04-05 15:39:30 +00:00
# ifdef DEBUG_ENABLED
struct _ObjectDebugLock {
Object * obj ;
_ObjectDebugLock ( Object * p_obj ) {
2017-03-05 15:44:50 +00:00
obj = p_obj ;
2014-04-05 15:39:30 +00:00
obj - > _lock_index . ref ( ) ;
}
~ _ObjectDebugLock ( ) {
obj - > _lock_index . unref ( ) ;
}
} ;
# define OBJ_DEBUG_LOCK _ObjectDebugLock _debug_lock(this);
# else
# define OBJ_DEBUG_LOCK
# endif
2016-08-25 20:45:20 +00:00
PropertyInfo : : operator Dictionary ( ) const {
Dictionary d ;
2017-03-05 15:44:50 +00:00
d [ " name " ] = name ;
2017-08-23 22:10:32 +00:00
d [ " class_name " ] = class_name ;
2017-03-05 15:44:50 +00:00
d [ " type " ] = type ;
d [ " hint " ] = hint ;
d [ " hint_string " ] = hint_string ;
d [ " usage " ] = usage ;
2016-08-25 20:45:20 +00:00
return d ;
}
2017-03-05 15:44:50 +00:00
PropertyInfo PropertyInfo : : from_dict ( const Dictionary & p_dict ) {
2016-08-25 20:45:20 +00:00
PropertyInfo pi ;
if ( p_dict . has ( " type " ) )
2017-03-05 15:44:50 +00:00
pi . type = Variant : : Type ( int ( p_dict [ " type " ] ) ) ;
2016-08-25 20:45:20 +00:00
if ( p_dict . has ( " name " ) )
2017-03-05 15:44:50 +00:00
pi . name = p_dict [ " name " ] ;
2016-08-25 20:45:20 +00:00
2017-08-23 22:10:32 +00:00
if ( p_dict . has ( " class_name " ) )
pi . class_name = p_dict [ " class_name " ] ;
2016-08-25 20:45:20 +00:00
if ( p_dict . has ( " hint " ) )
2017-03-05 15:44:50 +00:00
pi . hint = PropertyHint ( int ( p_dict [ " hint " ] ) ) ;
2016-08-25 20:45:20 +00:00
if ( p_dict . has ( " hint_string " ) )
2017-03-05 15:44:50 +00:00
pi . hint_string = p_dict [ " hint_string " ] ;
2016-08-25 20:45:20 +00:00
if ( p_dict . has ( " usage " ) )
2017-03-05 15:44:50 +00:00
pi . usage = p_dict [ " usage " ] ;
2016-08-25 20:45:20 +00:00
return pi ;
}
2017-03-05 15:44:50 +00:00
Array convert_property_list ( const List < PropertyInfo > * p_list ) {
2014-02-10 01:10:30 +00:00
Array va ;
2017-03-05 15:44:50 +00:00
for ( const List < PropertyInfo > : : Element * E = p_list - > front ( ) ; E ; E = E - > next ( ) ) {
2016-08-25 20:45:20 +00:00
va . push_back ( Dictionary ( E - > get ( ) ) ) ;
2014-02-10 01:10:30 +00:00
}
return va ;
}
2016-08-25 20:45:20 +00:00
MethodInfo : : operator Dictionary ( ) const {
Dictionary d ;
2017-03-05 15:44:50 +00:00
d [ " name " ] = name ;
d [ " args " ] = convert_property_list ( & arguments ) ;
2016-08-25 20:45:20 +00:00
Array da ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < default_arguments . size ( ) ; i + + )
2016-08-25 20:45:20 +00:00
da . push_back ( default_arguments [ i ] ) ;
2017-03-05 15:44:50 +00:00
d [ " default_args " ] = da ;
d [ " flags " ] = flags ;
d [ " id " ] = id ;
2016-08-25 20:45:20 +00:00
Dictionary r = return_val ;
2017-03-05 15:44:50 +00:00
d [ " return " ] = r ;
2016-08-25 20:45:20 +00:00
return d ;
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( ) :
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
MethodInfo MethodInfo : : from_dict ( const Dictionary & p_dict ) {
2016-08-25 20:45:20 +00:00
MethodInfo mi ;
if ( p_dict . has ( " name " ) )
2017-03-05 15:44:50 +00:00
mi . name = p_dict [ " name " ] ;
2016-08-25 20:45:20 +00:00
Array args ;
if ( p_dict . has ( " args " ) ) {
2017-03-05 15:44:50 +00:00
args = p_dict [ " args " ] ;
2016-08-25 20:45:20 +00:00
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < args . size ( ) ; i + + ) {
2016-08-25 20:45:20 +00:00
Dictionary d = args [ i ] ;
mi . arguments . push_back ( PropertyInfo : : from_dict ( d ) ) ;
}
Array defargs ;
if ( p_dict . has ( " default_args " ) ) {
2017-03-05 15:44:50 +00:00
defargs = p_dict [ " default_args " ] ;
2016-08-25 20:45:20 +00:00
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < defargs . size ( ) ; i + + ) {
2016-08-25 20:45:20 +00:00
mi . default_arguments . push_back ( defargs [ i ] ) ;
}
if ( p_dict . has ( " return " ) ) {
2017-03-05 15:44:50 +00:00
mi . return_val = PropertyInfo : : from_dict ( p_dict [ " return " ] ) ;
2016-08-25 20:45:20 +00:00
}
if ( p_dict . has ( " flags " ) )
2017-03-05 15:44:50 +00:00
mi . flags = p_dict [ " flags " ] ;
2016-08-25 20:45:20 +00:00
return mi ;
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const String & p_name ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const String & p_name , const PropertyInfo & p_param1 ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-03-05 15:44:50 +00:00
arguments . push_back ( p_param1 ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-03-05 15:44:50 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-03-05 15:44:50 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 , const PropertyInfo & p_param4 ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-03-05 15:44:50 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
arguments . push_back ( p_param4 ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 , const PropertyInfo & p_param4 , const PropertyInfo & p_param5 ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-03-05 15:44:50 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
arguments . push_back ( p_param4 ) ;
arguments . push_back ( p_param5 ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( Variant : : Type ret ) :
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-03-05 15:44:50 +00:00
return_val . type = ret ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( Variant : : Type ret , const String & p_name ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-03-05 15:44:50 +00:00
return_val . type = ret ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-03-05 15:44:50 +00:00
return_val . type = ret ;
2017-07-30 23:07:04 +00:00
arguments . push_back ( p_param1 ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-07-30 23:07:04 +00:00
return_val . type = ret ;
2017-03-05 15:44:50 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-07-30 23:07:04 +00:00
return_val . type = ret ;
2017-03-05 15:44:50 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 , const PropertyInfo & p_param4 ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-07-30 23:07:04 +00:00
return_val . type = ret ;
2017-03-05 15:44:50 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
arguments . push_back ( p_param4 ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 , const PropertyInfo & p_param4 , const PropertyInfo & p_param5 ) :
name ( p_name ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-07-30 23:07:04 +00:00
return_val . type = ret ;
2017-03-05 15:44:50 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
arguments . push_back ( p_param4 ) ;
arguments . push_back ( p_param5 ) ;
2014-02-10 01:10:30 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const PropertyInfo & p_ret , const String & p_name ) :
name ( p_name ) ,
return_val ( p_ret ) ,
2018-09-28 15:17:38 +00:00
flags ( METHOD_FLAG_NORMAL ) ,
2017-12-06 20:36:34 +00:00
id ( 0 ) {
2017-08-29 05:15:46 +00:00
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const PropertyInfo & p_ret , const String & p_name , const PropertyInfo & p_param1 ) :
name ( p_name ) ,
return_val ( p_ret ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-08-29 05:15:46 +00:00
arguments . push_back ( p_param1 ) ;
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const PropertyInfo & p_ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 ) :
name ( p_name ) ,
return_val ( p_ret ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-08-29 05:15:46 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const PropertyInfo & p_ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 ) :
name ( p_name ) ,
return_val ( p_ret ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-08-29 05:15:46 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const PropertyInfo & p_ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 , const PropertyInfo & p_param4 ) :
name ( p_name ) ,
return_val ( p_ret ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-08-29 05:15:46 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
arguments . push_back ( p_param4 ) ;
}
2017-12-06 20:36:34 +00:00
MethodInfo : : MethodInfo ( const PropertyInfo & p_ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 , const PropertyInfo & p_param4 , const PropertyInfo & p_param5 ) :
name ( p_name ) ,
return_val ( p_ret ) ,
flags ( METHOD_FLAG_NORMAL ) ,
id ( 0 ) {
2017-08-29 05:15:46 +00:00
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
arguments . push_back ( p_param4 ) ;
arguments . push_back ( p_param5 ) ;
}
2014-02-10 01:10:30 +00:00
Object : : Connection : : operator Variant ( ) const {
Dictionary d ;
2017-03-05 15:44:50 +00:00
d [ " source " ] = source ;
d [ " signal " ] = signal ;
d [ " target " ] = target ;
d [ " method " ] = method ;
d [ " flags " ] = flags ;
d [ " binds " ] = binds ;
2014-02-10 01:10:30 +00:00
return d ;
}
2017-03-05 15:44:50 +00:00
bool Object : : Connection : : operator < ( const Connection & p_conn ) const {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( source = = p_conn . source ) {
2014-02-10 01:10:30 +00:00
if ( signal = = p_conn . signal ) {
if ( target = = p_conn . target ) {
return method < p_conn . method ;
} else {
return target < p_conn . target ;
}
} else
return signal < p_conn . signal ;
} else {
2017-03-05 15:44:50 +00:00
return source < p_conn . source ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
Object : : Connection : : Connection ( const Variant & p_variant ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Dictionary d = p_variant ;
2014-02-10 01:10:30 +00:00
if ( d . has ( " source " ) )
2017-03-05 15:44:50 +00:00
source = d [ " source " ] ;
2014-02-10 01:10:30 +00:00
if ( d . has ( " signal " ) )
2017-03-05 15:44:50 +00:00
signal = d [ " signal " ] ;
2014-02-10 01:10:30 +00:00
if ( d . has ( " target " ) )
2017-03-05 15:44:50 +00:00
target = d [ " target " ] ;
2014-02-10 01:10:30 +00:00
if ( d . has ( " method " ) )
2017-03-05 15:44:50 +00:00
method = d [ " method " ] ;
2014-02-10 01:10:30 +00:00
if ( d . has ( " flags " ) )
2017-03-05 15:44:50 +00:00
flags = d [ " flags " ] ;
2014-02-10 01:10:30 +00:00
if ( d . has ( " binds " ) )
2017-03-05 15:44:50 +00:00
binds = d [ " binds " ] ;
2014-02-10 01:10:30 +00:00
}
bool Object : : _predelete ( ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
_predelete_ok = 1 ;
notification ( NOTIFICATION_PREDELETE , true ) ;
2015-06-29 03:29:49 +00:00
if ( _predelete_ok ) {
2017-03-05 15:44:50 +00:00
_class_ptr = NULL ; //must restore so destructors can access class ptr correctly
2015-06-29 03:29:49 +00:00
}
2014-02-10 01:10:30 +00:00
return _predelete_ok ;
}
void Object : : _postinitialize ( ) {
2017-03-05 15:44:50 +00:00
_class_ptr = _get_class_namev ( ) ;
2017-01-03 02:03:46 +00:00
_initialize_classv ( ) ;
2014-02-10 01:10:30 +00:00
notification ( NOTIFICATION_POSTINITIALIZE ) ;
}
void Object : : get_valid_parents_static ( List < String > * p_parents ) {
}
void Object : : _get_valid_parents_static ( List < String > * p_parents ) {
}
2017-03-05 15:44:50 +00:00
void Object : : set ( const StringName & p_name , const Variant & p_value , bool * r_valid ) {
2014-02-10 01:10:30 +00:00
# ifdef TOOLS_ENABLED
2017-03-05 15:44:50 +00:00
_edited = true ;
2014-02-10 01:10:30 +00:00
# endif
2015-12-05 17:18:22 +00:00
2014-02-10 01:10:30 +00:00
if ( script_instance ) {
2017-03-05 15:44:50 +00:00
if ( script_instance - > set ( p_name , p_value ) ) {
2014-02-10 01:10:30 +00:00
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = true ;
2014-02-10 01:10:30 +00:00
return ;
}
}
//try built-in setgetter
{
2017-03-05 15:44:50 +00:00
if ( ClassDB : : set_property ( this , p_name , p_value , r_valid ) ) {
2017-01-14 11:26:56 +00:00
/*
if ( r_valid )
* r_valid = true ;
*/
2014-02-10 01:10:30 +00:00
return ;
}
}
2017-03-05 15:44:50 +00:00
if ( p_name = = CoreStringNames : : get_singleton ( ) - > _script ) {
2014-02-10 01:10:30 +00:00
set_script ( p_value ) ;
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = true ;
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
} else if ( p_name = = CoreStringNames : : get_singleton ( ) - > _meta ) {
2014-02-10 01:10:30 +00:00
//set_meta(p_name,p_value);
2019-09-28 15:15:23 +00:00
metadata = p_value . duplicate ( ) ;
2014-02-10 01:10:30 +00:00
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = true ;
2014-02-10 01:10:30 +00:00
return ;
2018-07-29 20:40:09 +00:00
}
//something inside the object... :|
bool success = _setv ( p_name , p_value ) ;
if ( success ) {
if ( r_valid )
* r_valid = true ;
return ;
}
{
bool valid ;
setvar ( p_name , p_value , & valid ) ;
if ( valid ) {
if ( r_valid )
* r_valid = true ;
return ;
}
}
# ifdef TOOLS_ENABLED
if ( script_instance ) {
bool valid ;
script_instance - > property_set_fallback ( p_name , p_value , & valid ) ;
if ( valid ) {
2014-02-10 01:10:30 +00:00
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = true ;
2014-02-10 01:10:30 +00:00
return ;
}
}
2018-07-29 20:40:09 +00:00
# endif
if ( r_valid )
* r_valid = false ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Object : : get ( const StringName & p_name , bool * r_valid ) const {
2014-02-10 01:10:30 +00:00
Variant ret ;
if ( script_instance ) {
2017-03-05 15:44:50 +00:00
if ( script_instance - > get ( p_name , ret ) ) {
2014-02-10 01:10:30 +00:00
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = true ;
2014-02-10 01:10:30 +00:00
return ret ;
}
}
//try built-in setgetter
{
2017-03-05 15:44:50 +00:00
if ( ClassDB : : get_property ( const_cast < Object * > ( this ) , p_name , ret ) ) {
2014-02-10 01:10:30 +00:00
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = true ;
2014-02-10 01:10:30 +00:00
return ret ;
}
}
2017-03-05 15:44:50 +00:00
if ( p_name = = CoreStringNames : : get_singleton ( ) - > _script ) {
2014-02-10 01:10:30 +00:00
ret = get_script ( ) ;
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = true ;
2014-02-10 01:10:30 +00:00
return ret ;
2017-03-05 15:44:50 +00:00
} else if ( p_name = = CoreStringNames : : get_singleton ( ) - > _meta ) {
2014-02-10 01:10:30 +00:00
ret = metadata ;
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = true ;
2014-02-10 01:10:30 +00:00
return ret ;
2018-10-29 19:36:31 +00:00
2014-02-10 01:10:30 +00:00
} else {
//something inside the object... :|
2017-03-05 15:44:50 +00:00
bool success = _getv ( p_name , ret ) ;
2014-02-10 01:10:30 +00:00
if ( success ) {
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = true ;
2014-02-10 01:10:30 +00:00
return ret ;
}
2018-07-29 20:40:09 +00:00
2014-02-10 01:10:30 +00:00
//if nothing else, use getvar
2018-07-29 20:40:09 +00:00
{
bool valid ;
ret = getvar ( p_name , & valid ) ;
if ( valid ) {
if ( r_valid )
* r_valid = true ;
return ret ;
}
}
# ifdef TOOLS_ENABLED
if ( script_instance ) {
bool valid ;
ret = script_instance - > property_get_fallback ( p_name , & valid ) ;
if ( valid ) {
if ( r_valid )
* r_valid = true ;
return ret ;
}
}
# endif
if ( r_valid )
* r_valid = false ;
return Variant ( ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-05-30 20:20:15 +00:00
void Object : : set_indexed ( const Vector < StringName > & p_names , const Variant & p_value , bool * r_valid ) {
if ( p_names . empty ( ) ) {
if ( r_valid )
* r_valid = false ;
return ;
}
if ( p_names . size ( ) = = 1 ) {
set ( p_names [ 0 ] , p_value , r_valid ) ;
return ;
}
bool valid = false ;
if ( ! r_valid ) r_valid = & valid ;
List < Variant > value_stack ;
value_stack . push_back ( get ( p_names [ 0 ] , r_valid ) ) ;
if ( ! * r_valid ) {
value_stack . clear ( ) ;
return ;
}
for ( int i = 1 ; i < p_names . size ( ) - 1 ; i + + ) {
value_stack . push_back ( value_stack . back ( ) - > get ( ) . get_named ( p_names [ i ] , r_valid ) ) ;
if ( ! * r_valid ) {
value_stack . clear ( ) ;
return ;
}
}
value_stack . push_back ( p_value ) ; // p_names[p_names.size() - 1]
for ( int i = p_names . size ( ) - 1 ; i > 0 ; i - - ) {
value_stack . back ( ) - > prev ( ) - > get ( ) . set_named ( p_names [ i ] , value_stack . back ( ) - > get ( ) , r_valid ) ;
value_stack . pop_back ( ) ;
if ( ! * r_valid ) {
value_stack . clear ( ) ;
return ;
}
}
set ( p_names [ 0 ] , value_stack . back ( ) - > get ( ) , r_valid ) ;
value_stack . pop_back ( ) ;
ERR_FAIL_COND ( ! value_stack . empty ( ) ) ;
}
Variant Object : : get_indexed ( const Vector < StringName > & p_names , bool * r_valid ) const {
if ( p_names . empty ( ) ) {
if ( r_valid )
* r_valid = false ;
return Variant ( ) ;
}
bool valid = false ;
2019-05-16 21:22:52 +00:00
Variant current_value = get ( p_names [ 0 ] , & valid ) ;
2017-05-30 20:20:15 +00:00
for ( int i = 1 ; i < p_names . size ( ) ; i + + ) {
current_value = current_value . get_named ( p_names [ i ] , & valid ) ;
2019-05-16 21:22:52 +00:00
if ( ! valid )
break ;
2017-05-30 20:20:15 +00:00
}
if ( r_valid )
2019-05-16 21:22:52 +00:00
* r_valid = valid ;
2017-05-30 20:20:15 +00:00
return current_value ;
}
2017-03-05 15:44:50 +00:00
void Object : : get_property_list ( List < PropertyInfo > * p_list , bool p_reversed ) const {
2014-02-10 01:10:30 +00:00
if ( script_instance & & p_reversed ) {
2017-03-05 15:44:50 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : NIL , " Script Variables " , PROPERTY_HINT_NONE , String ( ) , PROPERTY_USAGE_CATEGORY ) ) ;
2014-02-10 01:10:30 +00:00
script_instance - > get_property_list ( p_list ) ;
}
2017-03-05 15:44:50 +00:00
_get_property_listv ( p_list , p_reversed ) ;
2016-03-08 23:00:52 +00:00
2018-07-18 22:37:17 +00:00
if ( ! is_class ( " Script " ) ) { // can still be set, but this is for userfriendlyness
2018-11-08 14:30:02 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , " script " , PROPERTY_HINT_RESOURCE_TYPE , " Script " , PROPERTY_USAGE_DEFAULT ) ) ;
}
2019-07-22 10:03:57 +00:00
if ( ! metadata . empty ( ) ) {
p_list - > push_back ( PropertyInfo ( Variant : : DICTIONARY , " __meta__ " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) ) ;
}
2014-02-10 01:10:30 +00:00
if ( script_instance & & ! p_reversed ) {
2017-03-05 15:44:50 +00:00
p_list - > push_back ( PropertyInfo ( Variant : : NIL , " Script Variables " , PROPERTY_HINT_NONE , String ( ) , PROPERTY_USAGE_CATEGORY ) ) ;
2014-02-10 01:10:30 +00:00
script_instance - > get_property_list ( p_list ) ;
2016-03-08 23:00:52 +00:00
}
2014-02-10 01:10:30 +00:00
}
2016-05-15 02:48:23 +00:00
2017-03-05 15:44:50 +00:00
void Object : : _validate_property ( PropertyInfo & property ) const {
2016-05-15 02:48:23 +00:00
}
2014-02-10 01:10:30 +00:00
void Object : : get_method_list ( List < MethodInfo > * p_list ) const {
2017-03-05 15:44:50 +00:00
ClassDB : : get_method_list ( get_class_name ( ) , p_list ) ;
2014-02-10 01:10:30 +00:00
if ( script_instance ) {
script_instance - > get_method_list ( p_list ) ;
2016-03-08 23:00:52 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Object : : _call_bind ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( p_argcount < 1 ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 0 ;
2014-02-10 01:10:30 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : STRING ;
2014-02-10 01:10:30 +00:00
return Variant ( ) ;
}
StringName method = * p_args [ 0 ] ;
2017-03-05 15:44:50 +00:00
return call ( method , & p_args [ 1 ] , p_argcount - 1 , r_error ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Object : : _call_deferred_bind ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( p_argcount < 1 ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 0 ;
2014-02-10 01:10:30 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : STRING ;
2014-02-10 01:10:30 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
r_error . error = Variant : : CallError : : CALL_OK ;
2014-02-10 01:10:30 +00:00
2016-01-04 12:35:21 +00:00
StringName method = * p_args [ 0 ] ;
2014-02-10 01:10:30 +00:00
2020-07-18 07:11:07 +00:00
MessageQueue : : get_singleton ( ) - > push_call ( get_instance_id ( ) , method , & p_args [ 1 ] , p_argcount - 1 , true ) ;
2014-02-10 01:10:30 +00:00
return Variant ( ) ;
}
# ifdef DEBUG_ENABLED
2019-02-18 19:28:40 +00:00
static void _test_call_error ( const StringName & p_func , const Variant : : CallError & error ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
switch ( error . error ) {
2014-02-10 01:10:30 +00:00
case Variant : : CallError : : CALL_OK :
case Variant : : CallError : : CALL_ERROR_INVALID_METHOD :
2019-02-18 19:28:40 +00:00
break ;
2014-02-10 01:10:30 +00:00
case Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT : {
2019-08-15 02:57:49 +00:00
ERR_FAIL_MSG ( " Error calling function: " + String ( p_func ) + " - Invalid type for argument " + itos ( error . argument ) + " , expected " + Variant : : get_type_name ( error . expected ) + " . " ) ;
2019-02-18 19:28:40 +00:00
break ;
}
2014-02-10 01:10:30 +00:00
case Variant : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS : {
2019-08-15 02:57:49 +00:00
ERR_FAIL_MSG ( " Error calling function: " + String ( p_func ) + " - Too many arguments, expected " + itos ( error . argument ) + " . " ) ;
2019-02-18 19:28:40 +00:00
break ;
}
2014-02-10 01:10:30 +00:00
case Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS : {
2019-08-15 02:57:49 +00:00
ERR_FAIL_MSG ( " Error calling function: " + String ( p_func ) + " - Too few arguments, expected " + itos ( error . argument ) + " . " ) ;
2019-02-18 19:28:40 +00:00
break ;
}
case Variant : : CallError : : CALL_ERROR_INSTANCE_IS_NULL :
break ;
2014-02-10 01:10:30 +00:00
}
}
# else
2019-02-18 19:28:40 +00:00
# define _test_call_error(m_str, m_err)
2014-02-10 01:10:30 +00:00
# endif
2017-03-05 15:44:50 +00:00
void Object : : call_multilevel ( const StringName & p_method , const Variant * * p_args , int p_argcount ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( p_method = = CoreStringNames : : get_singleton ( ) - > _free ) {
2014-02-10 01:10:30 +00:00
# ifdef DEBUG_ENABLED
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_MSG ( Object : : cast_to < Reference > ( this ) , " Can't 'free' a reference. " ) ;
2014-04-05 15:39:30 +00:00
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_MSG ( _lock_index . get ( ) > 1 , " Object is locked and can't be freed. " ) ;
2014-02-10 01:10:30 +00:00
# endif
2014-04-05 15:39:30 +00:00
2014-02-10 01:10:30 +00:00
//must be here, must be before everything,
memdelete ( this ) ;
return ;
}
//Variant ret;
2014-04-05 15:39:30 +00:00
OBJ_DEBUG_LOCK
2014-02-10 01:10:30 +00:00
Variant : : CallError error ;
if ( script_instance ) {
2017-03-05 15:44:50 +00:00
script_instance - > call_multilevel ( p_method , p_args , p_argcount ) ;
2014-02-10 01:10:30 +00:00
//_test_call_error(p_method,error);
}
2017-03-05 15:44:50 +00:00
MethodBind * method = ClassDB : : get_method ( get_class_name ( ) , p_method ) ;
2014-02-10 01:10:30 +00:00
if ( method ) {
2017-03-05 15:44:50 +00:00
method - > call ( this , p_args , p_argcount , error ) ;
_test_call_error ( p_method , error ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
void Object : : call_multilevel_reversed ( const StringName & p_method , const Variant * * p_args , int p_argcount ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
MethodBind * method = ClassDB : : get_method ( get_class_name ( ) , p_method ) ;
2014-02-10 01:10:30 +00:00
Variant : : CallError error ;
2014-04-05 15:39:30 +00:00
OBJ_DEBUG_LOCK
2014-02-10 01:10:30 +00:00
if ( method ) {
2017-03-05 15:44:50 +00:00
method - > call ( this , p_args , p_argcount , error ) ;
_test_call_error ( p_method , error ) ;
2014-02-10 01:10:30 +00:00
}
//Variant ret;
if ( script_instance ) {
2017-03-05 15:44:50 +00:00
script_instance - > call_multilevel_reversed ( p_method , p_args , p_argcount ) ;
2014-02-10 01:10:30 +00:00
//_test_call_error(p_method,error);
}
}
2017-03-05 15:44:50 +00:00
bool Object : : has_method ( const StringName & p_method ) const {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( p_method = = CoreStringNames : : get_singleton ( ) - > _free ) {
2014-02-10 01:10:30 +00:00
return true ;
}
if ( script_instance & & script_instance - > has_method ( p_method ) ) {
return true ;
}
2017-03-05 15:44:50 +00:00
MethodBind * method = ClassDB : : get_method ( get_class_name ( ) , p_method ) ;
2014-02-10 01:10:30 +00:00
2019-06-26 13:08:25 +00:00
return method ! = NULL ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Object : : getvar ( const Variant & p_key , bool * r_valid ) const {
2014-02-10 01:10:30 +00:00
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = false ;
2014-02-10 01:10:30 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
void Object : : setvar ( const Variant & p_key , const Variant & p_value , bool * r_valid ) {
2014-02-10 01:10:30 +00:00
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = false ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Object : : callv ( const StringName & p_method , const Array & p_args ) {
2019-03-05 10:24:21 +00:00
const Variant * * argptrs = NULL ;
2014-02-10 01:10:30 +00:00
2019-03-05 10:24:21 +00:00
if ( p_args . size ( ) > 0 ) {
argptrs = ( const Variant * * ) alloca ( sizeof ( Variant * ) * p_args . size ( ) ) ;
for ( int i = 0 ; i < p_args . size ( ) ; i + + ) {
argptrs [ i ] = & p_args [ i ] ;
}
2014-02-10 01:10:30 +00:00
}
Variant : : CallError ce ;
2019-03-05 10:24:21 +00:00
Variant ret = call ( p_method , argptrs , p_args . size ( ) , ce ) ;
if ( ce . error ! = Variant : : CallError : : CALL_OK ) {
2019-08-15 02:57:49 +00:00
ERR_FAIL_V_MSG ( Variant ( ) , " Error calling method from 'callv': " + Variant : : get_call_error_text ( this , p_method , argptrs , p_args . size ( ) , ce ) + " . " ) ;
2019-03-05 10:24:21 +00:00
}
return ret ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Object : : call ( const StringName & p_name , VARIANT_ARG_DECLARE ) {
2014-02-10 01:10:30 +00:00
VARIANT_ARGPTRS ;
2017-03-05 15:44:50 +00:00
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
2014-02-10 01:10:30 +00:00
break ;
argc + + ;
}
Variant : : CallError error ;
2017-03-05 15:44:50 +00:00
Variant ret = call ( p_name , argptr , argc , error ) ;
2014-02-10 01:10:30 +00:00
return ret ;
}
2017-03-05 15:44:50 +00:00
void Object : : call_multilevel ( const StringName & p_name , VARIANT_ARG_DECLARE ) {
2014-02-10 01:10:30 +00:00
VARIANT_ARGPTRS ;
2017-03-05 15:44:50 +00:00
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
2014-02-10 01:10:30 +00:00
break ;
argc + + ;
}
//Variant::CallError error;
2017-03-05 15:44:50 +00:00
call_multilevel ( p_name , argptr , argc ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Object : : call ( const StringName & p_method , const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
r_error . error = Variant : : CallError : : CALL_OK ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( p_method = = CoreStringNames : : get_singleton ( ) - > _free ) {
//free must be here, before anything, always ready
2014-02-10 01:10:30 +00:00
# ifdef DEBUG_ENABLED
2017-03-05 15:44:50 +00:00
if ( p_argcount ! = 0 ) {
r_error . argument = 0 ;
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS ;
2014-02-10 01:10:30 +00:00
return Variant ( ) ;
}
2017-08-24 20:58:51 +00:00
if ( Object : : cast_to < Reference > ( this ) ) {
2017-03-05 15:44:50 +00:00
r_error . argument = 0 ;
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_METHOD ;
2019-08-15 02:57:49 +00:00
ERR_FAIL_V_MSG ( Variant ( ) , " Can't 'free' a reference. " ) ;
2014-02-10 01:10:30 +00:00
}
2014-04-05 15:39:30 +00:00
2017-03-05 15:44:50 +00:00
if ( _lock_index . get ( ) > 1 ) {
r_error . argument = 0 ;
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_METHOD ;
2019-08-15 02:57:49 +00:00
ERR_FAIL_V_MSG ( Variant ( ) , " Object is locked and can't be freed. " ) ;
2014-04-05 15:39:30 +00:00
}
2014-02-10 01:10:30 +00:00
# endif
//must be here, must be before everything,
memdelete ( this ) ;
2017-03-05 15:44:50 +00:00
r_error . error = Variant : : CallError : : CALL_OK ;
2014-02-10 01:10:30 +00:00
return Variant ( ) ;
}
Variant ret ;
2014-04-05 15:39:30 +00:00
OBJ_DEBUG_LOCK
2014-02-10 01:10:30 +00:00
if ( script_instance ) {
2017-03-05 15:44:50 +00:00
ret = script_instance - > call ( p_method , p_args , p_argcount , r_error ) ;
2014-02-10 01:10:30 +00:00
//force jumptable
2017-03-05 15:44:50 +00:00
switch ( r_error . error ) {
2014-02-10 01:10:30 +00:00
case Variant : : CallError : : CALL_OK :
return ret ;
case Variant : : CallError : : CALL_ERROR_INVALID_METHOD :
break ;
case Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT :
case Variant : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS :
case Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS :
return ret ;
2017-03-05 15:44:50 +00:00
case Variant : : CallError : : CALL_ERROR_INSTANCE_IS_NULL : {
}
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
MethodBind * method = ClassDB : : get_method ( get_class_name ( ) , p_method ) ;
2014-02-10 01:10:30 +00:00
if ( method ) {
2017-03-05 15:44:50 +00:00
ret = method - > call ( this , p_args , p_argcount , r_error ) ;
2014-02-10 01:10:30 +00:00
} else {
2017-03-05 15:44:50 +00:00
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_METHOD ;
2014-02-10 01:10:30 +00:00
}
return ret ;
}
2017-03-05 15:44:50 +00:00
void Object : : notification ( int p_notification , bool p_reversed ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
_notificationv ( p_notification , p_reversed ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( script_instance ) {
script_instance - > notification ( p_notification ) ;
}
}
2019-04-10 05:07:40 +00:00
String Object : : to_string ( ) {
if ( script_instance ) {
bool valid ;
String ret = script_instance - > to_string ( & valid ) ;
if ( valid )
return ret ;
}
return " [ " + get_class ( ) + " : " + itos ( get_instance_id ( ) ) + " ] " ;
}
2017-03-05 15:44:50 +00:00
void Object : : _changed_callback ( Object * p_changed , const char * p_prop ) {
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Object : : add_change_receptor ( Object * p_receptor ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
change_receptors . insert ( p_receptor ) ;
}
2017-03-05 15:44:50 +00:00
void Object : : remove_change_receptor ( Object * p_receptor ) {
2014-02-10 01:10:30 +00:00
change_receptors . erase ( p_receptor ) ;
}
void Object : : property_list_changed_notify ( ) {
_change_notify ( ) ;
}
void Object : : cancel_delete ( ) {
2017-03-05 15:44:50 +00:00
_predelete_ok = true ;
2014-02-10 01:10:30 +00:00
}
2020-04-23 10:40:06 +00:00
# ifdef DEBUG_ENABLED
ObjectRC * Object : : _use_rc ( ) {
// The RC object is lazily created the first time it's requested;
// that way, there's no need to allocate and release it at all if this Object
// is not being referred by any Variant at all.
// Although when dealing with Objects from multiple threads some locking
// mechanism should be used, this at least makes safe the case of first
// assignment.
ObjectRC * rc = nullptr ;
ObjectRC * const creating = reinterpret_cast < ObjectRC * > ( 1 ) ;
if ( unlikely ( _rc . compare_exchange_strong ( rc , creating , std : : memory_order_acq_rel ) ) ) {
// Not created yet
rc = memnew ( ObjectRC ( this ) ) ;
_rc . store ( rc , std : : memory_order_release ) ;
return rc ;
}
// Spin-wait until we know it's created (or just return if it's already created)
for ( ; ; ) {
if ( likely ( rc ! = creating ) ) {
rc - > increment ( ) ;
return rc ;
}
rc = _rc . load ( std : : memory_order_acquire ) ;
}
}
# endif
2017-07-22 19:57:56 +00:00
void Object : : set_script_and_instance ( const RefPtr & p_script , ScriptInstance * p_instance ) {
//this function is not meant to be used in any of these ways
ERR_FAIL_COND ( p_script . is_null ( ) ) ;
ERR_FAIL_COND ( ! p_instance ) ;
ERR_FAIL_COND ( script_instance ! = NULL | | ! script . is_null ( ) ) ;
script = p_script ;
script_instance = p_instance ;
}
2017-03-05 15:44:50 +00:00
void Object : : set_script ( const RefPtr & p_script ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( script = = p_script )
2014-02-10 01:10:30 +00:00
return ;
if ( script_instance ) {
memdelete ( script_instance ) ;
2017-03-05 15:44:50 +00:00
script_instance = NULL ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
script = p_script ;
2014-02-10 01:10:30 +00:00
Ref < Script > s ( script ) ;
2018-07-29 20:40:09 +00:00
if ( ! s . is_null ( ) ) {
if ( s - > can_instance ( ) ) {
OBJ_DEBUG_LOCK
script_instance = s - > instance_create ( this ) ;
} else if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
OBJ_DEBUG_LOCK
script_instance = s - > placeholder_instance_create ( this ) ;
}
2014-02-10 01:10:30 +00:00
}
2019-02-24 13:50:43 +00:00
_change_notify ( ) ; //scripts may add variables, so refresh is desired
2014-02-10 01:10:30 +00:00
emit_signal ( CoreStringNames : : get_singleton ( ) - > script_changed ) ;
}
void Object : : set_script_instance ( ScriptInstance * p_instance ) {
2017-03-05 15:44:50 +00:00
if ( script_instance = = p_instance )
2014-02-10 01:10:30 +00:00
return ;
if ( script_instance )
memdelete ( script_instance ) ;
2017-03-05 15:44:50 +00:00
script_instance = p_instance ;
2014-02-10 01:10:30 +00:00
2015-11-28 15:47:09 +00:00
if ( p_instance )
2017-03-05 15:44:50 +00:00
script = p_instance - > get_script ( ) . get_ref_ptr ( ) ;
2015-11-28 15:47:09 +00:00
else
2017-03-05 15:44:50 +00:00
script = RefPtr ( ) ;
2014-02-10 01:10:30 +00:00
}
RefPtr Object : : get_script ( ) const {
return script ;
}
2017-03-05 15:44:50 +00:00
bool Object : : has_meta ( const String & p_name ) const {
2014-02-10 01:10:30 +00:00
return metadata . has ( p_name ) ;
}
2017-03-05 15:44:50 +00:00
void Object : : set_meta ( const String & p_name , const Variant & p_value ) {
2014-02-10 01:10:30 +00:00
if ( p_value . get_type ( ) = = Variant : : NIL ) {
metadata . erase ( p_name ) ;
return ;
} ;
2017-03-05 15:44:50 +00:00
metadata [ p_name ] = p_value ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Object : : get_meta ( const String & p_name ) const {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! metadata . has ( p_name ) , Variant ( ) ) ;
2014-02-10 01:10:30 +00:00
return metadata [ p_name ] ;
}
2019-04-26 17:23:50 +00:00
void Object : : remove_meta ( const String & p_name ) {
metadata . erase ( p_name ) ;
}
2014-02-10 01:10:30 +00:00
Array Object : : _get_property_list_bind ( ) const {
List < PropertyInfo > lpi ;
get_property_list ( & lpi ) ;
return convert_property_list ( & lpi ) ;
}
2015-05-25 04:46:45 +00:00
Array Object : : _get_method_list_bind ( ) const {
List < MethodInfo > ml ;
get_method_list ( & ml ) ;
Array ret ;
2017-03-05 15:44:50 +00:00
for ( List < MethodInfo > : : Element * E = ml . front ( ) ; E ; E = E - > next ( ) ) {
2015-05-25 04:46:45 +00:00
2016-08-25 20:45:20 +00:00
Dictionary d = E - > get ( ) ;
2015-05-25 04:46:45 +00:00
//va.push_back(d);
ret . push_back ( d ) ;
}
return ret ;
}
2017-01-07 21:25:37 +00:00
PoolVector < String > Object : : _get_meta_list_bind ( ) const {
2014-02-10 01:10:30 +00:00
2017-01-07 21:25:37 +00:00
PoolVector < String > _metaret ;
2014-02-10 01:10:30 +00:00
List < Variant > keys ;
metadata . get_key_list ( & keys ) ;
2017-03-05 15:44:50 +00:00
for ( List < Variant > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
_metaret . push_back ( E - > get ( ) ) ;
}
return _metaret ;
}
void Object : : get_meta_list ( List < String > * p_list ) const {
List < Variant > keys ;
metadata . get_key_list ( & keys ) ;
2017-03-05 15:44:50 +00:00
for ( List < Variant > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
p_list - > push_back ( E - > get ( ) ) ;
}
}
2017-03-05 15:44:50 +00:00
void Object : : add_user_signal ( const MethodInfo & p_signal ) {
2014-02-10 01:10:30 +00:00
2019-09-25 08:28:50 +00:00
ERR_FAIL_COND_MSG ( p_signal . name = = " " , " Signal name cannot be empty. " ) ;
ERR_FAIL_COND_MSG ( ClassDB : : has_signal ( get_class_name ( ) , p_signal . name ) , " User signal's name conflicts with a built-in signal of ' " + get_class_name ( ) + " '. " ) ;
ERR_FAIL_COND_MSG ( signal_map . has ( p_signal . name ) , " Trying to add already existing signal ' " + p_signal . name + " '. " ) ;
2014-02-10 01:10:30 +00:00
Signal s ;
2017-03-05 15:44:50 +00:00
s . user = p_signal ;
signal_map [ p_signal . name ] = s ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
bool Object : : _has_user_signal ( const StringName & p_name ) const {
2015-03-03 17:39:13 +00:00
if ( ! signal_map . has ( p_name ) )
return false ;
2017-03-05 15:44:50 +00:00
return signal_map [ p_name ] . user . name . length ( ) > 0 ;
2015-03-03 17:39:13 +00:00
}
2014-02-10 01:10:30 +00:00
struct _ObjectSignalDisconnectData {
StringName signal ;
Object * target ;
StringName method ;
} ;
2017-03-05 15:44:50 +00:00
Variant Object : : _emit_signal ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( p_argcount < 1 , Variant ( ) ) ;
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : STRING ;
ERR_FAIL_COND_V ( p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING , Variant ( ) ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
r_error . error = Variant : : CallError : : CALL_OK ;
2014-02-10 01:10:30 +00:00
StringName signal = * p_args [ 0 ] ;
2017-03-05 15:44:50 +00:00
const Variant * * args = NULL ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
int argc = p_argcount - 1 ;
2016-01-04 12:35:21 +00:00
if ( argc ) {
2017-03-05 15:44:50 +00:00
args = & p_args [ 1 ] ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
emit_signal ( signal , args , argc ) ;
2016-01-04 12:35:21 +00:00
2014-02-10 01:10:30 +00:00
return Variant ( ) ;
2016-01-04 12:35:21 +00:00
}
2014-02-10 01:10:30 +00:00
2017-08-05 22:48:29 +00:00
Error Object : : emit_signal ( const StringName & p_name , const Variant * * p_args , int p_argcount ) {
2014-02-10 01:10:30 +00:00
if ( _block_signals )
2017-09-22 03:58:29 +00:00
return ERR_CANT_ACQUIRE_RESOURCE ; //no emit, signals blocked
2014-02-10 01:10:30 +00:00
Signal * s = signal_map . getptr ( p_name ) ;
if ( ! s ) {
2016-09-25 17:21:21 +00:00
# ifdef DEBUG_ENABLED
2017-03-05 15:44:50 +00:00
bool signal_is_valid = ClassDB : : has_signal ( get_class_name ( ) , p_name ) ;
2016-09-25 17:21:21 +00:00
//check in script
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_V_MSG ( ! signal_is_valid & & ! script . is_null ( ) & & ! Ref < Script > ( script ) - > has_script_signal ( p_name ) , ERR_UNAVAILABLE , " Can't emit non-existing signal " + String ( " \" " ) + p_name + " \" . " ) ;
2016-09-25 17:21:21 +00:00
# endif
//not connected? just return
2017-08-05 22:48:29 +00:00
return ERR_UNAVAILABLE ;
2014-02-10 01:10:30 +00:00
}
List < _ObjectSignalDisconnectData > disconnect_data ;
//copy on write will ensure that disconnecting the signal or even deleting the object will not affect the signal calling.
//this happens automatically and will not change the performance of calling.
//awesome, isn't it?
2017-03-05 15:44:50 +00:00
VMap < Signal : : Target , Signal : : Slot > slot_map = s - > slot_map ;
2014-02-10 01:10:30 +00:00
int ssize = slot_map . size ( ) ;
2014-04-05 15:39:30 +00:00
OBJ_DEBUG_LOCK
2017-03-05 15:44:50 +00:00
Vector < const Variant * > bind_mem ;
2016-01-04 12:35:21 +00:00
2017-08-05 22:48:29 +00:00
Error err = OK ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < ssize ; i + + ) {
2014-02-10 01:10:30 +00:00
const Connection & c = slot_map . getv ( i ) . conn ;
2020-01-13 21:11:03 +00:00
Object * target = ObjectDB : : get_instance ( slot_map . getk ( i ) . _id ) ;
if ( ! target ) {
// Target might have been deleted during signal callback, this is expected and OK.
continue ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
const Variant * * args = p_args ;
int argc = p_argcount ;
2014-02-10 01:10:30 +00:00
2016-01-04 12:35:21 +00:00
if ( c . binds . size ( ) ) {
//handle binds
2017-03-05 15:44:50 +00:00
bind_mem . resize ( p_argcount + c . binds . size ( ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int j = 0 ; j < p_argcount ; j + + ) {
2018-07-25 01:11:03 +00:00
bind_mem . write [ j ] = p_args [ j ] ;
2016-01-04 12:35:21 +00:00
}
2017-03-05 15:44:50 +00:00
for ( int j = 0 ; j < c . binds . size ( ) ; j + + ) {
2018-07-25 01:11:03 +00:00
bind_mem . write [ p_argcount + j ] = & c . binds [ j ] ;
2014-02-10 01:10:30 +00:00
}
2016-01-04 12:35:21 +00:00
2017-11-25 03:07:54 +00:00
args = ( const Variant * * ) bind_mem . ptr ( ) ;
2017-03-05 15:44:50 +00:00
argc = bind_mem . size ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
if ( c . flags & CONNECT_DEFERRED ) {
2017-08-07 10:17:31 +00:00
MessageQueue : : get_singleton ( ) - > push_call ( target - > get_instance_id ( ) , c . method , args , argc , true ) ;
2014-02-10 01:10:30 +00:00
} else {
2016-01-04 12:35:21 +00:00
Variant : : CallError ce ;
2020-01-22 00:45:06 +00:00
_emitting = true ;
2017-03-05 15:44:50 +00:00
target - > call ( c . method , args , argc , ce ) ;
2020-01-22 00:45:06 +00:00
_emitting = false ;
2017-08-05 22:48:29 +00:00
2017-03-05 15:44:50 +00:00
if ( ce . error ! = Variant : : CallError : : CALL_OK ) {
2018-09-20 22:05:39 +00:00
# ifdef DEBUG_ENABLED
if ( c . flags & CONNECT_PERSIST & & Engine : : get_singleton ( ) - > is_editor_hint ( ) & & ( script . is_null ( ) | | ! Ref < Script > ( script ) - > is_tool ( ) ) )
continue ;
# endif
2017-03-05 15:44:50 +00:00
if ( ce . error = = Variant : : CallError : : CALL_ERROR_INVALID_METHOD & & ! ClassDB : : class_exists ( target - > get_class_name ( ) ) ) {
2016-01-04 12:35:21 +00:00
//most likely object is not initialized yet, do not throw error.
} else {
2019-08-15 02:57:49 +00:00
ERR_PRINTS ( " Error calling method from signal ' " + String ( p_name ) + " ': " + Variant : : get_call_error_text ( target , c . method , args , argc , ce ) + " . " ) ;
2017-08-05 22:48:29 +00:00
err = ERR_METHOD_NOT_FOUND ;
2016-01-04 12:35:21 +00:00
}
}
2014-02-10 01:10:30 +00:00
}
2018-07-30 00:05:31 +00:00
bool disconnect = c . flags & CONNECT_ONESHOT ;
# ifdef TOOLS_ENABLED
if ( disconnect & & ( c . flags & CONNECT_PERSIST ) & & Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2019-02-13 08:23:29 +00:00
//this signal was connected from the editor, and is being edited. just don't disconnect for now
2018-07-30 00:05:31 +00:00
disconnect = false ;
}
# endif
if ( disconnect ) {
2014-02-10 01:10:30 +00:00
_ObjectSignalDisconnectData dd ;
2017-03-05 15:44:50 +00:00
dd . signal = p_name ;
dd . target = target ;
dd . method = c . method ;
2014-02-10 01:10:30 +00:00
disconnect_data . push_back ( dd ) ;
}
}
2016-01-04 12:35:21 +00:00
while ( ! disconnect_data . empty ( ) ) {
2014-02-10 01:10:30 +00:00
2016-01-04 12:35:21 +00:00
const _ObjectSignalDisconnectData & dd = disconnect_data . front ( ) - > get ( ) ;
2017-03-05 15:44:50 +00:00
disconnect ( dd . signal , dd . target , dd . method ) ;
2016-01-04 12:35:21 +00:00
disconnect_data . pop_front ( ) ;
}
2017-08-05 22:48:29 +00:00
return err ;
2016-01-04 12:35:21 +00:00
}
2014-02-10 01:10:30 +00:00
2017-08-05 22:48:29 +00:00
Error Object : : emit_signal ( const StringName & p_name , VARIANT_ARG_DECLARE ) {
2014-02-10 01:10:30 +00:00
2016-01-04 12:35:21 +00:00
VARIANT_ARGPTRS ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
int argc = 0 ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
2017-08-05 22:48:29 +00:00
2017-03-05 15:44:50 +00:00
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
2016-01-04 12:35:21 +00:00
break ;
argc + + ;
2014-02-10 01:10:30 +00:00
}
2017-08-05 22:48:29 +00:00
return emit_signal ( p_name , argptr , argc ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Object : : _add_user_signal ( const String & p_name , const Array & p_args ) {
2014-02-10 01:10:30 +00:00
// this version of add_user_signal is meant to be used from scripts or external apis
// without access to ADD_SIGNAL in bind_methods
// added events are per instance, as opposed to the other ones, which are global
MethodInfo mi ;
2017-03-05 15:44:50 +00:00
mi . name = p_name ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_args . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Dictionary d = p_args [ i ] ;
2014-02-10 01:10:30 +00:00
PropertyInfo param ;
if ( d . has ( " name " ) )
2017-03-05 15:44:50 +00:00
param . name = d [ " name " ] ;
2014-02-10 01:10:30 +00:00
if ( d . has ( " type " ) )
2017-03-05 15:44:50 +00:00
param . type = ( Variant : : Type ) ( int ) d [ " type " ] ;
2014-02-10 01:10:30 +00:00
mi . arguments . push_back ( param ) ;
}
add_user_signal ( mi ) ;
}
2017-03-05 15:44:50 +00:00
Array Object : : _get_signal_list ( ) const {
2014-02-10 01:10:30 +00:00
2016-01-01 13:27:25 +00:00
List < MethodInfo > signal_list ;
get_signal_list ( & signal_list ) ;
Array ret ;
2017-03-05 15:44:50 +00:00
for ( List < MethodInfo > : : Element * E = signal_list . front ( ) ; E ; E = E - > next ( ) ) {
2016-01-01 13:27:25 +00:00
2016-08-25 20:45:20 +00:00
ret . push_back ( Dictionary ( E - > get ( ) ) ) ;
2016-01-01 13:27:25 +00:00
}
return ret ;
2014-02-10 01:10:30 +00:00
}
2017-08-27 19:07:15 +00:00
2017-03-05 15:44:50 +00:00
Array Object : : _get_signal_connection_list ( const String & p_signal ) const {
2014-02-10 01:10:30 +00:00
2016-01-01 13:27:25 +00:00
List < Connection > conns ;
get_all_signal_connections ( & conns ) ;
Array ret ;
2017-03-05 15:44:50 +00:00
for ( List < Connection > : : Element * E = conns . front ( ) ; E ; E = E - > next ( ) ) {
2016-01-01 13:27:25 +00:00
2017-03-05 15:44:50 +00:00
Connection & c = E - > get ( ) ;
if ( c . signal = = p_signal ) {
2016-06-21 11:07:50 +00:00
Dictionary rc ;
2017-03-05 15:44:50 +00:00
rc [ " signal " ] = c . signal ;
rc [ " method " ] = c . method ;
rc [ " source " ] = c . source ;
rc [ " target " ] = c . target ;
rc [ " binds " ] = c . binds ;
rc [ " flags " ] = c . flags ;
2016-06-21 11:07:50 +00:00
ret . push_back ( rc ) ;
}
2016-01-01 13:27:25 +00:00
}
return ret ;
2014-02-10 01:10:30 +00:00
}
2017-06-15 13:31:57 +00:00
Array Object : : _get_incoming_connections ( ) const {
Array ret ;
int connections_amount = connections . size ( ) ;
for ( int idx_conn = 0 ; idx_conn < connections_amount ; idx_conn + + ) {
Dictionary conn_data ;
conn_data [ " source " ] = connections [ idx_conn ] . source ;
conn_data [ " signal_name " ] = connections [ idx_conn ] . signal ;
conn_data [ " method_name " ] = connections [ idx_conn ] . method ;
ret . push_back ( conn_data ) ;
}
return ret ;
}
2019-11-10 05:59:44 +00:00
bool Object : : has_signal ( const StringName & p_name ) const {
if ( ! script . is_null ( ) ) {
Ref < Script > scr = script ;
if ( scr . is_valid ( ) & & scr - > has_script_signal ( p_name ) ) {
return true ;
}
}
if ( ClassDB : : has_signal ( get_class_name ( ) , p_name ) ) {
return true ;
}
if ( _has_user_signal ( p_name ) ) {
return true ;
}
return false ;
}
2017-03-05 15:44:50 +00:00
void Object : : get_signal_list ( List < MethodInfo > * p_signals ) const {
2014-02-10 01:10:30 +00:00
2015-06-24 16:29:23 +00:00
if ( ! script . is_null ( ) ) {
2019-04-19 20:03:00 +00:00
Ref < Script > scr = script ;
if ( scr . is_valid ( ) ) {
scr - > get_script_signal_list ( p_signals ) ;
}
2015-06-24 16:29:23 +00:00
}
2017-03-05 15:44:50 +00:00
ClassDB : : get_signal_list ( get_class_name ( ) , p_signals ) ;
2014-02-10 01:10:30 +00:00
//find maybe usersignals?
2017-03-05 15:44:50 +00:00
const StringName * S = NULL ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
while ( ( S = signal_map . next ( S ) ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( signal_map [ * S ] . user . name ! = " " ) {
2014-02-10 01:10:30 +00:00
//user signal
p_signals - > push_back ( signal_map [ * S ] . user ) ;
}
}
}
2015-05-10 18:45:33 +00:00
void Object : : get_all_signal_connections ( List < Connection > * p_connections ) const {
2017-03-05 15:44:50 +00:00
const StringName * S = NULL ;
2015-05-10 18:45:33 +00:00
2017-03-05 15:44:50 +00:00
while ( ( S = signal_map . next ( S ) ) ) {
2015-05-10 18:45:33 +00:00
2017-03-05 15:44:50 +00:00
const Signal * s = & signal_map [ * S ] ;
2015-05-10 18:45:33 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < s - > slot_map . size ( ) ; i + + ) {
2015-05-10 18:45:33 +00:00
p_connections - > push_back ( s - > slot_map . getv ( i ) . conn ) ;
}
}
}
2017-03-05 15:44:50 +00:00
void Object : : get_signal_connection_list ( const StringName & p_signal , List < Connection > * p_connections ) const {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
const Signal * s = signal_map . getptr ( p_signal ) ;
2014-02-10 01:10:30 +00:00
if ( ! s )
return ; //nothing
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < s - > slot_map . size ( ) ; i + + )
2014-02-10 01:10:30 +00:00
p_connections - > push_back ( s - > slot_map . getv ( i ) . conn ) ;
}
2019-08-16 20:30:31 +00:00
int Object : : get_persistent_signal_connection_count ( ) const {
2016-06-04 16:17:56 +00:00
2019-08-16 20:30:31 +00:00
int count = 0 ;
2017-03-05 15:44:50 +00:00
const StringName * S = NULL ;
2016-06-04 16:17:56 +00:00
2017-03-05 15:44:50 +00:00
while ( ( S = signal_map . next ( S ) ) ) {
2016-06-04 16:17:56 +00:00
2017-03-05 15:44:50 +00:00
const Signal * s = & signal_map [ * S ] ;
2016-06-04 16:17:56 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < s - > slot_map . size ( ) ; i + + ) {
2019-08-16 20:30:31 +00:00
if ( s - > slot_map . getv ( i ) . conn . flags & CONNECT_PERSIST ) {
count + = 1 ;
}
2016-06-04 16:17:56 +00:00
}
}
2019-08-16 20:30:31 +00:00
return count ;
2016-06-04 16:17:56 +00:00
}
2016-06-06 22:55:50 +00:00
void Object : : get_signals_connected_to_this ( List < Connection > * p_connections ) const {
2017-03-05 15:44:50 +00:00
for ( const List < Connection > : : Element * E = connections . front ( ) ; E ; E = E - > next ( ) ) {
2016-06-07 05:39:40 +00:00
p_connections - > push_back ( E - > get ( ) ) ;
}
2016-06-06 22:55:50 +00:00
}
2017-03-05 15:44:50 +00:00
Error Object : : connect ( const StringName & p_signal , Object * p_to_object , const StringName & p_to_method , const Vector < Variant > & p_binds , uint32_t p_flags ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_NULL_V ( p_to_object , ERR_INVALID_PARAMETER ) ;
2014-02-10 01:10:30 +00:00
Signal * s = signal_map . getptr ( p_signal ) ;
if ( ! s ) {
2017-03-05 15:44:50 +00:00
bool signal_is_valid = ClassDB : : has_signal ( get_class_name ( ) , p_signal ) ;
2015-06-24 16:29:23 +00:00
//check in script
2018-11-27 22:55:37 +00:00
if ( ! signal_is_valid & & ! script . is_null ( ) ) {
if ( Ref < Script > ( script ) - > has_script_signal ( p_signal ) ) {
signal_is_valid = true ;
}
# ifdef TOOLS_ENABLED
else {
//allow connecting signals anyway if script is invalid, see issue #17070
if ( ! Ref < Script > ( script ) - > is_valid ( ) ) {
signal_is_valid = true ;
}
}
# endif
}
2015-06-24 16:29:23 +00:00
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_V_MSG ( ! signal_is_valid , ERR_INVALID_PARAMETER , " In Object of type ' " + String ( get_class ( ) ) + " ': Attempt to connect nonexistent signal ' " + p_signal + " ' to method ' " + p_to_object - > get_class ( ) + " . " + p_to_method + " '. " ) ;
2017-03-05 15:44:50 +00:00
signal_map [ p_signal ] = Signal ( ) ;
s = & signal_map [ p_signal ] ;
2014-02-10 01:10:30 +00:00
}
2017-08-07 10:17:31 +00:00
Signal : : Target target ( p_to_object - > get_instance_id ( ) , p_to_method ) ;
2014-02-10 01:10:30 +00:00
if ( s - > slot_map . has ( target ) ) {
2018-08-20 16:38:18 +00:00
if ( p_flags & CONNECT_REFERENCE_COUNTED ) {
s - > slot_map [ target ] . reference_count + + ;
return OK ;
} else {
2019-08-15 02:57:49 +00:00
ERR_FAIL_V_MSG ( ERR_INVALID_PARAMETER , " Signal ' " + p_signal + " ' is already connected to given method ' " + p_to_method + " ' in that object. " ) ;
2018-08-20 16:38:18 +00:00
}
2014-02-10 01:10:30 +00:00
}
Signal : : Slot slot ;
Connection conn ;
2017-03-05 15:44:50 +00:00
conn . source = this ;
conn . target = p_to_object ;
conn . method = p_to_method ;
conn . signal = p_signal ;
conn . flags = p_flags ;
conn . binds = p_binds ;
slot . conn = conn ;
slot . cE = p_to_object - > connections . push_back ( conn ) ;
2018-08-20 16:38:18 +00:00
if ( p_flags & CONNECT_REFERENCE_COUNTED ) {
slot . reference_count = 1 ;
}
2017-03-05 15:44:50 +00:00
s - > slot_map [ target ] = slot ;
2014-09-15 14:33:30 +00:00
return OK ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
bool Object : : is_connected ( const StringName & p_signal , Object * p_to_object , const StringName & p_to_method ) const {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_NULL_V ( p_to_object , false ) ;
2014-02-10 01:10:30 +00:00
const Signal * s = signal_map . getptr ( p_signal ) ;
if ( ! s ) {
2017-03-05 15:44:50 +00:00
bool signal_is_valid = ClassDB : : has_signal ( get_class_name ( ) , p_signal ) ;
2014-02-10 01:10:30 +00:00
if ( signal_is_valid )
return false ;
2015-12-11 10:53:40 +00:00
if ( ! script . is_null ( ) & & Ref < Script > ( script ) - > has_script_signal ( p_signal ) )
return false ;
2019-08-15 02:57:49 +00:00
ERR_FAIL_V_MSG ( false , " Nonexistent signal: " + p_signal + " . " ) ;
2014-02-10 01:10:30 +00:00
}
2017-08-07 10:17:31 +00:00
Signal : : Target target ( p_to_object - > get_instance_id ( ) , p_to_method ) ;
2014-02-10 01:10:30 +00:00
return s - > slot_map . has ( target ) ;
//const Map<Signal::Target,Signal::Slot>::Element *E = s->slot_map.find(target);
//return (E!=NULL);
}
2017-03-05 15:44:50 +00:00
void Object : : disconnect ( const StringName & p_signal , Object * p_to_object , const StringName & p_to_method ) {
2014-02-10 01:10:30 +00:00
2018-08-20 19:35:36 +00:00
_disconnect ( p_signal , p_to_object , p_to_method ) ;
}
void Object : : _disconnect ( const StringName & p_signal , Object * p_to_object , const StringName & p_to_method , bool p_force ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL_NULL ( p_to_object ) ;
Signal * s = signal_map . getptr ( p_signal ) ;
2020-12-31 10:33:39 +00:00
if ( ! s ) {
bool signal_is_valid = ClassDB : : has_signal ( get_class_name ( ) , p_signal ) | |
( ! script . is_null ( ) & & Ref < Script > ( script ) - > has_script_signal ( p_signal ) ) ;
ERR_FAIL_COND_MSG ( signal_is_valid , vformat ( " Attempt to disconnect a nonexistent connection to signal '%s' in %s, with target '%s' in %s. " ,
p_signal , to_string ( ) , p_to_method , p_to_object - > to_string ( ) ) ) ;
}
ERR_FAIL_COND_MSG ( ! s , vformat ( " Disconnecting nonexistent signal '%s' in %s. " , p_signal , to_string ( ) ) ) ;
2019-08-15 02:57:49 +00:00
2017-08-07 10:17:31 +00:00
Signal : : Target target ( p_to_object - > get_instance_id ( ) , p_to_method ) ;
2014-02-10 01:10:30 +00:00
2019-08-15 02:57:49 +00:00
ERR_FAIL_COND_MSG ( ! s - > slot_map . has ( target ) , " Disconnecting nonexistent signal ' " + p_signal + " ', slot: " + itos ( target . _id ) + " : " + target . method + " . " ) ;
2016-07-07 22:32:28 +00:00
2018-08-20 16:38:18 +00:00
Signal : : Slot * slot = & s - > slot_map [ target ] ;
2018-08-20 19:35:36 +00:00
if ( ! p_force ) {
slot - > reference_count - - ; // by default is zero, if it was not referenced it will go below it
if ( slot - > reference_count > = 0 ) {
return ;
}
2018-08-20 16:38:18 +00:00
}
p_to_object - > connections . erase ( slot - > cE ) ;
2014-02-10 01:10:30 +00:00
s - > slot_map . erase ( target ) ;
2017-03-05 15:44:50 +00:00
if ( s - > slot_map . empty ( ) & & ClassDB : : has_signal ( get_class_name ( ) , p_signal ) ) {
2014-02-10 01:10:30 +00:00
//not user signal, delete
signal_map . erase ( p_signal ) ;
}
}
2017-03-05 15:44:50 +00:00
void Object : : _set_bind ( const String & p_set , const Variant & p_value ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
set ( p_set , p_value ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Object : : _get_bind ( const String & p_name ) const {
2014-02-10 01:10:30 +00:00
return get ( p_name ) ;
}
2017-05-30 20:20:15 +00:00
void Object : : _set_indexed_bind ( const NodePath & p_name , const Variant & p_value ) {
set_indexed ( p_name . get_as_property_path ( ) . get_subnames ( ) , p_value ) ;
}
Variant Object : : _get_indexed_bind ( const NodePath & p_name ) const {
return get_indexed ( p_name . get_as_property_path ( ) . get_subnames ( ) ) ;
}
2017-01-03 02:03:46 +00:00
void Object : : initialize_class ( ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
static bool initialized = false ;
2014-02-10 01:10:30 +00:00
if ( initialized )
return ;
2017-01-03 02:03:46 +00:00
ClassDB : : _add_class < Object > ( ) ;
2014-02-10 01:10:30 +00:00
_bind_methods ( ) ;
2017-03-05 15:44:50 +00:00
initialized = true ;
2014-02-10 01:10:30 +00:00
}
2017-08-18 20:29:15 +00:00
StringName Object : : tr ( const StringName & p_message ) const {
2014-02-10 01:10:30 +00:00
if ( ! _can_translate | | ! TranslationServer : : get_singleton ( ) )
return p_message ;
return TranslationServer : : get_singleton ( ) - > translate ( p_message ) ;
}
2015-06-22 03:03:19 +00:00
void Object : : _clear_internal_resource_paths ( const Variant & p_var ) {
2017-03-05 15:44:50 +00:00
switch ( p_var . get_type ( ) ) {
2015-06-22 03:03:19 +00:00
case Variant : : OBJECT : {
RES r = p_var ;
if ( ! r . is_valid ( ) )
return ;
2017-03-05 15:44:50 +00:00
if ( ! r - > get_path ( ) . begins_with ( " res:// " ) | | r - > get_path ( ) . find ( " :: " ) = = - 1 )
2015-06-22 03:03:19 +00:00
return ; //not an internal resource
2017-03-05 15:44:50 +00:00
Object * object = p_var ;
2015-06-22 03:03:19 +00:00
if ( ! object )
return ;
r - > set_path ( " " ) ;
r - > clear_internal_resource_paths ( ) ;
} break ;
case Variant : : ARRAY : {
2017-03-05 15:44:50 +00:00
Array a = p_var ;
for ( int i = 0 ; i < a . size ( ) ; i + + ) {
2015-06-22 03:03:19 +00:00
_clear_internal_resource_paths ( a [ i ] ) ;
}
} break ;
case Variant : : DICTIONARY : {
2017-03-05 15:44:50 +00:00
Dictionary d = p_var ;
2015-06-22 03:03:19 +00:00
List < Variant > keys ;
d . get_key_list ( & keys ) ;
2017-03-05 15:44:50 +00:00
for ( List < Variant > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
2015-06-22 03:03:19 +00:00
_clear_internal_resource_paths ( E - > get ( ) ) ;
_clear_internal_resource_paths ( d [ E - > get ( ) ] ) ;
}
} break ;
2019-04-09 15:08:36 +00:00
default : {
}
2015-06-22 03:03:19 +00:00
}
}
2017-06-25 20:30:28 +00:00
# ifdef TOOLS_ENABLED
void Object : : editor_set_section_unfold ( const String & p_section , bool p_unfolded ) {
set_edited ( true ) ;
if ( p_unfolded )
editor_section_folding . insert ( p_section ) ;
else
editor_section_folding . erase ( p_section ) ;
}
bool Object : : editor_is_section_unfolded ( const String & p_section ) {
return editor_section_folding . has ( p_section ) ;
}
# endif
2015-06-22 03:03:19 +00:00
void Object : : clear_internal_resource_paths ( ) {
List < PropertyInfo > pinfo ;
get_property_list ( & pinfo ) ;
2017-03-05 15:44:50 +00:00
for ( List < PropertyInfo > : : Element * E = pinfo . front ( ) ; E ; E = E - > next ( ) ) {
2015-06-22 03:03:19 +00:00
_clear_internal_resource_paths ( get ( E - > get ( ) . name ) ) ;
}
}
2014-02-10 01:10:30 +00:00
void Object : : _bind_methods ( ) {
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_class " ) , & Object : : get_class ) ;
2019-06-26 13:57:13 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_class " , " class " ) , & Object : : is_class ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set " , " property " , " value " ) , & Object : : _set_bind ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get " , " property " ) , & Object : : _get_bind ) ;
2017-05-30 20:20:15 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_indexed " , " property " , " value " ) , & Object : : _set_indexed_bind ) ;
ClassDB : : bind_method ( D_METHOD ( " get_indexed " , " property " ) , & Object : : _get_indexed_bind ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_property_list " ) , & Object : : _get_property_list_bind ) ;
ClassDB : : bind_method ( D_METHOD ( " get_method_list " ) , & Object : : _get_method_list_bind ) ;
ClassDB : : bind_method ( D_METHOD ( " notification " , " what " , " reversed " ) , & Object : : notification , DEFVAL ( false ) ) ;
2019-04-10 05:07:40 +00:00
ClassDB : : bind_method ( D_METHOD ( " to_string " ) , & Object : : to_string ) ;
2017-08-07 10:17:31 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_instance_id " ) , & Object : : get_instance_id ) ;
2017-02-13 11:47:24 +00:00
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_script " , " script " ) , & Object : : set_script ) ;
ClassDB : : bind_method ( D_METHOD ( " get_script " ) , & Object : : get_script ) ;
2017-02-13 11:47:24 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_meta " , " name " , " value " ) , & Object : : set_meta ) ;
2019-04-26 17:23:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " remove_meta " , " name " ) , & Object : : remove_meta ) ;
2017-08-09 11:54:55 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_meta " , " name " ) , & Object : : get_meta ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_meta " , " name " ) , & Object : : has_meta ) ;
ClassDB : : bind_method ( D_METHOD ( " get_meta_list " ) , & Object : : _get_meta_list_bind ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_user_signal " , " signal " , " arguments " ) , & Object : : _add_user_signal , DEFVAL ( Array ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " has_user_signal " , " signal " ) , & Object : : _has_user_signal ) ;
2014-02-10 01:10:30 +00:00
{
MethodInfo mi ;
2017-03-05 15:44:50 +00:00
mi . name = " emit_signal " ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING , " signal " ) ) ;
2014-02-10 01:10:30 +00:00
2020-01-02 08:31:43 +00:00
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " emit_signal " , & Object : : _emit_signal , mi , varray ( ) , false ) ;
2014-02-10 01:10:30 +00:00
}
{
MethodInfo mi ;
2017-03-05 15:44:50 +00:00
mi . name = " call " ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING , " method " ) ) ;
2014-02-10 01:10:30 +00:00
2017-08-09 11:20:24 +00:00
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " call " , & Object : : _call_bind , mi ) ;
2014-02-10 01:10:30 +00:00
}
{
MethodInfo mi ;
2017-03-05 15:44:50 +00:00
mi . name = " call_deferred " ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING , " method " ) ) ;
2014-02-10 01:10:30 +00:00
2020-01-02 08:31:43 +00:00
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " call_deferred " , & Object : : _call_deferred_bind , mi , varray ( ) , false ) ;
2014-02-10 01:10:30 +00:00
}
2018-11-16 11:49:26 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_deferred " , " property " , " value " ) , & Object : : set_deferred ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " callv " , " method " , " arg_array " ) , & Object : : callv ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_method " , " method " ) , & Object : : has_method ) ;
2014-02-10 01:10:30 +00:00
2019-11-10 05:59:44 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_signal " , " signal " ) , & Object : : has_signal ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_signal_list " ) , & Object : : _get_signal_list ) ;
ClassDB : : bind_method ( D_METHOD ( " get_signal_connection_list " , " signal " ) , & Object : : _get_signal_connection_list ) ;
2017-06-15 13:31:57 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_incoming_connections " ) , & Object : : _get_incoming_connections ) ;
2014-02-10 01:10:30 +00:00
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " connect " , " signal " , " target " , " method " , " binds " , " flags " ) , & Object : : connect , DEFVAL ( Array ( ) ) , DEFVAL ( 0 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " disconnect " , " signal " , " target " , " method " ) , & Object : : disconnect ) ;
ClassDB : : bind_method ( D_METHOD ( " is_connected " , " signal " , " target " , " method " ) , & Object : : is_connected ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_block_signals " , " enable " ) , & Object : : set_block_signals ) ;
ClassDB : : bind_method ( D_METHOD ( " is_blocking_signals " ) , & Object : : is_blocking_signals ) ;
ClassDB : : bind_method ( D_METHOD ( " property_list_changed_notify " ) , & Object : : property_list_changed_notify ) ;
2014-02-10 01:10:30 +00:00
2017-08-18 20:29:15 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_message_translation " , " enable " ) , & Object : : set_message_translation ) ;
ClassDB : : bind_method ( D_METHOD ( " can_translate_messages " ) , & Object : : can_translate_messages ) ;
ClassDB : : bind_method ( D_METHOD ( " tr " , " message " ) , & Object : : tr ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_queued_for_deletion " ) , & Object : : is_queued_for_deletion ) ;
2015-03-28 17:34:28 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : add_virtual_method ( " Object " , MethodInfo ( " free " ) , false ) ;
2015-04-13 01:22:44 +00:00
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " script_changed " ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
BIND_VMETHOD ( MethodInfo ( " _notification " , PropertyInfo ( Variant : : INT , " what " ) ) ) ;
2017-08-29 05:15:46 +00:00
BIND_VMETHOD ( MethodInfo ( Variant : : BOOL , " _set " , PropertyInfo ( Variant : : STRING , " property " ) , PropertyInfo ( Variant : : NIL , " value " ) ) ) ;
2014-02-10 01:10:30 +00:00
# ifdef TOOLS_ENABLED
2017-03-05 15:44:50 +00:00
MethodInfo miget ( " _get " , PropertyInfo ( Variant : : STRING , " property " ) ) ;
2017-07-18 15:39:46 +00:00
miget . return_val . name = " Variant " ;
2018-05-30 02:30:01 +00:00
miget . return_val . usage | = PROPERTY_USAGE_NIL_IS_VARIANT ;
2017-03-05 15:44:50 +00:00
BIND_VMETHOD ( miget ) ;
2014-02-10 01:10:30 +00:00
MethodInfo plget ( " _get_property_list " ) ;
2014-09-21 04:43:42 +00:00
2017-03-05 15:44:50 +00:00
plget . return_val . type = Variant : : ARRAY ;
BIND_VMETHOD ( plget ) ;
2014-02-10 01:10:30 +00:00
# endif
2017-03-05 15:44:50 +00:00
BIND_VMETHOD ( MethodInfo ( " _init " ) ) ;
2019-04-10 05:07:40 +00:00
BIND_VMETHOD ( MethodInfo ( Variant : : STRING , " _to_string " ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
BIND_CONSTANT ( NOTIFICATION_POSTINITIALIZE ) ;
BIND_CONSTANT ( NOTIFICATION_PREDELETE ) ;
2014-02-10 01:10:30 +00:00
2017-08-20 15:45:01 +00:00
BIND_ENUM_CONSTANT ( CONNECT_DEFERRED ) ;
BIND_ENUM_CONSTANT ( CONNECT_PERSIST ) ;
BIND_ENUM_CONSTANT ( CONNECT_ONESHOT ) ;
2018-08-20 16:38:18 +00:00
BIND_ENUM_CONSTANT ( CONNECT_REFERENCE_COUNTED ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Object : : call_deferred ( const StringName & p_method , VARIANT_ARG_DECLARE ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
MessageQueue : : get_singleton ( ) - > push_call ( this , p_method , VARIANT_ARG_PASS ) ;
2014-02-10 01:10:30 +00:00
}
2018-11-16 11:49:26 +00:00
void Object : : set_deferred ( const StringName & p_property , const Variant & p_value ) {
MessageQueue : : get_singleton ( ) - > push_set ( this , p_property , p_value ) ;
}
2014-02-10 01:10:30 +00:00
void Object : : set_block_signals ( bool p_block ) {
2017-03-05 15:44:50 +00:00
_block_signals = p_block ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
bool Object : : is_blocking_signals ( ) const {
2014-02-10 01:10:30 +00:00
return _block_signals ;
}
void Object : : get_translatable_strings ( List < String > * p_strings ) const {
List < PropertyInfo > plist ;
get_property_list ( & plist ) ;
2017-03-05 15:44:50 +00:00
for ( List < PropertyInfo > : : Element * E = plist . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( ! ( E - > get ( ) . usage & PROPERTY_USAGE_INTERNATIONALIZED ) )
2014-02-10 01:10:30 +00:00
continue ;
2017-03-05 15:44:50 +00:00
String text = get ( E - > get ( ) . name ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( text = = " " )
2014-02-10 01:10:30 +00:00
continue ;
p_strings - > push_back ( text ) ;
}
}
2017-03-05 15:44:50 +00:00
Variant : : Type Object : : get_static_property_type ( const StringName & p_property , bool * r_valid ) const {
2015-12-05 17:18:22 +00:00
bool valid ;
2017-03-05 15:44:50 +00:00
Variant : : Type t = ClassDB : : get_property_type ( get_class_name ( ) , p_property , & valid ) ;
2015-12-05 17:18:22 +00:00
if ( valid ) {
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = true ;
2015-12-05 17:18:22 +00:00
return t ;
}
if ( get_script_instance ( ) ) {
2017-03-05 15:44:50 +00:00
return get_script_instance ( ) - > get_property_type ( p_property , r_valid ) ;
2015-12-05 17:18:22 +00:00
}
if ( r_valid )
2017-03-05 15:44:50 +00:00
* r_valid = false ;
2015-12-05 17:18:22 +00:00
return Variant : : NIL ;
}
2017-05-30 20:20:15 +00:00
Variant : : Type Object : : get_static_property_type_indexed ( const Vector < StringName > & p_path , bool * r_valid ) const {
2017-11-24 13:26:32 +00:00
if ( p_path . size ( ) = = 0 ) {
if ( r_valid )
* r_valid = false ;
return Variant : : NIL ;
}
2017-05-30 20:20:15 +00:00
bool valid = false ;
Variant : : Type t = get_static_property_type ( p_path [ 0 ] , & valid ) ;
if ( ! valid ) {
if ( r_valid )
* r_valid = false ;
return Variant : : NIL ;
}
Variant : : CallError ce ;
Variant check = Variant : : construct ( t , NULL , 0 , ce ) ;
for ( int i = 1 ; i < p_path . size ( ) ; i + + ) {
if ( check . get_type ( ) = = Variant : : OBJECT | | check . get_type ( ) = = Variant : : DICTIONARY | | check . get_type ( ) = = Variant : : ARRAY ) {
// We cannot be sure about the type of properties this types can have
if ( r_valid )
* r_valid = false ;
return Variant : : NIL ;
}
check = check . get_named ( p_path [ i ] , & valid ) ;
if ( ! valid ) {
if ( r_valid )
* r_valid = false ;
return Variant : : NIL ;
}
}
if ( r_valid )
* r_valid = true ;
return check . get_type ( ) ;
}
2015-03-28 17:34:28 +00:00
bool Object : : is_queued_for_deletion ( ) const {
return _is_queued_for_deletion ;
}
2014-02-10 01:10:30 +00:00
# ifdef TOOLS_ENABLED
void Object : : set_edited ( bool p_edited ) {
2017-03-05 15:44:50 +00:00
_edited = p_edited ;
2016-05-27 17:18:40 +00:00
_edited_version + + ;
2014-02-10 01:10:30 +00:00
}
bool Object : : is_edited ( ) const {
return _edited ;
}
2016-05-27 17:18:40 +00:00
uint32_t Object : : get_edited_version ( ) const {
return _edited_version ;
}
2014-02-10 01:10:30 +00:00
# endif
2017-07-16 15:39:23 +00:00
void * Object : : get_script_instance_binding ( int p_script_language_index ) {
# ifdef DEBUG_ENABLED
ERR_FAIL_INDEX_V ( p_script_language_index , MAX_SCRIPT_INSTANCE_BINDINGS , NULL ) ;
# endif
//it's up to the script language to make this thread safe, if the function is called twice due to threads being out of syncro
//just return the same pointer.
//if you want to put a big lock in the entire function and keep allocated pointers in a map or something, feel free to do it
//as it should not really affect performance much (won't be called too often), as in far most caes the condition below will be false afterwards
if ( ! _script_instance_bindings [ p_script_language_index ] ) {
2018-02-22 14:34:08 +00:00
void * script_data = ScriptServer : : get_language ( p_script_language_index ) - > alloc_instance_binding_data ( this ) ;
if ( script_data ) {
atomic_increment ( & instance_binding_count ) ;
_script_instance_bindings [ p_script_language_index ] = script_data ;
}
2017-07-16 15:39:23 +00:00
}
return _script_instance_bindings [ p_script_language_index ] ;
}
2019-02-03 05:35:22 +00:00
bool Object : : has_script_instance_binding ( int p_script_language_index ) {
return _script_instance_bindings [ p_script_language_index ] ! = NULL ;
}
2019-02-04 19:39:02 +00:00
void Object : : set_script_instance_binding ( int p_script_language_index , void * p_data ) {
# ifdef DEBUG_ENABLED
CRASH_COND ( _script_instance_bindings [ p_script_language_index ] ! = NULL ) ;
# endif
_script_instance_bindings [ p_script_language_index ] = p_data ;
}
2014-02-10 01:10:30 +00:00
Object : : Object ( ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
_class_ptr = NULL ;
_block_signals = false ;
_predelete_ok = 0 ;
2019-05-09 09:21:49 +00:00
_instance_id = 0 ;
_instance_id = ObjectDB : : add_instance ( this ) ;
2017-03-05 15:44:50 +00:00
_can_translate = true ;
_is_queued_for_deletion = false ;
2020-01-22 00:45:06 +00:00
_emitting = false ;
2018-02-22 14:34:08 +00:00
instance_binding_count = 0 ;
2017-07-16 15:39:23 +00:00
memset ( _script_instance_bindings , 0 , sizeof ( void * ) * MAX_SCRIPT_INSTANCE_BINDINGS ) ;
2017-03-05 15:44:50 +00:00
script_instance = NULL ;
2020-04-23 10:40:06 +00:00
# ifdef DEBUG_ENABLED
_rc . store ( nullptr , std : : memory_order_release ) ;
# endif
2014-02-10 01:10:30 +00:00
# ifdef TOOLS_ENABLED
2017-03-05 15:44:50 +00:00
_edited = false ;
_edited_version = 0 ;
2014-02-10 01:10:30 +00:00
# endif
2014-04-05 15:39:30 +00:00
# ifdef DEBUG_ENABLED
_lock_index . init ( 1 ) ;
# endif
2014-02-10 01:10:30 +00:00
}
Object : : ~ Object ( ) {
2020-04-23 10:40:06 +00:00
# ifdef DEBUG_ENABLED
ObjectRC * rc = _rc . load ( std : : memory_order_acquire ) ;
if ( rc ) {
if ( rc - > invalidate ( ) ) {
2020-06-27 23:27:03 +00:00
memdelete ( rc ) ;
2020-04-23 10:40:06 +00:00
}
}
# endif
2014-02-10 01:10:30 +00:00
if ( script_instance )
memdelete ( script_instance ) ;
2017-03-05 15:44:50 +00:00
script_instance = NULL ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
const StringName * S = NULL ;
2014-02-10 01:10:30 +00:00
2020-01-22 00:45:06 +00:00
if ( _emitting ) {
//@todo this may need to actually reach the debugger prioritarily somehow because it may crash before
ERR_PRINTS ( " Object " + to_string ( ) + " was freed or unreferenced while a signal is being emitted from it. Try connecting to the signal using 'CONNECT_DEFERRED' flag, or use queue_free() to free the object (if this object is a Node) to avoid this error and potential crashes. " ) ;
}
2018-11-18 14:47:19 +00:00
while ( ( S = signal_map . next ( NULL ) ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Signal * s = & signal_map [ * S ] ;
2014-02-10 01:10:30 +00:00
2018-11-18 14:47:19 +00:00
//brute force disconnect for performance
int slot_count = s - > slot_map . size ( ) ;
const VMap < Signal : : Target , Signal : : Slot > : : Pair * slot_list = s - > slot_map . get_array ( ) ;
2014-02-10 01:10:30 +00:00
2018-11-18 14:47:19 +00:00
for ( int i = 0 ; i < slot_count ; i + + ) {
slot_list [ i ] . value . conn . target - > connections . erase ( slot_list [ i ] . value . cE ) ;
}
2014-02-10 01:10:30 +00:00
2018-11-18 14:47:19 +00:00
signal_map . erase ( * S ) ;
2014-02-10 01:10:30 +00:00
}
2018-11-18 14:47:19 +00:00
//signals from nodes that connect to this node
2017-03-05 15:44:50 +00:00
while ( connections . size ( ) ) {
2014-02-10 01:10:30 +00:00
Connection c = connections . front ( ) - > get ( ) ;
2018-08-20 19:35:36 +00:00
c . source - > _disconnect ( c . signal , c . target , c . method , true ) ;
2014-02-10 01:10:30 +00:00
}
ObjectDB : : remove_instance ( this ) ;
2019-05-09 09:21:49 +00:00
_instance_id = 0 ;
2017-03-05 15:44:50 +00:00
_predelete_ok = 2 ;
2017-07-16 15:39:23 +00:00
2019-02-04 19:39:02 +00:00
if ( ! ScriptServer : : are_languages_finished ( ) ) {
for ( int i = 0 ; i < MAX_SCRIPT_INSTANCE_BINDINGS ; i + + ) {
if ( _script_instance_bindings [ i ] ) {
ScriptServer : : get_language ( i ) - > free_instance_binding_data ( _script_instance_bindings [ i ] ) ;
}
2017-07-16 15:39:23 +00:00
}
}
2014-02-10 01:10:30 +00:00
}
bool predelete_handler ( Object * p_object ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return p_object - > _predelete ( ) ;
}
void postinitialize_handler ( Object * p_object ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
p_object - > _postinitialize ( ) ;
}
2017-06-09 03:23:50 +00:00
HashMap < ObjectID , Object * > ObjectDB : : instances ;
ObjectID ObjectDB : : instance_counter = 1 ;
2017-03-05 15:44:50 +00:00
HashMap < Object * , ObjectID , ObjectDB : : ObjectPtrHash > ObjectDB : : instance_checks ;
2017-06-09 03:23:50 +00:00
ObjectID ObjectDB : : add_instance ( Object * p_object ) {
2014-02-10 01:10:30 +00:00
2017-08-07 10:17:31 +00:00
ERR_FAIL_COND_V ( p_object - > get_instance_id ( ) ! = 0 , 0 ) ;
2017-01-07 21:25:37 +00:00
rw_lock - > write_lock ( ) ;
2018-09-29 14:45:09 +00:00
ObjectID instance_id = + + instance_counter ;
instances [ instance_id ] = p_object ;
instance_checks [ p_object ] = instance_id ;
2017-01-07 21:25:37 +00:00
rw_lock - > write_unlock ( ) ;
2018-09-29 14:45:09 +00:00
return instance_id ;
2014-02-10 01:10:30 +00:00
}
void ObjectDB : : remove_instance ( Object * p_object ) {
2017-01-07 21:25:37 +00:00
rw_lock - > write_lock ( ) ;
2017-08-07 10:17:31 +00:00
instances . erase ( p_object - > get_instance_id ( ) ) ;
2014-02-10 01:10:30 +00:00
instance_checks . erase ( p_object ) ;
2017-01-07 21:25:37 +00:00
rw_lock - > write_unlock ( ) ;
2014-02-10 01:10:30 +00:00
}
2019-05-09 09:21:49 +00:00
Object * ObjectDB : : get_instance ( ObjectID p_instance_id ) {
2014-02-10 01:10:30 +00:00
2017-01-07 21:25:37 +00:00
rw_lock - > read_lock ( ) ;
2019-05-09 09:21:49 +00:00
Object * * obj = instances . getptr ( p_instance_id ) ;
2017-01-07 21:25:37 +00:00
rw_lock - > read_unlock ( ) ;
2014-02-10 01:10:30 +00:00
if ( ! obj )
return NULL ;
return * obj ;
}
void ObjectDB : : debug_objects ( DebugFunc p_func ) {
2017-01-07 21:25:37 +00:00
rw_lock - > read_lock ( ) ;
2014-02-10 01:10:30 +00:00
2017-06-09 03:23:50 +00:00
const ObjectID * K = NULL ;
2017-03-05 15:44:50 +00:00
while ( ( K = instances . next ( K ) ) ) {
2014-02-10 01:10:30 +00:00
p_func ( instances [ * K ] ) ;
}
2017-01-07 21:25:37 +00:00
rw_lock - > read_unlock ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Object : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
2014-12-17 01:31:57 +00:00
}
2014-02-10 01:10:30 +00:00
int ObjectDB : : get_object_count ( ) {
2017-01-07 21:25:37 +00:00
rw_lock - > read_lock ( ) ;
2017-03-05 15:44:50 +00:00
int count = instances . size ( ) ;
2017-01-07 21:25:37 +00:00
rw_lock - > read_unlock ( ) ;
return count ;
}
2017-03-05 15:44:50 +00:00
RWLock * ObjectDB : : rw_lock = NULL ;
2014-02-10 01:10:30 +00:00
2017-01-07 21:25:37 +00:00
void ObjectDB : : setup ( ) {
rw_lock = RWLock : : create ( ) ;
2014-02-10 01:10:30 +00:00
}
void ObjectDB : : cleanup ( ) {
2017-01-07 21:25:37 +00:00
rw_lock - > write_lock ( ) ;
2014-02-10 01:10:30 +00:00
if ( instances . size ( ) ) {
2016-03-08 23:00:52 +00:00
2020-06-08 14:39:08 +00:00
WARN_PRINT ( " ObjectDB instances leaked at exit (run with --verbose for details). " ) ;
2015-04-20 22:38:02 +00:00
if ( OS : : get_singleton ( ) - > is_stdout_verbose ( ) ) {
2020-05-06 12:19:04 +00:00
// Ensure calling the native classes because if a leaked instance has a script
// that overrides any of those methods, it'd not be OK to call them at this point,
// now the scripting languages have already been terminated.
MethodBind * node_get_name = ClassDB : : get_method ( " Node " , " get_name " ) ;
MethodBind * resource_get_path = ClassDB : : get_method ( " Resource " , " get_path " ) ;
Variant : : CallError call_error ;
2017-06-09 03:23:50 +00:00
const ObjectID * K = NULL ;
2017-03-05 15:44:50 +00:00
while ( ( K = instances . next ( K ) ) ) {
2015-04-20 22:38:02 +00:00
2020-05-06 12:19:04 +00:00
String extra_info ;
2017-01-03 02:03:46 +00:00
if ( instances [ * K ] - > is_class ( " Node " ) )
2020-05-06 12:19:04 +00:00
extra_info = " - Node name: " + String ( node_get_name - > call ( instances [ * K ] , NULL , 0 , call_error ) ) ;
2017-08-06 09:04:35 +00:00
if ( instances [ * K ] - > is_class ( " Resource " ) )
2020-05-06 12:19:04 +00:00
extra_info = " - Resource path: " + String ( resource_get_path - > call ( instances [ * K ] , NULL , 0 , call_error ) ) ;
print_line ( " Leaked instance: " + String ( instances [ * K ] - > get_class ( ) ) + " : " + itos ( * K ) + extra_info ) ;
2015-04-20 22:38:02 +00:00
}
2020-06-08 14:39:08 +00:00
print_line ( " Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`). " ) ;
2015-04-20 22:38:02 +00:00
}
2014-02-10 01:10:30 +00:00
}
instances . clear ( ) ;
instance_checks . clear ( ) ;
2017-01-07 21:25:37 +00:00
rw_lock - > write_unlock ( ) ;
memdelete ( rw_lock ) ;
2014-02-10 01:10:30 +00:00
}