2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* object.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2017-01-01 22:01:57 +01:00
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
2017-04-08 00:11:42 +02:00
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
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. */
/*************************************************************************/
# ifndef OBJECT_H
# define OBJECT_H
# include "list.h"
# include "map.h"
2017-01-07 22:25:37 +01:00
# include "os/rw_lock.h"
2017-03-05 16:44:50 +01:00
# include "set.h"
# include "variant.h"
# include "vmap.h"
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
# define VARIANT_ARG_LIST const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant()
# define VARIANT_ARG_PASS p_arg1, p_arg2, p_arg3, p_arg4, p_arg5
# define VARIANT_ARG_DECLARE const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5
2014-02-10 02:10:30 +01:00
# define VARIANT_ARG_MAX 5
2017-03-05 16:44:50 +01:00
# define VARIANT_ARGPTRS const Variant *argptr[5] = { &p_arg1, &p_arg2, &p_arg3, &p_arg4, &p_arg5 };
# define VARIANT_ARGPTRS_PASS *argptr[0], *argptr[1], *argptr[2], *argptr[3], *argptr[4]
# define VARIANT_ARGS_FROM_ARRAY(m_arr) m_arr[0], m_arr[1], m_arr[2], m_arr[3], m_arr[4]
2014-02-10 02:10:30 +01:00
/**
@ author Juan Linietsky < reduzio @ gmail . com >
*/
enum PropertyHint {
PROPERTY_HINT_NONE , ///< no hint provided.
2015-08-30 02:09:11 +02:00
PROPERTY_HINT_RANGE , ///< hint_text = "min,max,step,slider; //slider is optional"
2014-02-10 02:10:30 +01:00
PROPERTY_HINT_EXP_RANGE , ///< hint_text = "min,max,step", exponential edit
PROPERTY_HINT_ENUM , ///< hint_text= "val1,val2,val3,etc"
2017-03-24 21:45:31 +01:00
PROPERTY_HINT_EXP_EASING , /// exponential easing function (Math::ease)
2014-02-10 02:10:30 +01:00
PROPERTY_HINT_LENGTH , ///< hint_text= "length" (as integer)
2015-05-25 06:46:45 +02:00
PROPERTY_HINT_SPRITE_FRAME ,
2014-02-10 02:10:30 +01:00
PROPERTY_HINT_KEY_ACCEL , ///< hint_text= "length" (as integer)
PROPERTY_HINT_FLAGS , ///< hint_text= "flag1,flag2,etc" (as bit flags)
2017-01-11 02:20:57 +01:00
PROPERTY_HINT_LAYERS_2D_RENDER ,
PROPERTY_HINT_LAYERS_2D_PHYSICS ,
PROPERTY_HINT_LAYERS_3D_RENDER ,
PROPERTY_HINT_LAYERS_3D_PHYSICS ,
2015-08-30 02:09:11 +02:00
PROPERTY_HINT_FILE , ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
2014-02-10 02:10:30 +01:00
PROPERTY_HINT_DIR , ///< a directort path must be passed
PROPERTY_HINT_GLOBAL_FILE , ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
PROPERTY_HINT_GLOBAL_DIR , ///< a directort path must be passed
PROPERTY_HINT_RESOURCE_TYPE , ///< a resource object type
2015-08-30 02:09:11 +02:00
PROPERTY_HINT_MULTILINE_TEXT , ///< used for string properties that can contain multiple lines
2014-02-10 02:10:30 +01:00
PROPERTY_HINT_COLOR_NO_ALPHA , ///< used for ignoring alpha component when editing a color
PROPERTY_HINT_IMAGE_COMPRESS_LOSSY ,
PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS ,
2016-05-23 00:28:37 +02:00
PROPERTY_HINT_OBJECT_ID ,
2016-08-03 00:11:05 +02:00
PROPERTY_HINT_TYPE_STRING , ///< a type string, the hint is the base type to choose
PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE , ///< so something else can provide this (used in scripts)
2016-08-24 00:29:07 +02:00
PROPERTY_HINT_METHOD_OF_VARIANT_TYPE , ///< a method of a type
PROPERTY_HINT_METHOD_OF_BASE_TYPE , ///< a method of a base type
PROPERTY_HINT_METHOD_OF_INSTANCE , ///< a method of an instance
PROPERTY_HINT_METHOD_OF_SCRIPT , ///< a method of a script & base
PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE , ///< a property of a type
PROPERTY_HINT_PROPERTY_OF_BASE_TYPE , ///< a property of a base type
PROPERTY_HINT_PROPERTY_OF_INSTANCE , ///< a property of an instance
PROPERTY_HINT_PROPERTY_OF_SCRIPT , ///< a property of a script & base
2017-08-18 15:59:31 +02:00
PROPERTY_HINT_OBJECT_TOO_BIG , ///< object is too big to send
2014-02-10 02:10:30 +01:00
PROPERTY_HINT_MAX ,
} ;
enum PropertyUsageFlags {
2015-08-30 02:09:11 +02:00
2017-03-05 16:44:50 +01:00
PROPERTY_USAGE_STORAGE = 1 ,
PROPERTY_USAGE_EDITOR = 2 ,
PROPERTY_USAGE_NETWORK = 4 ,
PROPERTY_USAGE_EDITOR_HELPER = 8 ,
PROPERTY_USAGE_CHECKABLE = 16 , //used for editing global variables
PROPERTY_USAGE_CHECKED = 32 , //used for editing global variables
PROPERTY_USAGE_INTERNATIONALIZED = 64 , //hint for internationalized strings
PROPERTY_USAGE_GROUP = 128 , //used for grouping props in the editor
PROPERTY_USAGE_CATEGORY = 256 ,
PROPERTY_USAGE_STORE_IF_NONZERO = 512 , //only store if nonzero
PROPERTY_USAGE_STORE_IF_NONONE = 1024 , //only store if false
PROPERTY_USAGE_NO_INSTANCE_STATE = 2048 ,
PROPERTY_USAGE_RESTART_IF_CHANGED = 4096 ,
PROPERTY_USAGE_SCRIPT_VARIABLE = 8192 ,
PROPERTY_USAGE_STORE_IF_NULL = 16384 ,
PROPERTY_USAGE_ANIMATE_AS_TRIGGER = 32768 ,
PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED = 65536 ,
2017-08-06 14:32:52 +02:00
PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE = 1 < < 17 ,
2017-08-24 00:10:32 +02:00
PROPERTY_USAGE_CLASS_IS_ENUM = 1 < < 18 ,
PROPERTY_USAGE_NIL_IS_VARIANT = 1 < < 19 ,
2017-03-05 16:44:50 +01:00
PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK ,
PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED ,
PROPERTY_USAGE_NOEDITOR = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK ,
2014-02-10 02:10:30 +01:00
} ;
2017-03-05 16:44:50 +01:00
# define ADD_SIGNAL(m_signal) ClassDB::add_signal(get_class_static(), m_signal)
# define ADD_PROPERTY(m_property, m_setter, m_getter) ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter))
# define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter), m_index)
# define ADD_PROPERTYNZ(m_property, m_setter, m_getter) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONZERO), _scs_create(m_setter), _scs_create(m_getter))
# define ADD_PROPERTYINZ(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONZERO), _scs_create(m_setter), _scs_create(m_getter), m_index)
# define ADD_PROPERTYNO(m_property, m_setter, m_getter) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), _scs_create(m_setter), _scs_create(m_getter))
# define ADD_PROPERTYINO(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), _scs_create(m_setter), _scs_create(m_getter), m_index)
# define ADD_GROUP(m_name, m_prefix) ClassDB::add_property_group(get_class_static(), m_name, m_prefix)
2014-02-10 02:10:30 +01:00
struct PropertyInfo {
2015-08-30 02:09:11 +02:00
Variant : : Type type ;
2014-02-10 02:10:30 +01:00
String name ;
2017-08-24 00:10:32 +02:00
StringName class_name ; //for classes
2014-02-10 02:10:30 +01:00
PropertyHint hint ;
2015-08-30 02:09:11 +02:00
String hint_string ;
2014-02-10 02:10:30 +01:00
uint32_t usage ;
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ PropertyInfo added_usage ( int p_fl ) const {
PropertyInfo pi = * this ;
pi . usage | = p_fl ;
return pi ;
}
2016-08-25 22:45:20 +02:00
operator Dictionary ( ) const ;
2017-03-05 16:44:50 +01:00
static PropertyInfo from_dict ( const Dictionary & p_dict ) ;
2016-08-25 22:45:20 +02:00
2017-07-31 01:07:04 +02:00
PropertyInfo ( )
: type ( Variant : : NIL ) ,
hint ( PROPERTY_HINT_NONE ) ,
usage ( PROPERTY_USAGE_DEFAULT ) {
2017-03-05 16:44:50 +01:00
}
2017-08-24 00:10:32 +02:00
PropertyInfo ( Variant : : Type p_type , const String p_name , PropertyHint p_hint = PROPERTY_HINT_NONE , const String & p_hint_string = " " , uint32_t p_usage = PROPERTY_USAGE_DEFAULT , const StringName & p_class_name = StringName ( ) )
2017-07-31 01:07:04 +02:00
: type ( p_type ) ,
name ( p_name ) ,
hint ( p_hint ) ,
hint_string ( p_hint_string ) ,
usage ( p_usage ) {
2017-08-24 00:10:32 +02:00
if ( hint = = PROPERTY_HINT_RESOURCE_TYPE ) {
class_name = hint_string ;
} else {
class_name = p_class_name ;
}
}
PropertyInfo ( const StringName & p_class_name )
: type ( Variant : : OBJECT ) ,
hint ( PROPERTY_HINT_NONE ) ,
usage ( PROPERTY_USAGE_DEFAULT ) {
class_name = p_class_name ;
2014-02-10 02:10:30 +01:00
}
2017-08-24 00:10:32 +02:00
2017-03-05 16:44:50 +01:00
bool operator < ( const PropertyInfo & p_info ) const {
return name < p_info . name ;
2015-05-01 02:53:41 +02:00
}
2014-02-10 02:10:30 +01:00
} ;
2017-03-05 16:44:50 +01:00
Array convert_property_list ( const List < PropertyInfo > * p_list ) ;
2014-02-10 02:10:30 +01:00
struct MethodInfo {
2015-08-30 02:09:11 +02:00
2014-02-10 02:10:30 +01:00
String name ;
List < PropertyInfo > arguments ;
Vector < Variant > default_arguments ;
PropertyInfo return_val ;
uint32_t flags ;
int id ;
2015-08-30 02:09:11 +02:00
2017-08-26 21:41:25 +02:00
inline bool operator = = ( const MethodInfo & p_method ) const { return id = = p_method . id ; }
2017-03-05 16:44:50 +01:00
inline bool operator < ( const MethodInfo & p_method ) const { return id = = p_method . id ? ( name < p_method . name ) : ( id < p_method . id ) ; }
2015-08-30 02:09:11 +02:00
2016-08-25 22:45:20 +02:00
operator Dictionary ( ) const ;
2017-03-05 16:44:50 +01:00
static MethodInfo from_dict ( const Dictionary & p_dict ) ;
2014-02-10 02:10:30 +01:00
MethodInfo ( ) ;
2017-03-05 16:44:50 +01:00
MethodInfo ( const String & p_name ) ;
MethodInfo ( const String & p_name , const PropertyInfo & p_param1 ) ;
MethodInfo ( const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 ) ;
MethodInfo ( const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 ) ;
MethodInfo ( const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 , const PropertyInfo & p_param4 ) ;
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 ) ;
2014-02-10 02:10:30 +01:00
MethodInfo ( Variant : : Type ret ) ;
2017-03-05 16:44:50 +01:00
MethodInfo ( Variant : : Type ret , const String & p_name ) ;
MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 ) ;
MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 ) ;
MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 ) ;
MethodInfo ( Variant : : Type ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 , const PropertyInfo & p_param4 ) ;
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 ) ;
2017-08-29 07:15:46 +02:00
MethodInfo ( const PropertyInfo & p_ret , const String & p_name ) ;
MethodInfo ( const PropertyInfo & p_ret , const String & p_name , const PropertyInfo & p_param1 ) ;
MethodInfo ( const PropertyInfo & p_ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 ) ;
MethodInfo ( const PropertyInfo & p_ret , const String & p_name , const PropertyInfo & p_param1 , const PropertyInfo & p_param2 , const PropertyInfo & p_param3 ) ;
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 ) ;
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 ) ;
2014-02-10 02:10:30 +01:00
} ;
// old cast_to
2017-01-03 03:03:46 +01:00
//if ( is_type(T::get_class_static()) )
2014-02-10 02:10:30 +01:00
//return static_cast<T*>(this);
////else
//return NULL;
/*
2015-08-30 02:09:11 +02:00
the following is an uncomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C + + . As a plus , this macro pretty much alone defines the object model .
2014-02-10 02:10:30 +01:00
*/
2017-03-05 16:44:50 +01:00
# define REVERSE_GET_PROPERTY_LIST \
public : \
_FORCE_INLINE_ bool _is_gpl_reversed ( ) const { return true ; } ; \
\
2014-02-10 02:10:30 +01:00
private :
2017-03-05 16:44:50 +01:00
# define UNREVERSE_GET_PROPERTY_LIST \
public : \
_FORCE_INLINE_ bool _is_gpl_reversed ( ) const { return false ; } ; \
\
2014-02-10 02:10:30 +01:00
private :
2017-03-05 16:44:50 +01:00
# define GDCLASS(m_class, m_inherits) \
private : \
void operator = ( const m_class & p_rval ) { } \
mutable StringName _class_name ; \
friend class ClassDB ; \
\
public : \
virtual String get_class ( ) const { \
return String ( # m_class ) ; \
} \
virtual const StringName * _get_class_namev ( ) const { \
if ( ! _class_name ) \
_class_name = get_class_static ( ) ; \
return & _class_name ; \
} \
static _FORCE_INLINE_ void * get_class_ptr_static ( ) { \
static int ptr ; \
return & ptr ; \
} \
static _FORCE_INLINE_ String get_class_static ( ) { \
return String ( # m_class ) ; \
} \
static _FORCE_INLINE_ String get_parent_class_static ( ) { \
return m_inherits : : get_class_static ( ) ; \
} \
static void get_inheritance_list_static ( List < String > * p_inheritance_list ) { \
m_inherits : : get_inheritance_list_static ( p_inheritance_list ) ; \
p_inheritance_list - > push_back ( String ( # m_class ) ) ; \
} \
static String get_category_static ( ) { \
String category = m_inherits : : get_category_static ( ) ; \
if ( _get_category ! = m_inherits : : _get_category ) { \
if ( category ! = " " ) \
category + = " / " ; \
category + = _get_category ( ) ; \
} \
return category ; \
} \
static String inherits_static ( ) { \
return String ( # m_inherits ) ; \
} \
virtual bool is_class ( const String & p_class ) const { return ( p_class = = ( # m_class ) ) ? true : m_inherits : : is_class ( p_class ) ; } \
virtual bool is_class_ptr ( void * p_ptr ) const { return ( p_ptr = = get_class_ptr_static ( ) ) ? true : m_inherits : : is_class_ptr ( p_ptr ) ; } \
\
static void get_valid_parents_static ( List < String > * p_parents ) { \
\
if ( m_class : : _get_valid_parents_static ! = m_inherits : : _get_valid_parents_static ) { \
m_class : : _get_valid_parents_static ( p_parents ) ; \
} \
\
m_inherits : : get_valid_parents_static ( p_parents ) ; \
} \
\
protected : \
_FORCE_INLINE_ static void ( * _get_bind_methods ( ) ) ( ) { \
return & m_class : : _bind_methods ; \
} \
\
public : \
static void initialize_class ( ) { \
static bool initialized = false ; \
if ( initialized ) \
return ; \
m_inherits : : initialize_class ( ) ; \
ClassDB : : _add_class < m_class > ( ) ; \
if ( m_class : : _get_bind_methods ( ) ! = m_inherits : : _get_bind_methods ( ) ) \
_bind_methods ( ) ; \
initialized = true ; \
} \
\
protected : \
virtual void _initialize_classv ( ) { \
initialize_class ( ) ; \
} \
_FORCE_INLINE_ bool ( Object : : * ( _get_get ( ) const ) ) ( const StringName & p_name , Variant & ) const { \
return ( bool ( Object : : * ) ( const StringName & , Variant & ) const ) & m_class : : _get ; \
} \
virtual bool _getv ( const StringName & p_name , Variant & r_ret ) const { \
if ( m_class : : _get_get ( ) ! = m_inherits : : _get_get ( ) ) { \
if ( _get ( p_name , r_ret ) ) \
return true ; \
} \
return m_inherits : : _getv ( p_name , r_ret ) ; \
} \
_FORCE_INLINE_ bool ( Object : : * ( _get_set ( ) const ) ) ( const StringName & p_name , const Variant & p_property ) { \
return ( bool ( Object : : * ) ( const StringName & , const Variant & ) ) & m_class : : _set ; \
} \
virtual bool _setv ( const StringName & p_name , const Variant & p_property ) { \
if ( m_inherits : : _setv ( p_name , p_property ) ) return true ; \
if ( m_class : : _get_set ( ) ! = m_inherits : : _get_set ( ) ) { \
return _set ( p_name , p_property ) ; \
} \
return false ; \
} \
_FORCE_INLINE_ void ( Object : : * ( _get_get_property_list ( ) const ) ) ( List < PropertyInfo > * p_list ) const { \
return ( void ( Object : : * ) ( List < PropertyInfo > * ) const ) & m_class : : _get_property_list ; \
} \
virtual void _get_property_listv ( List < PropertyInfo > * p_list , bool p_reversed ) const { \
if ( ! p_reversed ) { \
m_inherits : : _get_property_listv ( p_list , p_reversed ) ; \
} \
p_list - > push_back ( PropertyInfo ( Variant : : NIL , get_class_static ( ) , PROPERTY_HINT_NONE , String ( ) , PROPERTY_USAGE_CATEGORY ) ) ; \
if ( ! _is_gpl_reversed ( ) ) \
ClassDB : : get_property_list ( # m_class , p_list , true , this ) ; \
if ( m_class : : _get_get_property_list ( ) ! = m_inherits : : _get_get_property_list ( ) ) { \
_get_property_list ( p_list ) ; \
} \
if ( _is_gpl_reversed ( ) ) \
ClassDB : : get_property_list ( # m_class , p_list , true , this ) ; \
if ( p_reversed ) { \
m_inherits : : _get_property_listv ( p_list , p_reversed ) ; \
} \
} \
_FORCE_INLINE_ void ( Object : : * ( _get_notification ( ) const ) ) ( int ) { \
return ( void ( Object : : * ) ( int ) ) & m_class : : _notification ; \
} \
virtual void _notificationv ( int p_notification , bool p_reversed ) { \
if ( ! p_reversed ) \
m_inherits : : _notificationv ( p_notification , p_reversed ) ; \
if ( m_class : : _get_notification ( ) ! = m_inherits : : _get_notification ( ) ) { \
_notification ( p_notification ) ; \
} \
if ( p_reversed ) \
m_inherits : : _notificationv ( p_notification , p_reversed ) ; \
} \
\
2014-02-10 02:10:30 +01:00
private :
2017-03-05 16:44:50 +01:00
# define OBJ_CATEGORY(m_category) \
protected : \
_FORCE_INLINE_ static String _get_category ( ) { return m_category ; } \
\
2014-02-10 02:10:30 +01:00
private :
2017-03-05 16:44:50 +01:00
# define OBJ_SAVE_TYPE(m_class) \
public : \
virtual String get_save_class ( ) const { return # m_class ; } \
\
2014-02-10 02:10:30 +01:00
private :
class ScriptInstance ;
2017-06-09 05:23:50 +02:00
typedef uint64_t ObjectID ;
2014-02-10 02:10:30 +01:00
2015-08-30 02:09:11 +02:00
class Object {
2014-02-10 02:10:30 +01:00
public :
enum ConnectFlags {
2017-03-05 16:44:50 +01:00
CONNECT_DEFERRED = 1 ,
CONNECT_PERSIST = 2 , // hint for scene to save this connection
CONNECT_ONESHOT = 4
2014-02-10 02:10:30 +01:00
} ;
struct Connection {
Object * source ;
StringName signal ;
Object * target ;
StringName method ;
uint32_t flags ;
Vector < Variant > binds ;
2017-03-05 16:44:50 +01:00
bool operator < ( const Connection & p_conn ) const ;
2014-02-10 02:10:30 +01:00
operator Variant ( ) const ;
2017-03-05 16:44:50 +01:00
Connection ( ) {
source = NULL ;
target = NULL ;
flags = 0 ;
}
Connection ( const Variant & p_variant ) ;
2014-02-10 02:10:30 +01:00
} ;
2017-03-05 16:44:50 +01:00
2014-02-10 02:10:30 +01:00
private :
2017-07-16 17:39:23 +02:00
enum {
MAX_SCRIPT_INSTANCE_BINDINGS = 8
} ;
2014-04-05 17:39:30 +02:00
# ifdef DEBUG_ENABLED
2017-03-05 16:44:50 +01:00
friend class _ObjectDebugLock ;
2014-04-05 17:39:30 +02:00
# endif
2017-03-05 16:44:50 +01:00
friend bool predelete_handler ( Object * ) ;
friend void postinitialize_handler ( Object * ) ;
2014-02-10 02:10:30 +01:00
struct Signal {
struct Target {
ObjectID _id ;
StringName method ;
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ bool operator < ( const Target & p_target ) const { return ( _id = = p_target . _id ) ? ( method < p_target . method ) : ( _id < p_target . _id ) ; }
2014-02-10 02:10:30 +01:00
2017-07-31 01:07:04 +02:00
Target ( const ObjectID & p_id , const StringName & p_method )
: _id ( p_id ) ,
method ( p_method ) {
2017-03-05 16:44:50 +01:00
}
Target ( ) { _id = 0 ; }
2014-02-10 02:10:30 +01:00
} ;
struct Slot {
Connection conn ;
List < Connection > : : Element * cE ;
} ;
MethodInfo user ;
2017-03-05 16:44:50 +01:00
VMap < Target , Slot > slot_map ;
2014-02-10 02:10:30 +01:00
int lock ;
2017-03-05 16:44:50 +01:00
Signal ( ) { lock = 0 ; }
2014-02-10 02:10:30 +01:00
} ;
2017-03-05 16:44:50 +01:00
HashMap < StringName , Signal , StringNameHasher > signal_map ;
2014-02-10 02:10:30 +01:00
List < Connection > connections ;
2014-04-05 17:39:30 +02:00
# ifdef DEBUG_ENABLED
SafeRefCount _lock_index ;
# endif
2014-02-10 02:10:30 +01:00
bool _block_signals ;
int _predelete_ok ;
2017-03-05 16:44:50 +01:00
Set < Object * > change_receptors ;
2017-06-09 05:23:50 +02:00
ObjectID _instance_ID ;
2014-02-10 02:10:30 +01:00
bool _predelete ( ) ;
void _postinitialize ( ) ;
bool _can_translate ;
# ifdef TOOLS_ENABLED
bool _edited ;
2016-05-27 19:18:40 +02:00
uint32_t _edited_version ;
2017-06-25 22:30:28 +02:00
Set < String > editor_section_folding ;
2014-02-10 02:10:30 +01:00
# endif
ScriptInstance * script_instance ;
RefPtr script ;
Dictionary metadata ;
2017-01-03 03:03:46 +01:00
mutable StringName _class_name ;
2017-03-05 16:44:50 +01:00
mutable const StringName * _class_ptr ;
2014-02-10 02:10:30 +01:00
2017-08-11 21:10:05 +02:00
void _add_user_signal ( const String & p_name , const Array & p_args = Array ( ) ) ;
2017-03-05 16:44:50 +01:00
bool _has_user_signal ( const StringName & p_name ) const ;
Variant _emit_signal ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) ;
2014-02-10 02:10:30 +01:00
Array _get_signal_list ( ) const ;
2017-03-05 16:44:50 +01:00
Array _get_signal_connection_list ( const String & p_signal ) const ;
2017-06-15 15:31:57 +02:00
Array _get_incoming_connections ( ) const ;
2017-03-05 16:44:50 +01:00
void _set_bind ( const String & p_set , const Variant & p_value ) ;
Variant _get_bind ( const String & p_name ) const ;
2014-02-10 02:10:30 +01:00
2017-07-16 17:39:23 +02:00
void * _script_instance_bindings [ MAX_SCRIPT_INSTANCE_BINDINGS ] ;
2014-02-10 02:10:30 +01:00
void property_list_changed_notify ( ) ;
2015-08-30 02:09:11 +02:00
protected :
2017-01-03 03:03:46 +01:00
virtual void _initialize_classv ( ) { initialize_class ( ) ; }
2017-03-05 16:44:50 +01:00
virtual bool _setv ( const StringName & p_name , const Variant & p_property ) { return false ; } ;
virtual bool _getv ( const StringName & p_name , Variant & r_property ) const { return false ; } ;
virtual void _get_property_listv ( List < PropertyInfo > * p_list , bool p_reversed ) const { } ;
virtual void _notificationv ( int p_notification , bool p_reversed ) { } ;
2015-08-30 02:09:11 +02:00
2014-02-10 02:10:30 +01:00
static String _get_category ( ) { return " " ; }
static void _bind_methods ( ) ;
2017-03-05 16:44:50 +01:00
bool _set ( const StringName & p_name , const Variant & p_property ) { return false ; } ;
bool _get ( const StringName & p_name , Variant & r_property ) const { return false ; } ;
2014-02-10 02:10:30 +01:00
void _get_property_list ( List < PropertyInfo > * p_list ) const { } ;
2017-03-05 16:44:50 +01:00
void _notification ( int p_notification ) { } ;
2015-08-30 02:09:11 +02:00
2014-02-10 02:10:30 +01:00
_FORCE_INLINE_ static void ( * _get_bind_methods ( ) ) ( ) {
return & Object : : _bind_methods ;
}
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ bool ( Object : : * ( _get_get ( ) const ) ) ( const StringName & p_name , Variant & r_ret ) const {
2014-02-10 02:10:30 +01:00
return & Object : : _get ;
}
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ bool ( Object : : * ( _get_set ( ) const ) ) ( const StringName & p_name , const Variant & p_property ) {
return & Object : : _set ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ void ( Object : : * ( _get_get_property_list ( ) const ) ) ( List < PropertyInfo > * p_list ) const {
return & Object : : _get_property_list ;
2015-08-30 02:09:11 +02:00
}
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ void ( Object : : * ( _get_notification ( ) const ) ) ( int ) {
return & Object : : _notification ;
2015-08-30 02:09:11 +02:00
}
2014-02-10 02:10:30 +01:00
static void get_valid_parents_static ( List < String > * p_parents ) ;
static void _get_valid_parents_static ( List < String > * p_parents ) ;
2015-08-30 02:09:11 +02:00
2014-02-10 02:10:30 +01:00
void cancel_delete ( ) ;
2017-03-05 16:44:50 +01:00
virtual void _changed_callback ( Object * p_changed , const char * p_prop ) ;
2014-02-10 02:10:30 +01:00
//Variant _call_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant());
//void _call_deferred_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant());
2017-03-05 16:44:50 +01:00
Variant _call_bind ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) ;
Variant _call_deferred_bind ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
virtual const StringName * _get_class_namev ( ) const {
2017-01-03 03:03:46 +01:00
if ( ! _class_name )
2017-03-05 16:44:50 +01:00
_class_name = get_class_static ( ) ;
2017-01-03 03:03:46 +01:00
return & _class_name ;
2015-06-29 05:29:49 +02:00
}
2014-02-10 02:10:30 +01:00
2017-01-07 22:25:37 +01:00
PoolVector < String > _get_meta_list_bind ( ) const ;
2014-02-10 02:10:30 +01:00
Array _get_property_list_bind ( ) const ;
2015-05-25 06:46:45 +02:00
Array _get_method_list_bind ( ) const ;
2014-02-10 02:10:30 +01:00
2015-06-22 05:03:19 +02:00
void _clear_internal_resource_paths ( const Variant & p_var ) ;
2017-03-05 16:44:50 +01:00
friend class ClassDB ;
virtual void _validate_property ( PropertyInfo & property ) const ;
2016-05-15 04:48:23 +02:00
2014-02-10 02:10:30 +01:00
public : //should be protected, but bug in clang++
2017-01-03 03:03:46 +01:00
static void initialize_class ( ) ;
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ static void register_custom_data_to_otdb ( ) { } ;
2014-02-10 02:10:30 +01:00
public :
# ifdef TOOLS_ENABLED
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ void _change_notify ( const char * p_property = " " ) {
_edited = true ;
for ( Set < Object * > : : Element * E = change_receptors . front ( ) ; E ; E = E - > next ( ) )
( ( Object * ) ( E - > get ( ) ) ) - > _changed_callback ( this , p_property ) ;
}
2014-02-10 02:10:30 +01:00
# else
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ void _change_notify ( const char * p_what = " " ) { }
2014-02-10 02:10:30 +01:00
# endif
2017-03-05 16:44:50 +01:00
static void * get_class_ptr_static ( ) {
2014-02-10 02:10:30 +01:00
static int ptr ;
return & ptr ;
}
bool _is_gpl_reversed ( ) const { return false ; }
2017-08-07 12:17:31 +02:00
_FORCE_INLINE_ ObjectID get_instance_id ( ) const { return _instance_ID ; }
2014-02-10 02:10:30 +01:00
// this is used for editors
2017-03-05 16:44:50 +01:00
void add_change_receptor ( Object * p_receptor ) ;
void remove_change_receptor ( Object * p_receptor ) ;
2015-08-30 02:09:11 +02:00
2017-08-24 21:58:13 +02:00
template < class T >
static T * cast_to ( Object * p_object ) {
# ifdef DEBUG_ENABLED
// TODO there are some legitimate reasons to pass NULL as p_object.
// we need to figure out how to deal with that in debug mode.
// This code will return NULL for a NULL input in release mode also.
ERR_FAIL_COND_V ( p_object = = NULL , NULL ) ;
# endif
# ifndef NO_SAFE_CAST
return dynamic_cast < T * > ( p_object ) ;
# else
if ( ! p_object )
return NULL ;
2017-08-26 17:10:58 +02:00
if ( p_object - > is_class_ptr ( T : : get_class_ptr_static ( ) ) )
return static_cast < T * > ( p_object ) ;
2017-08-24 21:58:13 +02:00
else
return NULL ;
# endif
}
template < class T >
static const T * cast_to ( const Object * p_object ) {
# ifdef DEBUG_ENABLED
// TODO there are some legitimate reasons to pass NULL as p_object.
// we need to figure out how to deal with that in debug mode.
// This code will return NULL for a NULL input in release mode also.
ERR_FAIL_COND_V ( p_object = = NULL , NULL ) ;
# endif
# ifndef NO_SAFE_CAST
return dynamic_cast < const T * > ( p_object ) ;
# else
if ( ! p_object )
return NULL ;
2017-08-26 17:10:58 +02:00
if ( p_object - > is_class_ptr ( T : : get_class_ptr_static ( ) ) )
2017-08-24 21:58:13 +02:00
return static_cast < const T * > ( p_object ) ;
else
return NULL ;
# endif
}
2014-02-10 02:10:30 +01:00
enum {
2015-08-30 02:09:11 +02:00
2017-03-05 16:44:50 +01:00
NOTIFICATION_POSTINITIALIZE = 0 ,
NOTIFICATION_PREDELETE = 1
2014-02-10 02:10:30 +01:00
} ;
2015-08-30 02:09:11 +02:00
2014-02-10 02:10:30 +01:00
/* TYPE API */
2017-03-05 16:44:50 +01:00
static void get_inheritance_list_static ( List < String > * p_inheritance_list ) { p_inheritance_list - > push_back ( " Object " ) ; }
2014-02-10 02:10:30 +01:00
2017-01-03 03:03:46 +01:00
static String get_class_static ( ) { return " Object " ; }
static String get_parent_class_static ( ) { return String ( ) ; }
2014-02-10 02:10:30 +01:00
static String get_category_static ( ) { return String ( ) ; }
2017-01-03 03:03:46 +01:00
virtual String get_class ( ) const { return " Object " ; }
virtual String get_save_class ( ) const { return get_class ( ) ; } //class stored when saving
2015-06-29 05:29:49 +02:00
2017-03-05 16:44:50 +01:00
virtual bool is_class ( const String & p_class ) const { return ( p_class = = " Object " ) ; }
virtual bool is_class_ptr ( void * p_ptr ) const { return get_class_ptr_static ( ) = = p_ptr ; }
2015-06-29 05:29:49 +02:00
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ const StringName & get_class_name ( ) const {
2017-01-03 03:03:46 +01:00
if ( ! _class_ptr ) {
return * _get_class_namev ( ) ;
2015-06-29 05:29:49 +02:00
} else {
2017-01-03 03:03:46 +01:00
return * _class_ptr ;
2015-06-29 05:29:49 +02:00
}
}
2015-08-30 02:09:11 +02:00
2014-02-10 02:10:30 +01:00
/* IAPI */
2017-01-14 12:26:56 +01:00
//void set(const String& p_name, const Variant& p_value);
//Variant get(const String& p_name) const;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
void set ( const StringName & p_name , const Variant & p_value , bool * r_valid = NULL ) ;
Variant get ( const StringName & p_name , bool * r_valid = NULL ) const ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
void get_property_list ( List < PropertyInfo > * p_list , bool p_reversed = false ) const ;
2015-08-30 02:09:11 +02:00
2017-03-05 16:44:50 +01:00
bool has_method ( const StringName & p_method ) const ;
2014-02-10 02:10:30 +01:00
void get_method_list ( List < MethodInfo > * p_list ) const ;
2017-03-05 16:44:50 +01:00
Variant callv ( const StringName & p_method , const Array & p_args ) ;
virtual Variant call ( const StringName & p_method , const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) ;
virtual void call_multilevel ( const StringName & p_method , const Variant * * p_args , int p_argcount ) ;
virtual void call_multilevel_reversed ( const StringName & p_method , const Variant * * p_args , int p_argcount ) ;
Variant call ( const StringName & p_name , VARIANT_ARG_LIST ) ; // C++ helper
void call_multilevel ( const StringName & p_name , VARIANT_ARG_LIST ) ; // C++ helper
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
void notification ( int p_notification , bool p_reversed = false ) ;
2014-02-10 02:10:30 +01:00
//used mainly by script, get and set all INCLUDING string
2017-03-05 16:44:50 +01:00
virtual Variant getvar ( const Variant & p_key , bool * r_valid = NULL ) const ;
virtual void setvar ( const Variant & p_key , const Variant & p_value , bool * r_valid = NULL ) ;
2014-02-10 02:10:30 +01:00
/* SCRIPT */
2015-08-30 02:09:11 +02:00
2017-03-05 16:44:50 +01:00
void set_script ( const RefPtr & p_script ) ;
2014-02-10 02:10:30 +01:00
RefPtr get_script ( ) const ;
/* SCRIPT */
2017-03-05 16:44:50 +01:00
bool has_meta ( const String & p_name ) const ;
void set_meta ( const String & p_name , const Variant & p_value ) ;
Variant get_meta ( const String & p_name ) const ;
2014-02-10 02:10:30 +01:00
void get_meta_list ( List < String > * p_list ) const ;
# ifdef TOOLS_ENABLED
void set_edited ( bool p_edited ) ;
bool is_edited ( ) const ;
2016-05-27 19:18:40 +02:00
uint32_t get_edited_version ( ) const ; //this function is used to check when something changed beyond a point, it's used mainly for generating previews
2014-02-10 02:10:30 +01:00
# endif
void set_script_instance ( ScriptInstance * p_instance ) ;
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ ScriptInstance * get_script_instance ( ) const { return script_instance ; }
2014-02-10 02:10:30 +01:00
2017-07-22 21:57:56 +02:00
void set_script_and_instance ( const RefPtr & p_script , ScriptInstance * p_instance ) ; //some script languages can't control instance creation, so this function eases the process
2017-03-05 16:44:50 +01:00
void add_user_signal ( const MethodInfo & p_signal ) ;
2017-08-06 00:48:29 +02:00
Error emit_signal ( const StringName & p_name , VARIANT_ARG_LIST ) ;
Error emit_signal ( const StringName & p_name , const Variant * * p_args , int p_argcount ) ;
2017-03-05 16:44:50 +01:00
void get_signal_list ( List < MethodInfo > * p_signals ) const ;
void get_signal_connection_list ( const StringName & p_signal , List < Connection > * p_connections ) const ;
2015-05-10 20:45:33 +02:00
void get_all_signal_connections ( List < Connection > * p_connections ) const ;
2016-06-04 18:17:56 +02:00
bool has_persistent_signal_connections ( ) const ;
2016-06-07 07:39:40 +02:00
void get_signals_connected_to_this ( List < Connection > * p_connections ) const ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Error connect ( const StringName & p_signal , Object * p_to_object , const StringName & p_to_method , const Vector < Variant > & p_binds = Vector < Variant > ( ) , uint32_t p_flags = 0 ) ;
void disconnect ( const StringName & p_signal , Object * p_to_object , const StringName & p_to_method ) ;
bool is_connected ( const StringName & p_signal , Object * p_to_object , const StringName & p_to_method ) const ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
void call_deferred ( const StringName & p_method , VARIANT_ARG_LIST ) ;
2014-02-10 02:10:30 +01:00
void set_block_signals ( bool p_block ) ;
bool is_blocking_signals ( ) const ;
2017-03-05 16:44:50 +01:00
Variant : : Type get_static_property_type ( const StringName & p_property , bool * r_valid = NULL ) const ;
2015-12-05 18:18:22 +01:00
2014-02-10 02:10:30 +01:00
virtual void get_translatable_strings ( List < String > * p_strings ) const ;
2017-03-05 16:44:50 +01:00
virtual void get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const ;
2014-02-10 02:10:30 +01:00
2017-08-18 22:29:15 +02:00
StringName tr ( const StringName & p_message ) const ; // translate message (internationalization)
2014-02-10 02:10:30 +01:00
2015-03-28 18:42:01 +01:00
bool _is_queued_for_deletion ; // set to true by SceneTree::queue_delete()
2015-08-30 02:09:11 +02:00
bool is_queued_for_deletion ( ) const ;
2015-03-28 18:34:28 +01:00
2017-08-18 22:29:15 +02:00
_FORCE_INLINE_ void set_message_translation ( bool p_enable ) { _can_translate = p_enable ; }
2014-02-10 02:10:30 +01:00
_FORCE_INLINE_ bool can_translate_messages ( ) const { return _can_translate ; }
2015-06-22 05:03:19 +02:00
2017-06-25 22:30:28 +02:00
# ifdef TOOLS_ENABLED
void editor_set_section_unfold ( const String & p_section , bool p_unfolded ) ;
bool editor_is_section_unfolded ( const String & p_section ) ;
# endif
2017-07-16 17:39:23 +02:00
//used by script languages to store binding data
void * get_script_instance_binding ( int p_script_language_index ) ;
2015-06-22 05:03:19 +02:00
void clear_internal_resource_paths ( ) ;
2015-08-30 02:09:11 +02:00
Object ( ) ;
2014-02-10 02:10:30 +01:00
virtual ~ Object ( ) ;
} ;
bool predelete_handler ( Object * p_object ) ;
void postinitialize_handler ( Object * p_object ) ;
class ObjectDB {
struct ObjectPtrHash {
static _FORCE_INLINE_ uint32_t hash ( const Object * p_obj ) {
union {
2017-03-05 16:44:50 +01:00
const Object * p ;
2014-02-10 02:10:30 +01:00
unsigned long i ;
} u ;
2017-03-05 16:44:50 +01:00
u . p = p_obj ;
2017-02-15 14:41:16 +01:00
return HashMapHasherDefault : : hash ( ( uint64_t ) u . i ) ;
2014-02-10 02:10:30 +01:00
}
} ;
2017-06-09 05:23:50 +02:00
static HashMap < ObjectID , Object * > instances ;
2017-03-05 16:44:50 +01:00
static HashMap < Object * , ObjectID , ObjectPtrHash > instance_checks ;
2014-02-10 02:10:30 +01:00
2017-06-09 05:23:50 +02:00
static ObjectID instance_counter ;
2017-03-05 16:44:50 +01:00
friend class Object ;
friend void unregister_core_types ( ) ;
2017-01-07 22:25:37 +01:00
static RWLock * rw_lock ;
2014-02-10 02:10:30 +01:00
static void cleanup ( ) ;
2017-06-09 05:23:50 +02:00
static ObjectID add_instance ( Object * p_object ) ;
2014-02-10 02:10:30 +01:00
static void remove_instance ( Object * p_object ) ;
2017-03-05 16:44:50 +01:00
friend void register_core_types ( ) ;
2017-01-07 22:25:37 +01:00
static void setup ( ) ;
2015-08-30 02:09:11 +02:00
public :
2014-02-10 02:10:30 +01:00
typedef void ( * DebugFunc ) ( Object * p_obj ) ;
2017-06-09 05:23:50 +02:00
static Object * get_instance ( ObjectID p_instance_ID ) ;
2014-02-10 02:10:30 +01:00
static void debug_objects ( DebugFunc p_func ) ;
static int get_object_count ( ) ;
# ifdef DEBUG_ENABLED
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ static bool instance_validate ( Object * p_ptr ) {
2014-02-10 02:10:30 +01:00
return instance_checks . has ( p_ptr ) ;
}
# else
2017-03-05 16:44:50 +01:00
_FORCE_INLINE_ static bool instance_validate ( Object * p_ptr ) { return true ; }
2014-02-10 02:10:30 +01:00
# endif
} ;
//needed by macros
2017-01-16 08:04:19 +01:00
# include "class_db.h"
2014-02-10 02:10:30 +01:00
# endif