2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* object.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
2016-01-01 14:50:53 +01:00
/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
2014-02-10 02:10:30 +01: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. */
/*************************************************************************/
# include "object.h"
# include "print_string.h"
# include "object_type_db.h"
# include "script_language.h"
# include "message_queue.h"
# include "core_string_names.h"
# include "translation.h"
2015-04-21 00:38:02 +02:00
# include "os/os.h"
2015-06-22 05:03:19 +02:00
# include "resource.h"
2014-04-05 17:39:30 +02:00
# ifdef DEBUG_ENABLED
struct _ObjectDebugLock {
Object * obj ;
_ObjectDebugLock ( Object * p_obj ) {
obj = p_obj ;
obj - > _lock_index . ref ( ) ;
}
~ _ObjectDebugLock ( ) {
obj - > _lock_index . unref ( ) ;
}
} ;
# define OBJ_DEBUG_LOCK _ObjectDebugLock _debug_lock(this);
# else
# define OBJ_DEBUG_LOCK
# endif
2014-02-10 02:10:30 +01:00
Array convert_property_list ( const List < PropertyInfo > * p_list ) {
Array va ;
for ( const List < PropertyInfo > : : Element * E = p_list - > front ( ) ; E ; E = E - > next ( ) ) {
const PropertyInfo & pi = E - > get ( ) ;
Dictionary d ;
d [ " name " ] = pi . name ;
d [ " type " ] = pi . type ;
d [ " hint " ] = pi . hint ;
d [ " hint_string " ] = pi . hint_string ;
d [ " usage " ] = pi . usage ;
va . push_back ( d ) ;
}
return va ;
}
MethodInfo : : MethodInfo ( ) {
id = 0 ;
flags = METHOD_FLAG_NORMAL ;
}
MethodInfo : : MethodInfo ( const String & p_name ) {
id = 0 ;
name = p_name ;
flags = METHOD_FLAG_NORMAL ;
}
MethodInfo : : MethodInfo ( const String & p_name , const PropertyInfo & p_param1 ) {
id = 0 ;
name = p_name ;
arguments . push_back ( p_param1 ) ;
flags = METHOD_FLAG_NORMAL ;
}
MethodInfo : : MethodInfo ( const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 ) {
id = 0 ;
name = p_name ;
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
flags = METHOD_FLAG_NORMAL ;
}
MethodInfo : : MethodInfo ( const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 ) {
id = 0 ;
name = p_name ;
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
flags = METHOD_FLAG_NORMAL ;
}
MethodInfo : : MethodInfo ( const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 , const PropertyInfo & p_param4 ) {
id = 0 ;
name = p_name ;
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
arguments . push_back ( p_param4 ) ;
flags = METHOD_FLAG_NORMAL ;
}
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 ) {
id = 0 ;
name = p_name ;
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 ) ;
flags = METHOD_FLAG_NORMAL ;
}
MethodInfo : : MethodInfo ( Variant : : Type ret ) {
id = 0 ;
flags = METHOD_FLAG_NORMAL ;
return_val . type = ret ;
}
MethodInfo : : MethodInfo ( Variant : : Type ret , const String & p_name ) {
id = 0 ;
name = p_name ;
flags = METHOD_FLAG_NORMAL ;
return_val . type = ret ;
}
MethodInfo : : MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 ) {
id = 0 ;
name = p_name ;
arguments . push_back ( p_param1 ) ;
flags = METHOD_FLAG_NORMAL ;
return_val . type = ret ;
}
MethodInfo : : MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 ) {
id = 0 ;
name = p_name ;
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
flags = METHOD_FLAG_NORMAL ;
return_val . type = ret ;
}
MethodInfo : : MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 ) {
id = 0 ;
name = p_name ;
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
flags = METHOD_FLAG_NORMAL ;
return_val . type = ret ;
}
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 ) {
id = 0 ;
name = p_name ;
arguments . push_back ( p_param1 ) ;
arguments . push_back ( p_param2 ) ;
arguments . push_back ( p_param3 ) ;
arguments . push_back ( p_param4 ) ;
flags = METHOD_FLAG_NORMAL ;
return_val . type = ret ;
}
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 ) {
id = 0 ;
name = p_name ;
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 ) ;
flags = METHOD_FLAG_NORMAL ;
return_val . type = ret ;
}
Object : : Connection : : operator Variant ( ) const {
Dictionary d ;
d [ " source " ] = source ;
d [ " signal " ] = signal ;
d [ " target " ] = target ;
d [ " method " ] = method ;
d [ " flags " ] = flags ;
d [ " binds " ] = binds ;
return d ;
}
bool Object : : Connection : : operator < ( const Connection & p_conn ) const {
if ( source = = p_conn . source ) {
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 {
return source < p_conn . source ;
}
}
Object : : Connection : : Connection ( const Variant & p_variant ) {
Dictionary d = p_variant ;
if ( d . has ( " source " ) )
source = d [ " source " ] ;
if ( d . has ( " signal " ) )
signal = d [ " signal " ] ;
if ( d . has ( " target " ) )
target = d [ " target " ] ;
if ( d . has ( " method " ) )
method = d [ " method " ] ;
if ( d . has ( " flags " ) )
flags = d [ " flags " ] ;
if ( d . has ( " binds " ) )
binds = d [ " binds " ] ;
}
bool Object : : _predelete ( ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
_predelete_ok = 1 ;
notification ( NOTIFICATION_PREDELETE , true ) ;
2015-06-29 05:29:49 +02:00
if ( _predelete_ok ) {
_type_ptr = NULL ; //must restore so destructors can access type ptr correctly
}
2014-02-10 02:10:30 +01:00
return _predelete_ok ;
}
void Object : : _postinitialize ( ) {
2015-06-29 05:29:49 +02:00
_type_ptr = _get_type_namev ( ) ;
2014-02-10 02:10:30 +01:00
_initialize_typev ( ) ;
notification ( NOTIFICATION_POSTINITIALIZE ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
}
void Object : : get_valid_parents_static ( List < String > * p_parents ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
}
void Object : : _get_valid_parents_static ( List < String > * p_parents ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
}
#if 0
//old style set, deprecated
void Object : : set ( const String & p_name , const Variant & p_value ) {
_setv ( p_name , p_value ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
//if (!_use_builtin_script())
// return;
bool success ;
ObjectTypeDB : : set_property ( this , p_name , p_value , success ) ;
if ( success ) {
return ;
}
if ( p_name = = " __meta__ " ) {
metadata = p_value ;
} else if ( p_name = = " script/script " ) {
set_script ( p_value ) ;
} else if ( script_instance ) {
script_instance - > set ( p_name , p_value ) ;
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
}
# endif
void Object : : set ( const StringName & p_name , const Variant & p_value , bool * r_valid ) {
# ifdef TOOLS_ENABLED
_edited = true ;
# endif
2015-12-05 18:18:22 +01:00
2014-02-10 02:10:30 +01:00
if ( script_instance ) {
if ( script_instance - > set ( p_name , p_value ) ) {
if ( r_valid )
* r_valid = true ;
return ;
}
}
//try built-in setgetter
{
2015-12-05 18:18:22 +01:00
if ( ObjectTypeDB : : set_property ( this , p_name , p_value , r_valid ) ) {
//if (r_valid)
// *r_valid=true;
2014-02-10 02:10:30 +01:00
return ;
}
}
if ( p_name = = CoreStringNames : : get_singleton ( ) - > _script ) {
set_script ( p_value ) ;
if ( r_valid )
* r_valid = true ;
return ;
} else if ( p_name = = CoreStringNames : : get_singleton ( ) - > _meta ) {
//set_meta(p_name,p_value);
metadata = p_value ;
if ( r_valid )
* r_valid = true ;
return ;
} else {
2016-03-09 00:00:52 +01:00
//something inside the object... :|
2014-02-10 02:10:30 +01:00
bool success = _setv ( p_name , p_value ) ;
if ( success ) {
if ( r_valid )
* r_valid = true ;
return ;
}
setvar ( p_name , p_value , r_valid ) ;
}
}
Variant Object : : get ( const StringName & p_name , bool * r_valid ) const {
Variant ret ;
if ( script_instance ) {
if ( script_instance - > get ( p_name , ret ) ) {
if ( r_valid )
* r_valid = true ;
return ret ;
}
}
//try built-in setgetter
{
if ( ObjectTypeDB : : get_property ( const_cast < Object * > ( this ) , p_name , ret ) ) {
if ( r_valid )
* r_valid = true ;
return ret ;
}
}
if ( p_name = = CoreStringNames : : get_singleton ( ) - > _script ) {
ret = get_script ( ) ;
if ( r_valid )
* r_valid = true ;
return ret ;
} else if ( p_name = = CoreStringNames : : get_singleton ( ) - > _meta ) {
ret = metadata ;
if ( r_valid )
* r_valid = true ;
return ret ;
} else {
//something inside the object... :|
bool success = _getv ( p_name , ret ) ;
if ( success ) {
if ( r_valid )
* r_valid = true ;
return ret ;
}
//if nothing else, use getvar
return getvar ( p_name , r_valid ) ;
}
}
#if 0
//old style get, deprecated
Variant Object : : get ( const String & p_name ) const {
Variant ret = _getv ( p_name ) ;
if ( ret . get_type ( ) ! = Variant : : NIL )
return ret ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
bool success ;
ObjectTypeDB : : get_property ( const_cast < Object * > ( this ) , p_name , ret , success ) ;
if ( success ) {
return ret ;
}
if ( p_name = = " __meta__ " )
return metadata ;
else if ( p_name = = " script/script " )
return script ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( script_instance ) {
return script_instance - > get ( p_name ) ;
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return Variant ( ) ;
}
# endif
void Object : : get_property_list ( List < PropertyInfo > * p_list , bool p_reversed ) const {
if ( script_instance & & p_reversed ) {
p_list - > push_back ( PropertyInfo ( Variant : : NIL , " Script Variables " , PROPERTY_HINT_NONE , String ( ) , PROPERTY_USAGE_CATEGORY ) ) ;
script_instance - > get_property_list ( p_list ) ;
}
_get_property_listv ( p_list , p_reversed ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( ! _use_builtin_script ( ) )
return ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( ! is_type ( " Script " ) ) // can still be set, but this is for userfriendlyness
p_list - > push_back ( PropertyInfo ( Variant : : OBJECT , " script/script " , PROPERTY_HINT_RESOURCE_TYPE , " Script " , PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NONZERO ) ) ;
if ( ! metadata . empty ( ) )
p_list - > push_back ( PropertyInfo ( Variant : : DICTIONARY , " __meta__ " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_STORE_IF_NONZERO ) ) ;
if ( script_instance & & ! p_reversed ) {
p_list - > push_back ( PropertyInfo ( Variant : : NIL , " Script Variables " , PROPERTY_HINT_NONE , String ( ) , PROPERTY_USAGE_CATEGORY ) ) ;
script_instance - > get_property_list ( p_list ) ;
2016-03-09 00:00:52 +01:00
}
2014-02-10 02:10:30 +01:00
}
2016-05-15 04:48:23 +02:00
void Object : : _validate_property ( PropertyInfo & property ) const {
}
2014-02-10 02:10:30 +01:00
void Object : : get_method_list ( List < MethodInfo > * p_list ) const {
ObjectTypeDB : : get_method_list ( get_type_name ( ) , p_list ) ;
if ( script_instance ) {
script_instance - > get_method_list ( p_list ) ;
2016-03-09 00:00:52 +01:00
}
2014-02-10 02:10:30 +01:00
}
Variant Object : : _call_bind ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
if ( p_argcount < 1 ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 0 ;
return 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 ;
return Variant ( ) ;
}
StringName method = * p_args [ 0 ] ;
return call ( method , & p_args [ 1 ] , p_argcount - 1 , r_error ) ;
}
Variant Object : : _call_deferred_bind ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
if ( p_argcount < 1 ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 0 ;
return 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 ;
return Variant ( ) ;
}
r_error . error = Variant : : CallError : : CALL_OK ;
2016-01-04 13:35:21 +01:00
StringName method = * p_args [ 0 ] ;
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
MessageQueue : : get_singleton ( ) - > push_call ( get_instance_ID ( ) , method , & p_args [ 1 ] , p_argcount - 1 ) ;
2014-02-10 02:10:30 +01:00
return Variant ( ) ;
}
#if 0
Variant Object : : _call_bind ( const StringName & p_name , const Variant & p_arg1 , const Variant & p_arg2 , const Variant & p_arg3 , const Variant & p_arg4 ) {
ERR_FAIL_COND_V ( p_argcount < 1 , Variant ( ) ) ;
return call ( p_name , p_arg1 , p_arg2 , p_arg3 , p_arg4 ) ;
} ;
void Object : : _call_deferred_bind ( const StringName & p_name , const Variant & p_arg1 , const Variant & p_arg2 , const Variant & p_arg3 , const Variant & p_arg4 ) {
call_deferred ( p_name , p_arg1 , p_arg2 , p_arg3 , p_arg4 ) ;
} ;
# endif
# ifdef DEBUG_ENABLED
static bool _test_call_error ( const StringName & p_func , const Variant : : CallError & error ) {
switch ( error . error ) {
case Variant : : CallError : : CALL_OK :
return true ;
case Variant : : CallError : : CALL_ERROR_INVALID_METHOD :
return false ;
case Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT : {
ERR_EXPLAIN ( " Error Calling Function: " + String ( p_func ) + " - Invalid type for argument " + itos ( error . argument ) + " , expected " + Variant : : get_type_name ( error . expected ) ) ;
ERR_FAIL_V ( true ) ;
} break ;
case Variant : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS : {
ERR_EXPLAIN ( " Error Calling Function: " + String ( p_func ) + " - Too many arguments, expected " + itos ( error . argument ) ) ;
ERR_FAIL_V ( true ) ;
} break ;
case Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS : {
ERR_EXPLAIN ( " Error Calling Function: " + String ( p_func ) + " - Too few arguments, expected " + itos ( error . argument ) ) ;
ERR_FAIL_V ( true ) ;
} break ;
case Variant : : CallError : : CALL_ERROR_INSTANCE_IS_NULL : { } //?
}
return true ;
}
# else
# define _test_call_error(m_str,m_err) ((m_err.error==Variant::CallError::CALL_ERROR_INVALID_METHOD)?false:true)
# endif
void Object : : call_multilevel ( const StringName & p_method , const Variant * * p_args , int p_argcount ) {
if ( p_method = = CoreStringNames : : get_singleton ( ) - > _free ) {
# ifdef DEBUG_ENABLED
if ( cast_to < Reference > ( ) ) {
ERR_EXPLAIN ( " Can't 'free' a reference. " ) ;
ERR_FAIL ( ) ;
return ;
}
2014-04-05 17:39:30 +02:00
if ( _lock_index . get ( ) > 1 ) {
ERR_EXPLAIN ( " Object is locked and can't be freed. " ) ;
ERR_FAIL ( ) ;
return ;
}
2014-02-10 02:10:30 +01:00
# endif
2014-04-05 17:39:30 +02:00
2014-02-10 02:10:30 +01:00
//must be here, must be before everything,
memdelete ( this ) ;
return ;
}
//Variant ret;
2014-04-05 17:39:30 +02:00
OBJ_DEBUG_LOCK
2014-02-10 02:10:30 +01:00
Variant : : CallError error ;
if ( script_instance ) {
script_instance - > call_multilevel ( p_method , p_args , p_argcount ) ;
//_test_call_error(p_method,error);
}
MethodBind * method = ObjectTypeDB : : get_method ( get_type_name ( ) , p_method ) ;
if ( method ) {
method - > call ( this , p_args , p_argcount , error ) ;
_test_call_error ( p_method , error ) ;
}
}
void Object : : call_multilevel_reversed ( const StringName & p_method , const Variant * * p_args , int p_argcount ) {
MethodBind * method = ObjectTypeDB : : get_method ( get_type_name ( ) , p_method ) ;
Variant : : CallError error ;
2014-04-05 17:39:30 +02:00
OBJ_DEBUG_LOCK
2014-02-10 02:10:30 +01:00
if ( method ) {
method - > call ( this , p_args , p_argcount , error ) ;
_test_call_error ( p_method , error ) ;
}
//Variant ret;
if ( script_instance ) {
script_instance - > call_multilevel_reversed ( p_method , p_args , p_argcount ) ;
//_test_call_error(p_method,error);
}
}
bool Object : : has_method ( const StringName & p_method ) const {
if ( p_method = = CoreStringNames : : get_singleton ( ) - > _free ) {
return true ;
}
if ( script_instance & & script_instance - > has_method ( p_method ) ) {
return true ;
}
MethodBind * method = ObjectTypeDB : : get_method ( get_type_name ( ) , p_method ) ;
if ( method ) {
return true ;
}
return false ;
}
Variant Object : : getvar ( const Variant & p_key , bool * r_valid ) const {
if ( r_valid )
* r_valid = false ;
return Variant ( ) ;
}
void Object : : setvar ( const Variant & p_key , const Variant & p_value , bool * r_valid ) {
if ( r_valid )
* r_valid = false ;
}
Variant Object : : callv ( const StringName & p_method , const Array & p_args ) {
if ( p_args . size ( ) = = 0 ) {
return call ( p_method ) ;
}
Vector < Variant > args ;
args . resize ( p_args . size ( ) ) ;
Vector < const Variant * > argptrs ;
argptrs . resize ( p_args . size ( ) ) ;
for ( int i = 0 ; i < p_args . size ( ) ; i + + ) {
args [ i ] = p_args [ i ] ;
argptrs [ i ] = & args [ i ] ;
}
Variant : : CallError ce ;
return call ( p_method , argptrs . ptr ( ) , p_args . size ( ) , ce ) ;
}
Variant Object : : call ( const StringName & p_name , VARIANT_ARG_DECLARE ) {
#if 0
if ( p_name = = CoreStringNames : : get_singleton ( ) - > _free ) {
# ifdef DEBUG_ENABLED
if ( cast_to < Reference > ( ) ) {
ERR_EXPLAIN ( " Can't 'free' a reference. " ) ;
ERR_FAIL_V ( Variant ( ) ) ;
}
# endif
//must be here, must be before everything,
memdelete ( this ) ;
return Variant ( ) ;
}
VARIANT_ARGPTRS ;
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
break ;
argc + + ;
}
Variant : : CallError error ;
Variant ret ;
if ( script_instance ) {
ret = script_instance - > call ( p_name , argptr , argc , error ) ;
if ( _test_call_error ( p_name , error ) )
return ret ;
}
MethodBind * method = ObjectTypeDB : : get_method ( get_type_name ( ) , p_name ) ;
if ( method ) {
Variant ret = method - > call ( this , argptr , argc , error ) ;
if ( _test_call_error ( p_name , error ) )
return ret ;
return ret ;
} else {
}
return Variant ( ) ;
# else
VARIANT_ARGPTRS ;
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
break ;
argc + + ;
}
Variant : : CallError error ;
Variant ret = call ( p_name , argptr , argc , error ) ;
return ret ;
# endif
}
void Object : : call_multilevel ( const StringName & p_name , VARIANT_ARG_DECLARE ) {
#if 0
if ( p_name = = CoreStringNames : : get_singleton ( ) - > _free ) {
# ifdef DEBUG_ENABLED
if ( cast_to < Reference > ( ) ) {
ERR_EXPLAIN ( " Can't 'free' a reference. " ) ;
ERR_FAIL ( ) ;
return ;
}
# endif
//must be here, must be before everything,
memdelete ( this ) ;
return ;
}
VARIANT_ARGPTRS ;
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
break ;
argc + + ;
}
Variant : : CallError error ;
if ( script_instance ) {
script_instance - > call ( p_name , argptr , argc , error ) ;
_test_call_error ( p_name , error ) ;
}
MethodBind * method = ObjectTypeDB : : get_method ( get_type_name ( ) , p_name ) ;
if ( method ) {
method - > call ( this , argptr , argc , error ) ;
_test_call_error ( p_name , error ) ;
}
# else
VARIANT_ARGPTRS ;
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
break ;
argc + + ;
}
//Variant::CallError error;
call_multilevel ( p_name , argptr , argc ) ;
# endif
}
Variant Object : : call ( const StringName & p_method , const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2016-01-04 13:35:21 +01:00
r_error . error = Variant : : CallError : : CALL_OK ;
2014-02-10 02:10:30 +01:00
if ( p_method = = CoreStringNames : : get_singleton ( ) - > _free ) {
//free must be here, before anything, always ready
# ifdef DEBUG_ENABLED
if ( p_argcount ! = 0 ) {
r_error . argument = 0 ;
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS ;
return Variant ( ) ;
}
if ( cast_to < Reference > ( ) ) {
r_error . argument = 0 ;
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_METHOD ;
ERR_EXPLAIN ( " Can't 'free' a reference. " ) ;
ERR_FAIL_V ( Variant ( ) ) ;
}
2014-04-05 17:39:30 +02:00
if ( _lock_index . get ( ) > 1 ) {
r_error . argument = 0 ;
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_METHOD ;
ERR_EXPLAIN ( " Object is locked and can't be freed. " ) ;
ERR_FAIL_V ( Variant ( ) ) ;
}
2014-02-10 02:10:30 +01:00
# endif
//must be here, must be before everything,
memdelete ( this ) ;
r_error . error = Variant : : CallError : : CALL_OK ;
return Variant ( ) ;
}
Variant ret ;
2014-04-05 17:39:30 +02:00
OBJ_DEBUG_LOCK
2014-02-10 02:10:30 +01:00
if ( script_instance ) {
ret = script_instance - > call ( p_method , p_args , p_argcount , r_error ) ;
//force jumptable
switch ( r_error . error ) {
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 ;
case Variant : : CallError : : CALL_ERROR_INSTANCE_IS_NULL : { }
}
}
MethodBind * method = ObjectTypeDB : : get_method ( get_type_name ( ) , p_method ) ;
if ( method ) {
ret = method - > call ( this , p_args , p_argcount , r_error ) ;
} else {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_METHOD ;
}
return ret ;
}
void Object : : notification ( int p_notification , bool p_reversed ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
_notificationv ( p_notification , p_reversed ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( script_instance ) {
script_instance - > notification ( p_notification ) ;
}
}
void Object : : _changed_callback ( Object * p_changed , const char * p_prop ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
}
void Object : : add_change_receptor ( Object * p_receptor ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
change_receptors . insert ( p_receptor ) ;
}
void Object : : remove_change_receptor ( Object * p_receptor ) {
change_receptors . erase ( p_receptor ) ;
}
void Object : : property_list_changed_notify ( ) {
_change_notify ( ) ;
}
void Object : : cancel_delete ( ) {
_predelete_ok = true ;
}
void Object : : set_script ( const RefPtr & p_script ) {
if ( script = = p_script )
return ;
if ( script_instance ) {
memdelete ( script_instance ) ;
script_instance = NULL ;
}
2016-03-09 00:00:52 +01:00
script = p_script ;
2014-02-10 02:10:30 +01:00
Ref < Script > s ( script ) ;
if ( ! s . is_null ( ) & & s - > can_instance ( ) ) {
2014-04-05 17:39:30 +02:00
OBJ_DEBUG_LOCK
2014-02-10 02:10:30 +01:00
script_instance = s - > instance_create ( this ) ;
}
_change_notify ( " script/script " ) ;
emit_signal ( CoreStringNames : : get_singleton ( ) - > script_changed ) ;
}
void Object : : set_script_instance ( ScriptInstance * p_instance ) {
if ( script_instance = = p_instance )
return ;
if ( script_instance )
memdelete ( script_instance ) ;
script_instance = p_instance ;
2015-11-28 16:47:09 +01:00
if ( p_instance )
script = p_instance - > get_script ( ) . get_ref_ptr ( ) ;
else
script = RefPtr ( ) ;
2014-02-10 02:10:30 +01:00
}
RefPtr Object : : get_script ( ) const {
return script ;
}
bool Object : : has_meta ( const String & p_name ) const {
return metadata . has ( p_name ) ;
}
void Object : : set_meta ( const String & p_name , const Variant & p_value ) {
if ( p_value . get_type ( ) = = Variant : : NIL ) {
metadata . erase ( p_name ) ;
return ;
} ;
metadata [ p_name ] = p_value ;
}
Variant Object : : get_meta ( const String & p_name ) const {
ERR_FAIL_COND_V ( ! metadata . has ( p_name ) , Variant ( ) ) ;
return metadata [ p_name ] ;
}
2015-05-25 06:46:45 +02:00
2014-02-10 02:10:30 +01:00
Array Object : : _get_property_list_bind ( ) const {
List < PropertyInfo > lpi ;
get_property_list ( & lpi ) ;
return convert_property_list ( & lpi ) ;
}
2015-05-25 06:46:45 +02:00
2016-01-01 14:27:25 +01:00
static Dictionary _get_dict_from_method ( const MethodInfo & mi ) {
Dictionary d ;
d [ " name " ] = mi . name ;
d [ " args " ] = convert_property_list ( & mi . arguments ) ;
Array da ;
for ( int i = 0 ; i < mi . default_arguments . size ( ) ; i + + )
da . push_back ( mi . default_arguments [ i ] ) ;
d [ " default_args " ] = da ;
d [ " flags " ] = mi . flags ;
d [ " id " ] = mi . id ;
Dictionary r ;
r [ " type " ] = mi . return_val . type ;
r [ " hint " ] = mi . return_val . hint ;
r [ " hint_string " ] = mi . return_val . hint_string ;
d [ " return_type " ] = r ;
return d ;
}
2015-05-25 06:46:45 +02:00
Array Object : : _get_method_list_bind ( ) const {
List < MethodInfo > ml ;
get_method_list ( & ml ) ;
Array ret ;
for ( List < MethodInfo > : : Element * E = ml . front ( ) ; E ; E = E - > next ( ) ) {
2016-01-01 14:27:25 +01:00
Dictionary d = _get_dict_from_method ( E - > get ( ) ) ;
2015-05-25 06:46:45 +02:00
//va.push_back(d);
ret . push_back ( d ) ;
}
return ret ;
}
2014-02-10 02:10:30 +01:00
DVector < String > Object : : _get_meta_list_bind ( ) const {
DVector < String > _metaret ;
List < Variant > keys ;
metadata . get_key_list ( & keys ) ;
for ( List < Variant > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
_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 ) ;
for ( List < Variant > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
p_list - > push_back ( E - > get ( ) ) ;
}
}
void Object : : add_user_signal ( const MethodInfo & p_signal ) {
ERR_FAIL_COND ( p_signal . name = = " " ) ;
ERR_FAIL_COND ( ObjectTypeDB : : has_signal ( get_type_name ( ) , p_signal . name ) ) ;
ERR_FAIL_COND ( signal_map . has ( p_signal . name ) ) ;
Signal s ;
s . user = p_signal ;
signal_map [ p_signal . name ] = s ;
}
2015-03-03 18:39:13 +01:00
bool Object : : _has_user_signal ( const StringName & p_name ) const {
if ( ! signal_map . has ( p_name ) )
return false ;
return signal_map [ p_name ] . user . name . length ( ) > 0 ;
}
2014-02-10 02:10:30 +01:00
struct _ObjectSignalDisconnectData {
StringName signal ;
Object * target ;
StringName method ;
} ;
#if 0
void Object : : _emit_signal ( const StringName & p_name , const Array & p_pargs ) {
Variant args [ VARIANT_ARG_MAX ] ;
int count = p_pargs . size ( ) ;
for ( int i = 0 ; i < count ; i + + ) {
args [ i ] = p_pargs [ i ] ;
}
emit_signal ( p_name , VARIANT_ARGS_FROM_ARRAY ( args ) ) ;
}
# endif
Variant Object : : _emit_signal ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
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 ( ) ) ;
}
r_error . error = Variant : : CallError : : CALL_OK ;
StringName signal = * p_args [ 0 ] ;
2016-01-04 13:35:21 +01:00
const Variant * * args = NULL ;
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
int argc = p_argcount - 1 ;
if ( argc ) {
args = & p_args [ 1 ] ;
2014-02-10 02:10:30 +01:00
}
2016-01-04 13:35:21 +01:00
emit_signal ( signal , args , argc ) ;
2014-02-10 02:10:30 +01:00
return Variant ( ) ;
2016-01-04 13:35:21 +01:00
}
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
void Object : : emit_signal ( const StringName & p_name , const Variant * * p_args , int p_argcount ) {
2014-02-10 02:10:30 +01:00
if ( _block_signals )
return ; //no emit, signals blocked
Signal * s = signal_map . getptr ( p_name ) ;
if ( ! s ) {
return ;
}
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?
VMap < Signal : : Target , Signal : : Slot > slot_map = s - > slot_map ;
int ssize = slot_map . size ( ) ;
2014-04-05 17:39:30 +02:00
OBJ_DEBUG_LOCK
2016-01-04 13:35:21 +01:00
Vector < const Variant * > bind_mem ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < ssize ; i + + ) {
const Connection & c = slot_map . getv ( i ) . conn ;
Object * target ;
# ifdef DEBUG_ENABLED
target = ObjectDB : : get_instance ( slot_map . getk ( i ) . _id ) ;
ERR_CONTINUE ( ! target ) ;
# else
target = c . target ;
# endif
2016-01-04 13:35:21 +01:00
const Variant * * args = p_args ;
int argc = p_argcount ;
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
if ( c . binds . size ( ) ) {
//handle binds
bind_mem . resize ( p_argcount + c . binds . size ( ) ) ;
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
for ( int j = 0 ; j < p_argcount ; j + + ) {
bind_mem [ j ] = p_args [ j ] ;
}
for ( int j = 0 ; j < c . binds . size ( ) ; j + + ) {
bind_mem [ p_argcount + j ] = & c . binds [ j ] ;
2014-02-10 02:10:30 +01:00
}
2016-01-04 13:35:21 +01:00
args = bind_mem . ptr ( ) ;
argc = bind_mem . size ( ) ;
2014-02-10 02:10:30 +01:00
}
if ( c . flags & CONNECT_DEFERRED ) {
2016-01-04 13:35:21 +01:00
MessageQueue : : get_singleton ( ) - > push_call ( target - > get_instance_ID ( ) , c . method , args , argc , true ) ;
2014-02-10 02:10:30 +01:00
} else {
2016-01-04 13:35:21 +01:00
Variant : : CallError ce ;
target - > call ( c . method , args , argc , ce ) ;
if ( ce . error ! = Variant : : CallError : : CALL_OK ) {
if ( ce . error = = Variant : : CallError : : CALL_ERROR_INVALID_METHOD & & ! ObjectTypeDB : : type_exists ( target - > get_type_name ( ) ) ) {
//most likely object is not initialized yet, do not throw error.
} else {
ERR_PRINTS ( " Error calling method from signal ' " + String ( p_name ) + " ': " + Variant : : get_call_error_text ( target , c . method , args , argc , ce ) ) ;
}
}
2014-02-10 02:10:30 +01:00
}
if ( c . flags & CONNECT_ONESHOT ) {
_ObjectSignalDisconnectData dd ;
dd . signal = p_name ;
dd . target = target ;
dd . method = c . method ;
disconnect_data . push_back ( dd ) ;
}
}
2016-01-04 13:35:21 +01:00
while ( ! disconnect_data . empty ( ) ) {
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
const _ObjectSignalDisconnectData & dd = disconnect_data . front ( ) - > get ( ) ;
disconnect ( dd . signal , dd . target , dd . method ) ;
disconnect_data . pop_front ( ) ;
}
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
}
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
void Object : : emit_signal ( const StringName & p_name , VARIANT_ARG_DECLARE ) {
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
VARIANT_ARGPTRS ;
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
int argc = 0 ;
2014-02-10 02:10:30 +01:00
2016-01-04 13:35:21 +01:00
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
break ;
argc + + ;
2014-02-10 02:10:30 +01:00
}
2016-05-22 02:18:16 +02:00
2016-01-04 13:35:21 +01:00
emit_signal ( p_name , argptr , argc ) ;
2014-02-10 02:10:30 +01:00
}
void Object : : _add_user_signal ( const String & p_name , const Array & p_args ) {
// 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 ;
mi . name = p_name ;
for ( int i = 0 ; i < p_args . size ( ) ; i + + ) {
Dictionary d = p_args [ i ] ;
PropertyInfo param ;
if ( d . has ( " name " ) )
param . name = d [ " name " ] ;
if ( d . has ( " type " ) )
param . type = ( Variant : : Type ) ( int ) d [ " type " ] ;
mi . arguments . push_back ( param ) ;
}
add_user_signal ( mi ) ;
}
#if 0
void Object : : _emit_signal ( const StringName & p_name , const Array & p_pargs ) {
Variant args [ VARIANT_ARG_MAX ] ;
int count = p_pargs . size ( ) ;
for ( int i = 0 ; i < count ; i + + ) {
args [ i ] = p_pargs [ i ] ;
}
emit_signal ( p_name , VARIANT_ARGS_FROM_ARRAY ( args ) ) ;
}
# endif
Array Object : : _get_signal_list ( ) const {
2016-01-01 14:27:25 +01:00
List < MethodInfo > signal_list ;
get_signal_list ( & signal_list ) ;
Array ret ;
for ( List < MethodInfo > : : Element * E = signal_list . front ( ) ; E ; E = E - > next ( ) ) {
ret . push_back ( _get_dict_from_method ( E - > get ( ) ) ) ;
}
return ret ;
2014-02-10 02:10:30 +01:00
}
Array Object : : _get_signal_connection_list ( const String & p_signal ) const {
2016-01-01 14:27:25 +01:00
List < Connection > conns ;
get_all_signal_connections ( & conns ) ;
Array ret ;
for ( List < Connection > : : Element * E = conns . front ( ) ; E ; E = E - > next ( ) ) {
Connection & c = E - > get ( ) ;
2016-06-21 13:07:50 +02:00
if ( c . signal = = p_signal ) {
Dictionary rc ;
rc [ " signal " ] = c . signal ;
rc [ " method " ] = c . method ;
rc [ " source " ] = c . source ;
rc [ " target " ] = c . target ;
rc [ " binds " ] = c . binds ;
rc [ " flags " ] = c . flags ;
ret . push_back ( rc ) ;
}
2016-01-01 14:27:25 +01:00
}
return ret ;
2014-02-10 02:10:30 +01:00
}
void Object : : get_signal_list ( List < MethodInfo > * p_signals ) const {
2015-06-24 18:29:23 +02:00
if ( ! script . is_null ( ) ) {
Ref < Script > ( script ) - > get_script_signal_list ( p_signals ) ;
}
2014-02-10 02:10:30 +01:00
ObjectTypeDB : : get_signal_list ( get_type_name ( ) , p_signals ) ;
//find maybe usersignals?
const StringName * S = NULL ;
while ( ( S = signal_map . next ( S ) ) ) {
if ( signal_map [ * S ] . user . name ! = " " ) {
//user signal
p_signals - > push_back ( signal_map [ * S ] . user ) ;
}
}
2015-06-24 18:29:23 +02:00
2014-02-10 02:10:30 +01:00
}
2015-05-10 20:45:33 +02:00
void Object : : get_all_signal_connections ( List < Connection > * p_connections ) const {
const StringName * S = NULL ;
while ( ( S = signal_map . next ( S ) ) ) {
const Signal * s = & signal_map [ * S ] ;
for ( int i = 0 ; i < s - > slot_map . size ( ) ; i + + ) {
p_connections - > push_back ( s - > slot_map . getv ( i ) . conn ) ;
}
}
}
2014-02-10 02:10:30 +01:00
void Object : : get_signal_connection_list ( const StringName & p_signal , List < Connection > * p_connections ) const {
const Signal * s = signal_map . getptr ( p_signal ) ;
if ( ! s )
return ; //nothing
for ( int i = 0 ; i < s - > slot_map . size ( ) ; i + + )
p_connections - > push_back ( s - > slot_map . getv ( i ) . conn ) ;
}
2016-06-04 18:17:56 +02:00
bool Object : : has_persistent_signal_connections ( ) const {
const StringName * S = NULL ;
while ( ( S = signal_map . next ( S ) ) ) {
const Signal * s = & signal_map [ * S ] ;
for ( int i = 0 ; i < s - > slot_map . size ( ) ; i + + ) {
if ( s - > slot_map . getv ( i ) . conn . flags & CONNECT_PERSIST )
return true ;
}
}
return false ;
}
2016-06-07 00:55:50 +02:00
void Object : : get_signals_connected_to_this ( List < Connection > * p_connections ) const {
2016-06-07 07:39:40 +02:00
for ( const List < Connection > : : Element * E = connections . front ( ) ; E ; E = E - > next ( ) ) {
p_connections - > push_back ( E - > get ( ) ) ;
}
2016-06-07 00:55:50 +02:00
}
2014-02-10 02:10:30 +01:00
2014-09-15 16:33:30 +02: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 02:10:30 +01:00
2014-09-15 16:33:30 +02:00
ERR_FAIL_NULL_V ( p_to_object , ERR_INVALID_PARAMETER ) ;
2014-02-10 02:10:30 +01:00
Signal * s = signal_map . getptr ( p_signal ) ;
if ( ! s ) {
bool signal_is_valid = ObjectTypeDB : : has_signal ( get_type_name ( ) , p_signal ) ;
2015-06-24 18:29:23 +02:00
//check in script
if ( ! signal_is_valid & & ! script . is_null ( ) & & Ref < Script > ( script ) - > has_script_signal ( p_signal ) )
signal_is_valid = true ;
2014-02-10 02:10:30 +01:00
if ( ! signal_is_valid ) {
2016-05-23 00:28:37 +02:00
ERR_EXPLAIN ( " In Object of type ' " + String ( get_type ( ) ) + " ': Attempt to connect nonexistent signal ' " + p_signal + " ' to method ' " + p_to_object - > get_type ( ) + " . " + p_to_method + " ' " ) ;
2014-09-15 16:33:30 +02:00
ERR_FAIL_COND_V ( ! signal_is_valid , ERR_INVALID_PARAMETER ) ;
2014-02-10 02:10:30 +01:00
}
signal_map [ p_signal ] = Signal ( ) ;
s = & signal_map [ p_signal ] ;
}
Signal : : Target target ( p_to_object - > get_instance_ID ( ) , p_to_method ) ;
if ( s - > slot_map . has ( target ) ) {
ERR_EXPLAIN ( " Signal ' " + p_signal + " '' already connected to given method ' " + p_to_method + " ' in that object. " ) ;
2014-09-15 16:33:30 +02:00
ERR_FAIL_COND_V ( s - > slot_map . has ( target ) , ERR_INVALID_PARAMETER ) ;
2014-02-10 02:10:30 +01:00
}
Signal : : Slot slot ;
Connection conn ;
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 ) ;
s - > slot_map [ target ] = slot ;
2014-09-15 16:33:30 +02:00
return OK ;
2014-02-10 02:10:30 +01:00
}
bool Object : : is_connected ( const StringName & p_signal , Object * p_to_object , const StringName & p_to_method ) const {
ERR_FAIL_NULL_V ( p_to_object , false ) ;
const Signal * s = signal_map . getptr ( p_signal ) ;
if ( ! s ) {
bool signal_is_valid = ObjectTypeDB : : has_signal ( get_type_name ( ) , p_signal ) ;
if ( signal_is_valid )
return false ;
2015-12-11 11:53:40 +01:00
if ( ! script . is_null ( ) & & Ref < Script > ( script ) - > has_script_signal ( p_signal ) )
return false ;
2015-05-18 15:20:54 +02:00
ERR_EXPLAIN ( " Nonexistent signal: " + p_signal ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND_V ( ! s , false ) ;
}
Signal : : Target target ( p_to_object - > get_instance_ID ( ) , p_to_method ) ;
return s - > slot_map . has ( target ) ;
//const Map<Signal::Target,Signal::Slot>::Element *E = s->slot_map.find(target);
//return (E!=NULL);
}
void Object : : disconnect ( const StringName & p_signal , Object * p_to_object , const StringName & p_to_method ) {
ERR_FAIL_NULL ( p_to_object ) ;
Signal * s = signal_map . getptr ( p_signal ) ;
if ( ! s ) {
2015-05-18 15:20:54 +02:00
ERR_EXPLAIN ( " Nonexistent signal: " + p_signal ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! s ) ;
}
if ( s - > lock > 0 ) {
ERR_EXPLAIN ( " Attempt to disconnect signal ' " + p_signal + " ' while emitting (locks: " + itos ( s - > lock ) + " ) " ) ;
ERR_FAIL_COND ( s - > lock > 0 ) ;
}
Signal : : Target target ( p_to_object - > get_instance_ID ( ) , p_to_method ) ;
if ( ! s - > slot_map . has ( target ) ) {
2015-05-18 15:20:54 +02:00
ERR_EXPLAIN ( " Disconnecting nonexistent signal ' " + p_signal + " ', slot: " + itos ( target . _id ) + " : " + target . method ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL ( ) ;
}
int prev = p_to_object - > connections . size ( ) ;
p_to_object - > connections . erase ( s - > slot_map [ target ] . cE ) ;
s - > slot_map . erase ( target ) ;
if ( s - > slot_map . empty ( ) & & ObjectTypeDB : : has_signal ( get_type_name ( ) , p_signal ) ) {
//not user signal, delete
signal_map . erase ( p_signal ) ;
}
}
void Object : : _set_bind ( const String & p_set , const Variant & p_value ) {
set ( p_set , p_value ) ;
}
Variant Object : : _get_bind ( const String & p_name ) const {
return get ( p_name ) ;
}
void Object : : initialize_type ( ) {
static bool initialized = false ;
if ( initialized )
return ;
ObjectTypeDB : : _add_type < Object > ( ) ;
_bind_methods ( ) ;
initialized = true ;
}
StringName Object : : XL_MESSAGE ( const StringName & p_message ) const {
if ( ! _can_translate | | ! TranslationServer : : get_singleton ( ) )
return p_message ;
return TranslationServer : : get_singleton ( ) - > translate ( p_message ) ;
}
StringName Object : : tr ( const StringName & p_message ) const {
return XL_MESSAGE ( p_message ) ;
}
2015-06-22 05:03:19 +02:00
void Object : : _clear_internal_resource_paths ( const Variant & p_var ) {
switch ( p_var . get_type ( ) ) {
case Variant : : OBJECT : {
RES r = p_var ;
if ( ! r . is_valid ( ) )
return ;
if ( ! r - > get_path ( ) . begins_with ( " res:// " ) | | r - > get_path ( ) . find ( " :: " ) = = - 1 )
return ; //not an internal resource
Object * object = p_var ;
if ( ! object )
return ;
r - > set_path ( " " ) ;
r - > clear_internal_resource_paths ( ) ;
} break ;
case Variant : : ARRAY : {
Array a = p_var ;
for ( int i = 0 ; i < a . size ( ) ; i + + ) {
_clear_internal_resource_paths ( a [ i ] ) ;
}
} break ;
case Variant : : DICTIONARY : {
Dictionary d = p_var ;
List < Variant > keys ;
d . get_key_list ( & keys ) ;
for ( List < Variant > : : Element * E = keys . front ( ) ; E ; E = E - > next ( ) ) {
_clear_internal_resource_paths ( E - > get ( ) ) ;
_clear_internal_resource_paths ( d [ E - > get ( ) ] ) ;
}
} break ;
}
}
void Object : : clear_internal_resource_paths ( ) {
List < PropertyInfo > pinfo ;
get_property_list ( & pinfo ) ;
for ( List < PropertyInfo > : : Element * E = pinfo . front ( ) ; E ; E = E - > next ( ) ) {
_clear_internal_resource_paths ( get ( E - > get ( ) . name ) ) ;
}
}
2014-02-10 02:10:30 +01:00
void Object : : _bind_methods ( ) {
ObjectTypeDB : : bind_method ( _MD ( " get_type " ) , & Object : : get_type ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_type " , " type " ) , & Object : : is_type ) ;
ObjectTypeDB : : bind_method ( _MD ( " set " , " property " , " value " ) , & Object : : _set_bind ) ;
ObjectTypeDB : : bind_method ( _MD ( " get " , " property " ) , & Object : : _get_bind ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_property_list " ) , & Object : : _get_property_list_bind ) ;
2015-05-25 06:46:45 +02:00
ObjectTypeDB : : bind_method ( _MD ( " get_method_list " ) , & Object : : _get_method_list_bind ) ;
2015-12-28 02:13:05 +01:00
ObjectTypeDB : : bind_method ( _MD ( " notification " , " what " , " reversed " ) , & Object : : notification , DEFVAL ( false ) ) ;
2014-02-10 02:10:30 +01:00
ObjectTypeDB : : bind_method ( _MD ( " get_instance_ID " ) , & Object : : get_instance_ID ) ;
ObjectTypeDB : : bind_method ( _MD ( " set_script " , " script:Script " ) , & Object : : set_script ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_script:Script " ) , & Object : : get_script ) ;
ObjectTypeDB : : bind_method ( _MD ( " set_meta " , " name " , " value " ) , & Object : : set_meta ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_meta " , " name " , " value " ) , & Object : : get_meta ) ;
ObjectTypeDB : : bind_method ( _MD ( " has_meta " , " name " ) , & Object : : has_meta ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_meta_list " ) , & Object : : _get_meta_list_bind ) ;
//todo reimplement this per language so all 5 arguments can be called
// ObjectTypeDB::bind_method(_MD("call","method","arg1","arg2","arg3","arg4"),&Object::_call_bind,DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()));
// ObjectTypeDB::bind_method(_MD("call_deferred","method","arg1","arg2","arg3","arg4"),&Object::_call_deferred_bind,DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()),DEFVAL(Variant()));
ObjectTypeDB : : bind_method ( _MD ( " add_user_signal " , " signal " , " arguments " ) , & Object : : _add_user_signal , DEFVAL ( Array ( ) ) ) ;
2015-03-03 18:39:13 +01:00
ObjectTypeDB : : bind_method ( _MD ( " has_user_signal " , " signal " ) , & Object : : _has_user_signal ) ;
2014-02-10 02:10:30 +01:00
// ObjectTypeDB::bind_method(_MD("emit_signal","signal","arguments"),&Object::_emit_signal,DEFVAL(Array()));
{
MethodInfo mi ;
mi . name = " emit_signal " ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING , " signal " ) ) ;
Vector < Variant > defargs ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
mi . arguments . push_back ( PropertyInfo ( Variant : : NIL , " arg " + itos ( i ) ) ) ;
defargs . push_back ( Variant ( ) ) ;
}
ObjectTypeDB : : bind_native_method ( METHOD_FLAGS_DEFAULT , " emit_signal " , & Object : : _emit_signal , mi , defargs ) ;
}
{
MethodInfo mi ;
mi . name = " call " ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING , " method " ) ) ;
Vector < Variant > defargs ;
for ( int i = 0 ; i < 10 ; i + + ) {
mi . arguments . push_back ( PropertyInfo ( Variant : : NIL , " arg " + itos ( i ) ) ) ;
defargs . push_back ( Variant ( ) ) ;
}
ObjectTypeDB : : bind_native_method ( METHOD_FLAGS_DEFAULT , " call " , & Object : : _call_bind , mi , defargs ) ;
}
{
MethodInfo mi ;
mi . name = " call_deferred " ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING , " method " ) ) ;
Vector < Variant > defargs ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
mi . arguments . push_back ( PropertyInfo ( Variant : : NIL , " arg " + itos ( i ) ) ) ;
defargs . push_back ( Variant ( ) ) ;
}
ObjectTypeDB : : bind_native_method ( METHOD_FLAGS_DEFAULT , " call_deferred " , & Object : : _call_deferred_bind , mi , defargs ) ;
}
2015-12-14 12:28:01 +01:00
ObjectTypeDB : : bind_method ( _MD ( " callv:Variant " , " method " , " arg_array " ) , & Object : : callv ) ;
2014-02-10 02:10:30 +01:00
2015-12-28 02:13:05 +01:00
ObjectTypeDB : : bind_method ( _MD ( " has_method " , " method " ) , & Object : : has_method ) ;
2014-02-10 02:10:30 +01:00
ObjectTypeDB : : bind_method ( _MD ( " get_signal_list " ) , & Object : : _get_signal_list ) ;
2016-01-01 14:27:25 +01:00
ObjectTypeDB : : bind_method ( _MD ( " get_signal_connection_list " , " signal " ) , & Object : : _get_signal_connection_list ) ;
2014-02-10 02:10:30 +01:00
ObjectTypeDB : : bind_method ( _MD ( " connect " , " signal " , " target:Object " , " method " , " binds " , " flags " ) , & Object : : connect , DEFVAL ( Array ( ) ) , DEFVAL ( 0 ) ) ;
ObjectTypeDB : : bind_method ( _MD ( " disconnect " , " signal " , " target:Object " , " method " ) , & Object : : disconnect ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_connected " , " signal " , " target:Object " , " method " ) , & Object : : is_connected ) ;
ObjectTypeDB : : bind_method ( _MD ( " set_block_signals " , " enable " ) , & Object : : set_block_signals ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_blocking_signals " ) , & Object : : is_blocking_signals ) ;
ObjectTypeDB : : bind_method ( _MD ( " set_message_translation " , " enable " ) , & Object : : set_message_translation ) ;
2014-10-26 15:07:54 +01:00
ObjectTypeDB : : bind_method ( _MD ( " can_translate_messages " ) , & Object : : can_translate_messages ) ;
2014-02-10 02:10:30 +01:00
ObjectTypeDB : : bind_method ( _MD ( " property_list_changed_notify " ) , & Object : : property_list_changed_notify ) ;
ObjectTypeDB : : bind_method ( _MD ( " XL_MESSAGE " , " message " ) , & Object : : XL_MESSAGE ) ;
ObjectTypeDB : : bind_method ( _MD ( " tr " , " message " ) , & Object : : tr ) ;
2015-03-28 18:34:28 +01:00
ObjectTypeDB : : bind_method ( _MD ( " is_queued_for_deletion " ) , & Object : : is_queued_for_deletion ) ;
2015-04-13 03:22:44 +02:00
ObjectTypeDB : : add_virtual_method ( " Object " , MethodInfo ( " free " ) , false ) ;
2014-02-10 02:10:30 +01:00
ADD_SIGNAL ( MethodInfo ( " script_changed " ) ) ;
BIND_VMETHOD ( MethodInfo ( " _notification " , PropertyInfo ( Variant : : INT , " what " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( " _set " , PropertyInfo ( Variant : : STRING , " property " ) , PropertyInfo ( Variant : : NIL , " value " ) ) ) ;
# ifdef TOOLS_ENABLED
MethodInfo miget ( " _get " , PropertyInfo ( Variant : : STRING , " property " ) ) ;
miget . return_val . name = " var " ;
BIND_VMETHOD ( miget ) ;
MethodInfo plget ( " _get_property_list " ) ;
2014-09-21 06:43:42 +02:00
2014-02-10 02:10:30 +01:00
plget . return_val . type = Variant : : ARRAY ;
BIND_VMETHOD ( plget ) ;
# endif
2014-09-21 06:43:42 +02:00
BIND_VMETHOD ( MethodInfo ( " _init " ) ) ;
2014-02-10 02:10:30 +01:00
BIND_CONSTANT ( NOTIFICATION_POSTINITIALIZE ) ;
BIND_CONSTANT ( NOTIFICATION_PREDELETE ) ;
BIND_CONSTANT ( CONNECT_DEFERRED ) ;
BIND_CONSTANT ( CONNECT_PERSIST ) ;
BIND_CONSTANT ( CONNECT_ONESHOT ) ;
}
void Object : : call_deferred ( const StringName & p_method , VARIANT_ARG_DECLARE ) {
MessageQueue : : get_singleton ( ) - > push_call ( this , p_method , VARIANT_ARG_PASS ) ;
}
void Object : : set_block_signals ( bool p_block ) {
_block_signals = p_block ;
}
bool Object : : is_blocking_signals ( ) const {
return _block_signals ;
}
void Object : : get_translatable_strings ( List < String > * p_strings ) const {
List < PropertyInfo > plist ;
get_property_list ( & plist ) ;
for ( List < PropertyInfo > : : Element * E = plist . front ( ) ; E ; E = E - > next ( ) ) {
if ( ! ( E - > get ( ) . usage & PROPERTY_USAGE_INTERNATIONALIZED ) )
continue ;
String text = get ( E - > get ( ) . name ) ;
if ( text = = " " )
continue ;
p_strings - > push_back ( text ) ;
}
}
2015-12-05 18:18:22 +01:00
Variant : : Type Object : : get_static_property_type ( const StringName & p_property , bool * r_valid ) const {
bool valid ;
Variant : : Type t = ObjectTypeDB : : get_property_type ( get_type_name ( ) , p_property , & valid ) ;
if ( valid ) {
if ( r_valid )
* r_valid = true ;
return t ;
}
if ( get_script_instance ( ) ) {
return get_script_instance ( ) - > get_property_type ( p_property , r_valid ) ;
}
if ( r_valid )
* r_valid = false ;
return Variant : : NIL ;
}
2015-03-28 18:34:28 +01:00
bool Object : : is_queued_for_deletion ( ) const {
return _is_queued_for_deletion ;
}
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
void Object : : set_edited ( bool p_edited ) {
_edited = p_edited ;
2016-05-27 19:18:40 +02:00
_edited_version + + ;
2014-02-10 02:10:30 +01:00
}
bool Object : : is_edited ( ) const {
return _edited ;
}
2016-05-27 19:18:40 +02:00
uint32_t Object : : get_edited_version ( ) const {
return _edited_version ;
}
2014-02-10 02:10:30 +01:00
# endif
Object : : Object ( ) {
2016-03-09 00:00:52 +01:00
2015-06-29 05:29:49 +02:00
_type_ptr = NULL ;
2014-02-10 02:10:30 +01:00
_block_signals = false ;
_predelete_ok = 0 ;
_instance_ID = 0 ;
_instance_ID = ObjectDB : : add_instance ( this ) ;
_can_translate = true ;
2015-03-28 18:34:28 +01:00
_is_queued_for_deletion = false ;
2014-02-10 02:10:30 +01:00
script_instance = NULL ;
# ifdef TOOLS_ENABLED
_edited = false ;
2016-05-27 19:18:40 +02:00
_edited_version = 0 ;
2014-02-10 02:10:30 +01:00
# endif
2014-04-05 17:39:30 +02:00
# ifdef DEBUG_ENABLED
_lock_index . init ( 1 ) ;
# endif
2014-02-10 02:10:30 +01:00
}
Object : : ~ Object ( ) {
if ( script_instance )
memdelete ( script_instance ) ;
script_instance = NULL ;
List < Connection > sconnections ;
const StringName * S = NULL ;
while ( ( S = signal_map . next ( S ) ) ) {
Signal * s = & signal_map [ * S ] ;
ERR_EXPLAIN ( " Attempt to delete an object in the middle of a signal emission from it " ) ;
ERR_CONTINUE ( s - > lock > 0 ) ;
for ( int i = 0 ; i < s - > slot_map . size ( ) ; i + + ) {
sconnections . push_back ( s - > slot_map . getv ( i ) . conn ) ;
}
}
for ( List < Connection > : : Element * E = sconnections . front ( ) ; E ; E = E - > next ( ) ) {
Connection & c = E - > get ( ) ;
ERR_CONTINUE ( c . source ! = this ) ; //bug?
this - > disconnect ( c . signal , c . target , c . method ) ;
}
while ( connections . size ( ) ) {
Connection c = connections . front ( ) - > get ( ) ;
c . source - > disconnect ( c . signal , c . target , c . method ) ;
}
ObjectDB : : remove_instance ( this ) ;
_instance_ID = 0 ;
_predelete_ok = 2 ;
}
bool predelete_handler ( Object * p_object ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return p_object - > _predelete ( ) ;
}
void postinitialize_handler ( Object * p_object ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
p_object - > _postinitialize ( ) ;
}
HashMap < uint32_t , Object * > ObjectDB : : instances ;
uint32_t ObjectDB : : instance_counter = 1 ;
HashMap < Object * , ObjectID , ObjectDB : : ObjectPtrHash > ObjectDB : : instance_checks ;
uint32_t ObjectDB : : add_instance ( Object * p_object ) {
GLOBAL_LOCK_FUNCTION ;
ERR_FAIL_COND_V ( p_object - > get_instance_ID ( ) ! = 0 , 0 ) ;
instances [ + + instance_counter ] = p_object ;
# ifdef DEBUG_ENABLED
instance_checks [ p_object ] = instance_counter ;
# endif
return instance_counter ;
}
void ObjectDB : : remove_instance ( Object * p_object ) {
GLOBAL_LOCK_FUNCTION ;
instances . erase ( p_object - > get_instance_ID ( ) ) ;
# ifdef DEBUG_ENABLED
instance_checks . erase ( p_object ) ;
# endif
}
Object * ObjectDB : : get_instance ( uint32_t p_instance_ID ) {
GLOBAL_LOCK_FUNCTION ;
Object * * obj = instances . getptr ( p_instance_ID ) ;
if ( ! obj )
return NULL ;
return * obj ;
}
void ObjectDB : : debug_objects ( DebugFunc p_func ) {
GLOBAL_LOCK_FUNCTION ;
const uint32_t * K = NULL ;
while ( ( K = instances . next ( K ) ) ) {
p_func ( instances [ * K ] ) ;
}
}
2014-12-17 02:31:57 +01:00
void Object : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
}
2014-02-10 02:10:30 +01:00
int ObjectDB : : get_object_count ( ) {
GLOBAL_LOCK_FUNCTION ;
return instances . size ( ) ;
}
void ObjectDB : : cleanup ( ) {
GLOBAL_LOCK_FUNCTION ;
if ( instances . size ( ) ) {
2016-03-09 00:00:52 +01:00
WARN_PRINT ( " ObjectDB Instances still exist! " ) ;
2015-04-21 00:38:02 +02:00
if ( OS : : get_singleton ( ) - > is_stdout_verbose ( ) ) {
const uint32_t * K = NULL ;
while ( ( K = instances . next ( K ) ) ) {
String node_name ;
if ( instances [ * K ] - > is_type ( " Node " ) )
node_name = " - Node Name: " + String ( instances [ * K ] - > call ( " get_name " ) ) ;
if ( instances [ * K ] - > is_type ( " Resoucre " ) )
node_name = " - Resource Name: " + String ( instances [ * K ] - > call ( " get_name " ) ) + " Path: " + String ( instances [ * K ] - > call ( " get_path " ) ) ;
print_line ( " Leaked Instance: " + String ( instances [ * K ] - > get_type ( ) ) + " : " + itos ( * K ) + node_name ) ;
}
}
2014-02-10 02:10:30 +01:00
}
instances . clear ( ) ;
instance_checks . clear ( ) ;
}