2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* node.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2020-01-01 10:16:22 +00:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 01:10:30 +00:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "node.h"
2017-08-27 19:07:15 +00:00
2017-09-06 12:21:19 +00:00
# include "core/core_string_names.h"
2018-09-11 16:13:45 +00:00
# include "core/io/resource_loader.h"
# include "core/message_queue.h"
# include "core/print_string.h"
2017-03-05 15:44:50 +00:00
# include "instance_placeholder.h"
2014-02-10 01:10:30 +00:00
# include "scene/resources/packed_scene.h"
2017-03-05 15:44:50 +00:00
# include "scene/scene_string_names.h"
2014-04-10 03:18:27 +00:00
# include "viewport.h"
2014-02-10 01:10:30 +00:00
2018-12-18 01:53:54 +00:00
# ifdef TOOLS_ENABLED
# include "editor/editor_settings.h"
# endif
2014-02-10 01:10:30 +00:00
VARIANT_ENUM_CAST ( Node : : PauseMode ) ;
2019-04-17 20:46:21 +00:00
int Node : : orphan_node_count = 0 ;
2014-02-10 01:10:30 +00:00
void Node : : _notification ( int p_notification ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
switch ( p_notification ) {
2014-02-10 01:10:30 +00:00
case NOTIFICATION_PROCESS : {
if ( get_script_instance ( ) ) {
2017-03-05 15:44:50 +00:00
Variant time = get_process_delta_time ( ) ;
const Variant * ptr [ 1 ] = { & time } ;
get_script_instance ( ) - > call_multilevel ( SceneStringNames : : get_singleton ( ) - > _process , ptr , 1 ) ;
2014-02-10 01:10:30 +00:00
}
} break ;
2017-09-30 14:19:07 +00:00
case NOTIFICATION_PHYSICS_PROCESS : {
2014-02-10 01:10:30 +00:00
if ( get_script_instance ( ) ) {
2017-09-30 14:19:07 +00:00
Variant time = get_physics_process_delta_time ( ) ;
2017-03-05 15:44:50 +00:00
const Variant * ptr [ 1 ] = { & time } ;
2017-09-30 14:19:07 +00:00
get_script_instance ( ) - > call_multilevel ( SceneStringNames : : get_singleton ( ) - > _physics_process , ptr , 1 ) ;
2014-02-10 01:10:30 +00:00
}
} break ;
2014-11-06 00:20:42 +00:00
case NOTIFICATION_ENTER_TREE : {
2019-06-22 12:52:51 +00:00
ERR_FAIL_COND ( ! get_viewport ( ) ) ;
ERR_FAIL_COND ( ! get_tree ( ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( data . pause_mode = = PAUSE_MODE_INHERIT ) {
2014-02-10 01:10:30 +00:00
if ( data . parent )
2017-03-05 15:44:50 +00:00
data . pause_owner = data . parent - > data . pause_owner ;
2014-02-10 01:10:30 +00:00
else
2017-03-05 15:44:50 +00:00
data . pause_owner = NULL ;
2014-02-10 01:10:30 +00:00
} else {
2017-03-05 15:44:50 +00:00
data . pause_owner = this ;
2014-02-10 01:10:30 +00:00
}
2014-04-10 03:18:27 +00:00
if ( data . input )
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-04-10 03:18:27 +00:00
if ( data . unhandled_input )
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-04-10 03:18:27 +00:00
if ( data . unhandled_key_input )
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-04-10 03:18:27 +00:00
2014-11-06 00:20:42 +00:00
get_tree ( ) - > node_count + + ;
2019-04-17 20:46:21 +00:00
orphan_node_count - - ;
2014-02-10 01:10:30 +00:00
} break ;
2014-11-06 00:20:42 +00:00
case NOTIFICATION_EXIT_TREE : {
2019-06-22 12:52:51 +00:00
ERR_FAIL_COND ( ! get_viewport ( ) ) ;
ERR_FAIL_COND ( ! get_tree ( ) ) ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
get_tree ( ) - > node_count - - ;
2019-04-17 20:46:21 +00:00
orphan_node_count + + ;
2014-04-10 03:18:27 +00:00
if ( data . input )
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-04-10 03:18:27 +00:00
if ( data . unhandled_input )
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-04-10 03:18:27 +00:00
if ( data . unhandled_key_input )
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
data . pause_owner = NULL ;
2016-08-14 21:49:50 +00:00
if ( data . path_cache ) {
memdelete ( data . path_cache ) ;
2017-03-05 15:44:50 +00:00
data . path_cache = NULL ;
2016-08-14 21:49:50 +00:00
}
} break ;
case NOTIFICATION_PATH_CHANGED : {
if ( data . path_cache ) {
memdelete ( data . path_cache ) ;
2017-03-05 15:44:50 +00:00
data . path_cache = NULL ;
2016-08-14 21:49:50 +00:00
}
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_READY : {
if ( get_script_instance ( ) ) {
2017-01-10 21:02:19 +00:00
if ( get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _input ) ) {
set_process_input ( true ) ;
}
if ( get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _unhandled_input ) ) {
set_process_unhandled_input ( true ) ;
}
if ( get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _unhandled_key_input ) ) {
set_process_unhandled_key_input ( true ) ;
}
if ( get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _process ) ) {
set_process ( true ) ;
}
2017-09-30 14:19:07 +00:00
if ( get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _physics_process ) ) {
set_physics_process ( true ) ;
2017-01-10 21:02:19 +00:00
}
2017-03-05 15:44:50 +00:00
get_script_instance ( ) - > call_multilevel_reversed ( SceneStringNames : : get_singleton ( ) - > _ready , NULL , 0 ) ;
2014-02-10 01:10:30 +00:00
}
} break ;
case NOTIFICATION_POSTINITIALIZE : {
2017-03-05 15:44:50 +00:00
data . in_constructor = false ;
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_PREDELETE : {
set_owner ( NULL ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( data . owned . size ( ) ) {
2016-03-08 23:00:52 +00:00
data . owned . front ( ) - > get ( ) - > set_owner ( NULL ) ;
2014-02-10 01:10:30 +00:00
}
if ( data . parent ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . parent - > remove_child ( this ) ;
}
// kill children as cleanly as possible
2017-03-05 15:44:50 +00:00
while ( data . children . size ( ) ) {
2016-03-08 23:00:52 +00:00
2018-11-18 14:47:19 +00:00
Node * child = data . children [ data . children . size ( ) - 1 ] ; //begin from the end because its faster and more consistent with creation
2014-02-10 01:10:30 +00:00
remove_child ( child ) ;
2017-03-05 15:44:50 +00:00
memdelete ( child ) ;
2014-02-10 01:10:30 +00:00
}
} break ;
}
}
void Node : : _propagate_ready ( ) {
2017-03-05 15:44:50 +00:00
data . ready_notified = true ;
2014-02-10 01:10:30 +00:00
data . blocked + + ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
data . children [ i ] - > _propagate_ready ( ) ;
}
data . blocked - - ;
2018-05-15 20:12:35 +00:00
notification ( NOTIFICATION_POST_ENTER_TREE ) ;
2017-01-10 21:02:19 +00:00
if ( data . ready_first ) {
2017-03-05 15:44:50 +00:00
data . ready_first = false ;
2017-12-14 11:59:46 +00:00
notification ( NOTIFICATION_READY ) ;
2018-01-20 21:57:59 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > ready ) ;
2017-01-10 21:02:19 +00:00
}
2014-02-10 01:10:30 +00:00
}
2014-11-06 00:20:42 +00:00
void Node : : _propagate_enter_tree ( ) {
2018-01-18 20:37:17 +00:00
// this needs to happen to all children before any enter_tree
2014-02-10 01:10:30 +00:00
if ( data . parent ) {
2017-03-05 15:44:50 +00:00
data . tree = data . parent - > data . tree ;
data . depth = data . parent - > data . depth + 1 ;
2014-02-10 01:10:30 +00:00
} else {
2017-03-05 15:44:50 +00:00
data . depth = 1 ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-08-24 20:58:51 +00:00
data . viewport = Object : : cast_to < Viewport > ( this ) ;
2019-07-20 06:09:57 +00:00
if ( ! data . viewport & & data . parent )
2014-04-10 03:18:27 +00:00
data . viewport = data . parent - > data . viewport ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . inside_tree = true ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( Map < StringName , GroupData > : : Element * E = data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
E - > get ( ) . group = data . tree - > add_to_group ( E - > key ( ) , this ) ;
2014-02-10 01:10:30 +00:00
}
2014-11-06 00:20:42 +00:00
notification ( NOTIFICATION_ENTER_TREE ) ;
2014-02-10 01:10:30 +00:00
if ( get_script_instance ( ) ) {
2017-03-05 15:44:50 +00:00
get_script_instance ( ) - > call_multilevel_reversed ( SceneStringNames : : get_singleton ( ) - > _enter_tree , NULL , 0 ) ;
2014-02-10 01:10:30 +00:00
}
2017-01-12 03:51:08 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > tree_entered ) ;
2014-02-10 01:10:30 +00:00
2017-10-19 00:30:27 +00:00
data . tree - > node_added ( this ) ;
2014-02-10 01:10:30 +00:00
data . blocked + + ;
//block while adding children
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2016-03-08 23:00:52 +00:00
2014-11-06 00:20:42 +00:00
if ( ! data . children [ i ] - > is_inside_tree ( ) ) // could have been added in enter_tree
data . children [ i ] - > _propagate_enter_tree ( ) ;
2016-03-08 23:00:52 +00:00
}
2014-02-10 01:10:30 +00:00
data . blocked - - ;
2015-08-02 15:29:37 +00:00
# ifdef DEBUG_ENABLED
2017-03-05 15:44:50 +00:00
if ( ScriptDebugger : : get_singleton ( ) & & data . filename ! = String ( ) ) {
2015-08-02 15:29:37 +00:00
//used for live edit
data . tree - > live_scene_edit_cache [ data . filename ] . insert ( this ) ;
}
# endif
2014-02-10 01:10:30 +00:00
// enter groups
}
2018-09-07 18:31:19 +00:00
void Node : : _propagate_after_exit_tree ( ) {
data . blocked + + ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > _propagate_after_exit_tree ( ) ;
}
data . blocked - - ;
emit_signal ( SceneStringNames : : get_singleton ( ) - > tree_exited ) ;
}
2014-11-06 00:20:42 +00:00
void Node : : _propagate_exit_tree ( ) {
2014-02-10 01:10:30 +00:00
2018-08-21 19:28:06 +00:00
//block while removing children
2014-02-10 01:10:30 +00:00
2015-08-02 15:29:37 +00:00
# ifdef DEBUG_ENABLED
2017-03-05 15:44:50 +00:00
if ( ScriptDebugger : : get_singleton ( ) & & data . filename ! = String ( ) ) {
2015-08-02 15:29:37 +00:00
//used for live edit
2017-03-05 15:44:50 +00:00
Map < String , Set < Node * > > : : Element * E = data . tree - > live_scene_edit_cache . find ( data . filename ) ;
2015-08-02 15:29:37 +00:00
if ( E ) {
E - > get ( ) . erase ( this ) ;
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) . size ( ) = = 0 ) {
2015-08-02 15:29:37 +00:00
data . tree - > live_scene_edit_cache . erase ( E ) ;
}
}
2015-08-02 23:28:10 +00:00
2017-03-05 15:44:50 +00:00
Map < Node * , Map < ObjectID , Node * > > : : Element * F = data . tree - > live_edit_remove_list . find ( this ) ;
2015-08-02 23:28:10 +00:00
if ( F ) {
2017-03-05 15:44:50 +00:00
for ( Map < ObjectID , Node * > : : Element * G = F - > get ( ) . front ( ) ; G ; G = G - > next ( ) ) {
2015-08-02 23:28:10 +00:00
memdelete ( G - > get ( ) ) ;
}
data . tree - > live_edit_remove_list . erase ( F ) ;
}
2015-08-02 15:29:37 +00:00
}
# endif
2014-02-10 01:10:30 +00:00
data . blocked + + ;
2017-03-05 15:44:50 +00:00
for ( int i = data . children . size ( ) - 1 ; i > = 0 ; i - - ) {
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
data . children [ i ] - > _propagate_exit_tree ( ) ;
2014-02-10 01:10:30 +00:00
}
data . blocked - - ;
if ( get_script_instance ( ) ) {
2017-03-05 15:44:50 +00:00
get_script_instance ( ) - > call_multilevel ( SceneStringNames : : get_singleton ( ) - > _exit_tree , NULL , 0 ) ;
2014-02-10 01:10:30 +00:00
}
2018-01-12 11:28:39 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > tree_exiting ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
notification ( NOTIFICATION_EXIT_TREE , true ) ;
2014-11-06 00:20:42 +00:00
if ( data . tree )
data . tree - > node_removed ( this ) ;
2014-02-10 01:10:30 +00:00
// exit groups
2017-03-05 15:44:50 +00:00
for ( Map < StringName , GroupData > : : Element * E = data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
data . tree - > remove_from_group ( E - > key ( ) , this ) ;
E - > get ( ) . group = NULL ;
2014-02-10 01:10:30 +00:00
}
2014-04-10 03:18:27 +00:00
data . viewport = NULL ;
2014-11-06 00:20:42 +00:00
if ( data . tree )
data . tree - > tree_changed ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . inside_tree = false ;
data . ready_notified = false ;
data . tree = NULL ;
data . depth = - 1 ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : move_child ( Node * p_child , int p_pos ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_NULL ( p_child ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_INDEX_MSG ( p_pos , data . children . size ( ) + 1 , " Invalid new child position: " + itos ( p_pos ) + " . " ) ;
ERR_FAIL_COND_MSG ( p_child - > data . parent ! = this , " Child is not a child of this node. " ) ;
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, move_child() failed. Consider using call_deferred( \" move_child \" ) instead (or \" popup \" if this is from a popup). " ) ;
2016-06-14 01:46:18 +00:00
2017-07-25 03:11:00 +00:00
// Specifying one place beyond the end
// means the same as moving to the last position
if ( p_pos = = data . children . size ( ) )
p_pos - - ;
2017-03-05 15:44:50 +00:00
if ( p_child - > data . pos = = p_pos )
2016-10-03 19:33:42 +00:00
return ; //do nothing
2017-03-05 15:44:50 +00:00
int motion_from = MIN ( p_pos , p_child - > data . pos ) ;
int motion_to = MAX ( p_pos , p_child - > data . pos ) ;
2016-10-03 19:33:42 +00:00
2017-03-05 15:44:50 +00:00
data . children . remove ( p_child - > data . pos ) ;
data . children . insert ( p_pos , p_child ) ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree ) {
data . tree - > tree_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
data . blocked + + ;
//new pos first
2017-03-05 15:44:50 +00:00
for ( int i = motion_from ; i < = motion_to ; i + + ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . children [ i ] - > data . pos = i ;
2014-02-10 01:10:30 +00:00
}
// notification second
2014-12-03 05:29:28 +00:00
move_child_notify ( p_child ) ;
2017-03-05 15:44:50 +00:00
for ( int i = motion_from ; i < = motion_to ; i + + ) {
data . children [ i ] - > notification ( NOTIFICATION_MOVED_IN_PARENT ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
for ( const Map < StringName , GroupData > : : Element * E = p_child - > data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
2017-12-23 11:16:27 +00:00
if ( E - > get ( ) . group )
E - > get ( ) . group - > changed = true ;
2016-06-08 01:08:12 +00:00
}
2014-02-10 01:10:30 +00:00
data . blocked - - ;
}
void Node : : raise ( ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( ! data . parent )
return ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . parent - > move_child ( this , data . parent - > data . children . size ( ) - 1 ) ;
2014-02-10 01:10:30 +00:00
}
void Node : : add_child_notify ( Node * p_child ) {
2016-03-08 23:00:52 +00:00
// to be used when not wanted
2014-02-10 01:10:30 +00:00
}
void Node : : remove_child_notify ( Node * p_child ) {
2016-03-08 23:00:52 +00:00
// to be used when not wanted
2014-02-10 01:10:30 +00:00
}
2014-12-03 04:17:23 +00:00
void Node : : move_child_notify ( Node * p_child ) {
2016-03-08 23:00:52 +00:00
// to be used when not wanted
2014-12-03 04:17:23 +00:00
}
2017-09-30 14:19:07 +00:00
void Node : : set_physics_process ( bool p_process ) {
2016-03-08 23:00:52 +00:00
2017-09-30 14:19:07 +00:00
if ( data . physics_process = = p_process )
2014-02-10 01:10:30 +00:00
return ;
2017-09-30 14:19:07 +00:00
data . physics_process = p_process ;
2016-03-08 23:00:52 +00:00
2017-09-30 14:19:07 +00:00
if ( data . physics_process )
add_to_group ( " physics_process " , false ) ;
2014-02-10 01:10:30 +00:00
else
2017-09-30 14:19:07 +00:00
remove_from_group ( " physics_process " ) ;
2016-03-08 23:00:52 +00:00
2017-09-30 14:19:07 +00:00
_change_notify ( " physics_process " ) ;
2014-02-10 01:10:30 +00:00
}
2017-09-30 14:19:07 +00:00
bool Node : : is_physics_processing ( ) const {
2017-01-10 21:02:19 +00:00
2017-09-30 14:19:07 +00:00
return data . physics_process ;
2017-01-10 21:02:19 +00:00
}
2017-09-30 14:19:07 +00:00
void Node : : set_physics_process_internal ( bool p_process_internal ) {
2017-01-10 21:02:19 +00:00
2017-09-30 14:19:07 +00:00
if ( data . physics_process_internal = = p_process_internal )
2017-01-10 21:02:19 +00:00
return ;
2017-09-30 14:19:07 +00:00
data . physics_process_internal = p_process_internal ;
2017-01-10 21:02:19 +00:00
2017-09-30 14:19:07 +00:00
if ( data . physics_process_internal )
add_to_group ( " physics_process_internal " , false ) ;
2017-01-10 21:02:19 +00:00
else
2017-09-30 14:19:07 +00:00
remove_from_group ( " physics_process_internal " ) ;
2017-01-10 21:02:19 +00:00
2017-09-30 14:19:07 +00:00
_change_notify ( " physics_process_internal " ) ;
2017-01-10 21:02:19 +00:00
}
2017-09-30 14:19:07 +00:00
bool Node : : is_physics_processing_internal ( ) const {
2017-01-10 21:02:19 +00:00
2017-09-30 14:19:07 +00:00
return data . physics_process_internal ;
2017-01-10 21:02:19 +00:00
}
2014-02-10 01:10:30 +00:00
void Node : : set_pause_mode ( PauseMode p_mode ) {
2017-03-05 15:44:50 +00:00
if ( data . pause_mode = = p_mode )
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
bool prev_inherits = data . pause_mode = = PAUSE_MODE_INHERIT ;
data . pause_mode = p_mode ;
2014-11-06 00:20:42 +00:00
if ( ! is_inside_tree ( ) )
2014-02-10 01:10:30 +00:00
return ; //pointless
2017-03-05 15:44:50 +00:00
if ( ( data . pause_mode = = PAUSE_MODE_INHERIT ) = = prev_inherits )
2014-02-10 01:10:30 +00:00
return ; ///nothing changed
2017-03-05 15:44:50 +00:00
Node * owner = NULL ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( data . pause_mode = = PAUSE_MODE_INHERIT ) {
2014-02-10 01:10:30 +00:00
if ( data . parent )
2017-03-05 15:44:50 +00:00
owner = data . parent - > data . pause_owner ;
2014-02-10 01:10:30 +00:00
} else {
2017-03-05 15:44:50 +00:00
owner = this ;
2014-02-10 01:10:30 +00:00
}
_propagate_pause_owner ( owner ) ;
}
Node : : PauseMode Node : : get_pause_mode ( ) const {
return data . pause_mode ;
}
2017-03-05 15:44:50 +00:00
void Node : : _propagate_pause_owner ( Node * p_owner ) {
2014-02-10 01:10:30 +00:00
2017-05-06 00:37:17 +00:00
if ( this ! = p_owner & & data . pause_mode ! = PAUSE_MODE_INHERIT )
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
data . pause_owner = p_owner ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
data . children [ i ] - > _propagate_pause_owner ( p_owner ) ;
}
}
2017-07-03 13:44:45 +00:00
void Node : : set_network_master ( int p_peer_id , bool p_recursive ) {
2016-08-14 21:49:50 +00:00
2017-07-03 13:44:45 +00:00
data . network_master = p_peer_id ;
2016-08-14 21:49:50 +00:00
2017-07-03 13:44:45 +00:00
if ( p_recursive ) {
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2016-08-14 21:49:50 +00:00
2017-07-03 13:44:45 +00:00
data . children [ i ] - > set_network_master ( p_peer_id , true ) ;
}
2016-08-14 21:49:50 +00:00
}
}
2017-07-03 13:44:45 +00:00
int Node : : get_network_master ( ) const {
2016-08-14 21:49:50 +00:00
2017-07-03 13:44:45 +00:00
return data . network_master ;
2016-08-14 21:49:50 +00:00
}
bool Node : : is_network_master ( ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , false ) ;
2016-08-14 21:49:50 +00:00
2018-05-08 08:51:04 +00:00
return get_multiplayer ( ) - > get_network_unique_id ( ) = = data . network_master ;
2016-08-14 21:49:50 +00:00
}
2016-08-19 19:48:08 +00:00
/***** RPC CONFIG ********/
2016-08-14 21:49:50 +00:00
2018-05-13 05:07:56 +00:00
void Node : : rpc_config ( const StringName & p_method , MultiplayerAPI : : RPCMode p_mode ) {
2016-08-14 21:49:50 +00:00
2018-05-13 05:07:56 +00:00
if ( p_mode = = MultiplayerAPI : : RPC_MODE_DISABLED ) {
2016-08-19 19:48:08 +00:00
data . rpc_methods . erase ( p_method ) ;
} else {
2017-03-05 15:44:50 +00:00
data . rpc_methods [ p_method ] = p_mode ;
2016-08-19 19:48:08 +00:00
} ;
2016-08-14 21:49:50 +00:00
}
2018-05-13 05:07:56 +00:00
void Node : : rset_config ( const StringName & p_property , MultiplayerAPI : : RPCMode p_mode ) {
2016-08-19 19:48:08 +00:00
2018-05-13 05:07:56 +00:00
if ( p_mode = = MultiplayerAPI : : RPC_MODE_DISABLED ) {
2016-08-19 19:48:08 +00:00
data . rpc_properties . erase ( p_property ) ;
} else {
2017-03-05 15:44:50 +00:00
data . rpc_properties [ p_property ] = p_mode ;
2016-08-19 19:48:08 +00:00
} ;
2016-08-14 21:49:50 +00:00
}
2016-08-19 19:48:08 +00:00
/***** RPC FUNCTIONS ********/
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
void Node : : rpc ( const StringName & p_method , VARIANT_ARG_DECLARE ) {
2016-08-14 21:49:50 +00:00
2016-08-19 19:48:08 +00:00
VARIANT_ARGPTRS ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
2016-08-19 19:48:08 +00:00
break ;
argc + + ;
2016-08-14 21:49:50 +00:00
}
2016-08-19 19:48:08 +00:00
2017-03-05 15:44:50 +00:00
rpcp ( 0 , false , p_method , argptr , argc ) ;
2016-08-14 21:49:50 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : rpc_id ( int p_peer_id , const StringName & p_method , VARIANT_ARG_DECLARE ) {
2016-08-14 21:49:50 +00:00
VARIANT_ARGPTRS ;
2017-03-05 15:44:50 +00:00
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
2016-08-14 21:49:50 +00:00
break ;
argc + + ;
}
2017-03-05 15:44:50 +00:00
rpcp ( p_peer_id , false , p_method , argptr , argc ) ;
2016-08-14 21:49:50 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : rpc_unreliable ( const StringName & p_method , VARIANT_ARG_DECLARE ) {
2016-08-19 19:48:08 +00:00
VARIANT_ARGPTRS ;
2017-03-05 15:44:50 +00:00
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
2016-08-19 19:48:08 +00:00
break ;
argc + + ;
}
2017-03-05 15:44:50 +00:00
rpcp ( 0 , true , p_method , argptr , argc ) ;
2016-08-14 21:49:50 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : rpc_unreliable_id ( int p_peer_id , const StringName & p_method , VARIANT_ARG_DECLARE ) {
2016-08-14 21:49:50 +00:00
VARIANT_ARGPTRS ;
2017-03-05 15:44:50 +00:00
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL )
2016-08-14 21:49:50 +00:00
break ;
argc + + ;
}
2017-03-05 15:44:50 +00:00
rpcp ( p_peer_id , true , p_method , argptr , argc ) ;
2016-08-14 21:49:50 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Node : : _rpc_bind ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
if ( p_argcount < 1 ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 1 ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : STRING ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2016-08-14 21:49:50 +00:00
2016-08-19 19:48:08 +00:00
StringName method = * p_args [ 0 ] ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
rpcp ( 0 , false , method , & p_args [ 1 ] , p_argcount - 1 ) ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
r_error . error = Variant : : CallError : : CALL_OK ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
2016-08-14 21:49:50 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Node : : _rpc_id_bind ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
if ( p_argcount < 2 ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 2 ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : INT ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : INT ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
if ( p_args [ 1 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 1 ;
r_error . expected = Variant : : STRING ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
int peer_id = * p_args [ 0 ] ;
StringName method = * p_args [ 1 ] ;
2017-03-05 15:44:50 +00:00
rpcp ( peer_id , false , method , & p_args [ 2 ] , p_argcount - 2 ) ;
2016-08-19 19:48:08 +00:00
2017-03-05 15:44:50 +00:00
r_error . error = Variant : : CallError : : CALL_OK ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
2016-08-14 21:49:50 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Node : : _rpc_unreliable_bind ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2016-08-19 19:48:08 +00:00
2017-03-05 15:44:50 +00:00
if ( p_argcount < 1 ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 1 ;
2016-08-14 21:49:50 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : STRING ;
2016-08-14 21:49:50 +00:00
return Variant ( ) ;
}
StringName method = * p_args [ 0 ] ;
2017-03-05 15:44:50 +00:00
rpcp ( 0 , true , method , & p_args [ 1 ] , p_argcount - 1 ) ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
r_error . error = Variant : : CallError : : CALL_OK ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
2016-08-14 21:49:50 +00:00
}
2017-03-05 15:44:50 +00:00
Variant Node : : _rpc_unreliable_id_bind ( const Variant * * p_args , int p_argcount , Variant : : CallError & r_error ) {
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
if ( p_argcount < 2 ) {
r_error . error = Variant : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 2 ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : INT ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : INT ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
if ( p_args [ 1 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Variant : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 1 ;
r_error . expected = Variant : : STRING ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
int peer_id = * p_args [ 0 ] ;
StringName method = * p_args [ 1 ] ;
2017-03-05 15:44:50 +00:00
rpcp ( peer_id , true , method , & p_args [ 2 ] , p_argcount - 2 ) ;
2016-08-19 19:48:08 +00:00
2017-03-05 15:44:50 +00:00
r_error . error = Variant : : CallError : : CALL_OK ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2017-03-05 15:44:50 +00:00
void Node : : rpcp ( int p_peer_id , bool p_unreliable , const StringName & p_method , const Variant * * p_arg , int p_argcount ) {
2016-08-19 19:48:08 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2018-05-08 08:51:04 +00:00
get_multiplayer ( ) - > rpcp ( this , p_peer_id , p_unreliable , p_method , p_arg , p_argcount ) ;
2016-08-19 19:48:08 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : rsetp ( int p_peer_id , bool p_unreliable , const StringName & p_property , const Variant & p_value ) {
2016-08-19 19:48:08 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2018-05-08 08:51:04 +00:00
get_multiplayer ( ) - > rsetp ( this , p_peer_id , p_unreliable , p_property , p_value ) ;
2016-08-19 19:48:08 +00:00
}
2018-03-03 17:30:11 +00:00
/******** RSET *********/
2017-03-05 15:44:50 +00:00
void Node : : rset ( const StringName & p_property , const Variant & p_value ) {
2016-08-19 19:48:08 +00:00
2017-03-05 15:44:50 +00:00
rsetp ( 0 , false , p_property , p_value ) ;
2016-08-19 19:48:08 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : rset_id ( int p_peer_id , const StringName & p_property , const Variant & p_value ) {
2016-08-19 19:48:08 +00:00
2017-03-05 15:44:50 +00:00
rsetp ( p_peer_id , false , p_property , p_value ) ;
2016-08-19 19:48:08 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : rset_unreliable ( const StringName & p_property , const Variant & p_value ) {
2016-08-19 19:48:08 +00:00
2017-03-05 15:44:50 +00:00
rsetp ( 0 , true , p_property , p_value ) ;
2016-08-19 19:48:08 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : rset_unreliable_id ( int p_peer_id , const StringName & p_property , const Variant & p_value ) {
2016-08-19 19:48:08 +00:00
2017-03-05 15:44:50 +00:00
rsetp ( p_peer_id , true , p_property , p_value ) ;
2016-08-19 19:48:08 +00:00
}
//////////// end of rpc
2018-05-08 08:51:04 +00:00
Ref < MultiplayerAPI > Node : : get_multiplayer ( ) const {
if ( multiplayer . is_valid ( ) )
return multiplayer ;
2018-03-03 17:30:11 +00:00
if ( ! is_inside_tree ( ) )
return Ref < MultiplayerAPI > ( ) ;
2018-05-08 08:51:04 +00:00
return get_tree ( ) - > get_multiplayer ( ) ;
2018-03-03 17:30:11 +00:00
}
2018-05-08 08:51:04 +00:00
Ref < MultiplayerAPI > Node : : get_custom_multiplayer ( ) const {
return multiplayer ;
2018-03-03 17:30:11 +00:00
}
2018-05-08 08:51:04 +00:00
void Node : : set_custom_multiplayer ( Ref < MultiplayerAPI > p_multiplayer ) {
2018-03-03 17:30:11 +00:00
2018-05-08 08:51:04 +00:00
multiplayer = p_multiplayer ;
2018-03-03 17:30:11 +00:00
}
2018-05-13 05:07:56 +00:00
const Map < StringName , MultiplayerAPI : : RPCMode > : : Element * Node : : get_node_rpc_mode ( const StringName & p_method ) {
2018-03-03 17:30:11 +00:00
return data . rpc_methods . find ( p_method ) ;
}
2018-05-13 05:07:56 +00:00
const Map < StringName , MultiplayerAPI : : RPCMode > : : Element * Node : : get_node_rset_mode ( const StringName & p_property ) {
2018-03-03 17:30:11 +00:00
return data . rpc_properties . find ( p_property ) ;
}
2016-08-19 19:48:08 +00:00
2018-07-30 00:20:41 +00:00
bool Node : : can_process_notification ( int p_what ) const {
switch ( p_what ) {
case NOTIFICATION_PHYSICS_PROCESS : return data . physics_process ;
case NOTIFICATION_PROCESS : return data . idle_process ;
case NOTIFICATION_INTERNAL_PROCESS : return data . idle_process_internal ;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS : return data . physics_process_internal ;
}
return true ;
}
2014-02-10 01:10:30 +00:00
bool Node : : can_process ( ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , false ) ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
if ( get_tree ( ) - > is_paused ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( data . pause_mode = = PAUSE_MODE_STOP )
2014-12-27 16:28:02 +00:00
return false ;
2017-03-05 15:44:50 +00:00
if ( data . pause_mode = = PAUSE_MODE_PROCESS )
2014-02-10 01:10:30 +00:00
return true ;
2017-03-05 15:44:50 +00:00
if ( data . pause_mode = = PAUSE_MODE_INHERIT ) {
2014-02-10 01:10:30 +00:00
if ( ! data . pause_owner )
return false ; //clearly no pause owner by default
2017-03-05 15:44:50 +00:00
if ( data . pause_owner - > data . pause_mode = = PAUSE_MODE_PROCESS )
2014-02-10 01:10:30 +00:00
return true ;
2014-12-27 16:28:02 +00:00
2017-03-05 15:44:50 +00:00
if ( data . pause_owner - > data . pause_mode = = PAUSE_MODE_STOP )
2014-12-27 16:28:02 +00:00
return false ;
2014-02-10 01:10:30 +00:00
}
}
return true ;
}
2017-09-30 14:19:07 +00:00
float Node : : get_physics_process_delta_time ( ) const {
2016-03-08 23:00:52 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree )
2017-09-30 14:19:07 +00:00
return data . tree - > get_physics_process_time ( ) ;
2014-02-10 01:10:30 +00:00
else
return 0 ;
}
2017-01-10 21:02:19 +00:00
float Node : : get_process_delta_time ( ) const {
if ( data . tree )
return data . tree - > get_idle_process_time ( ) ;
else
return 0 ;
}
2014-02-10 01:10:30 +00:00
void Node : : set_process ( bool p_idle_process ) {
2017-03-05 15:44:50 +00:00
if ( data . idle_process = = p_idle_process )
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
data . idle_process = p_idle_process ;
2014-02-10 01:10:30 +00:00
if ( data . idle_process )
2017-03-05 15:44:50 +00:00
add_to_group ( " idle_process " , false ) ;
2014-02-10 01:10:30 +00:00
else
remove_from_group ( " idle_process " ) ;
_change_notify ( " idle_process " ) ;
}
2017-01-10 21:02:19 +00:00
bool Node : : is_processing ( ) const {
return data . idle_process ;
2014-02-10 01:10:30 +00:00
}
2017-01-10 21:02:19 +00:00
void Node : : set_process_internal ( bool p_idle_process_internal ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
if ( data . idle_process_internal = = p_idle_process_internal )
2017-01-10 21:02:19 +00:00
return ;
2017-03-05 15:44:50 +00:00
data . idle_process_internal = p_idle_process_internal ;
2017-01-10 21:02:19 +00:00
if ( data . idle_process_internal )
2017-03-05 15:44:50 +00:00
add_to_group ( " idle_process_internal " , false ) ;
2017-01-10 21:02:19 +00:00
else
remove_from_group ( " idle_process_internal " ) ;
_change_notify ( " idle_process_internal " ) ;
2014-02-10 01:10:30 +00:00
}
2017-01-10 21:02:19 +00:00
bool Node : : is_processing_internal ( ) const {
2014-02-10 01:10:30 +00:00
2017-01-10 21:02:19 +00:00
return data . idle_process_internal ;
2014-02-10 01:10:30 +00:00
}
2018-07-02 05:30:40 +00:00
void Node : : set_process_priority ( int p_priority ) {
data . process_priority = p_priority ;
2019-11-21 16:26:28 +00:00
// Make sure we are in SceneTree.
if ( data . tree = = NULL ) {
return ;
}
2019-06-22 12:52:51 +00:00
2019-11-21 16:26:28 +00:00
if ( is_processing ( ) ) {
2018-07-02 05:30:40 +00:00
data . tree - > make_group_changed ( " idle_process " ) ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
2019-11-21 16:26:28 +00:00
if ( is_processing_internal ( ) ) {
2018-07-02 05:30:40 +00:00
data . tree - > make_group_changed ( " idle_process_internal " ) ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
2019-11-21 16:26:28 +00:00
if ( is_physics_processing ( ) ) {
2018-07-02 05:30:40 +00:00
data . tree - > make_group_changed ( " physics_process " ) ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
2019-11-21 16:26:28 +00:00
if ( is_physics_processing_internal ( ) ) {
2018-07-02 05:30:40 +00:00
data . tree - > make_group_changed ( " physics_process_internal " ) ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
}
2019-11-16 21:07:02 +00:00
int Node : : get_process_priority ( ) const {
return data . process_priority ;
}
2014-02-10 01:10:30 +00:00
void Node : : set_process_input ( bool p_enable ) {
2017-03-05 15:44:50 +00:00
if ( p_enable = = data . input )
2014-02-10 01:10:30 +00:00
return ;
2014-04-10 03:18:27 +00:00
2017-03-05 15:44:50 +00:00
data . input = p_enable ;
2014-11-06 00:20:42 +00:00
if ( ! is_inside_tree ( ) )
2014-04-10 03:18:27 +00:00
return ;
2014-02-10 01:10:30 +00:00
if ( p_enable )
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-02-10 01:10:30 +00:00
else
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-02-10 01:10:30 +00:00
}
bool Node : : is_processing_input ( ) const {
return data . input ;
}
void Node : : set_process_unhandled_input ( bool p_enable ) {
2017-03-05 15:44:50 +00:00
if ( p_enable = = data . unhandled_input )
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
data . unhandled_input = p_enable ;
2014-11-06 00:20:42 +00:00
if ( ! is_inside_tree ( ) )
2014-04-10 03:18:27 +00:00
return ;
2014-02-10 01:10:30 +00:00
if ( p_enable )
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-02-10 01:10:30 +00:00
else
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-02-10 01:10:30 +00:00
}
bool Node : : is_processing_unhandled_input ( ) const {
return data . unhandled_input ;
}
2014-04-10 03:18:27 +00:00
void Node : : set_process_unhandled_key_input ( bool p_enable ) {
2017-03-05 15:44:50 +00:00
if ( p_enable = = data . unhandled_key_input )
2014-04-10 03:18:27 +00:00
return ;
2017-03-05 15:44:50 +00:00
data . unhandled_key_input = p_enable ;
2014-11-06 00:20:42 +00:00
if ( ! is_inside_tree ( ) )
2014-04-10 03:18:27 +00:00
return ;
if ( p_enable )
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-04-10 03:18:27 +00:00
else
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2014-04-10 03:18:27 +00:00
}
bool Node : : is_processing_unhandled_key_input ( ) const {
return data . unhandled_key_input ;
}
2014-02-10 01:10:30 +00:00
StringName Node : : get_name ( ) const {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return data . name ;
}
2017-03-05 15:44:50 +00:00
void Node : : _set_name_nocheck ( const StringName & p_name ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . name = p_name ;
2014-02-10 01:10:30 +00:00
}
2018-04-26 16:42:15 +00:00
String Node : : invalid_character = " . : @ / \" " ;
bool Node : : _validate_node_name ( String & p_name ) {
String name = p_name ;
Vector < String > chars = Node : : invalid_character . split ( " " ) ;
for ( int i = 0 ; i < chars . size ( ) ; i + + ) {
name = name . replace ( chars [ i ] , " " ) ;
}
bool is_valid = name = = p_name ;
p_name = name ;
return is_valid ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_name ( const String & p_name ) {
2016-03-08 23:00:52 +00:00
2018-04-26 16:42:15 +00:00
String name = p_name ;
_validate_node_name ( name ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( name = = " " ) ;
data . name = name ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( data . parent ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . parent - > _validate_child_name ( this ) ;
}
2016-08-14 21:49:50 +00:00
propagate_notification ( NOTIFICATION_PATH_CHANGED ) ;
2014-11-06 00:20:42 +00:00
if ( is_inside_tree ( ) ) {
2014-02-10 01:10:30 +00:00
emit_signal ( " renamed " ) ;
2019-05-24 13:27:22 +00:00
get_tree ( ) - > node_renamed ( this ) ;
2014-11-06 00:20:42 +00:00
get_tree ( ) - > tree_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
static bool node_hrcr = false ;
2014-02-22 23:28:19 +00:00
static SafeRefCount node_hrcr_count ;
void Node : : init_node_hrcr ( ) {
node_hrcr_count . init ( 1 ) ;
}
void Node : : set_human_readable_collision_renaming ( bool p_enabled ) {
2017-03-05 15:44:50 +00:00
node_hrcr = p_enabled ;
2014-02-22 23:28:19 +00:00
}
2016-10-07 18:25:29 +00:00
# ifdef TOOLS_ENABLED
2017-03-05 15:44:50 +00:00
String Node : : validate_child_name ( Node * p_child ) {
2015-08-02 15:29:37 +00:00
2019-01-10 21:52:47 +00:00
StringName name = p_child - > data . name ;
_generate_serial_child_name ( p_child , name ) ;
return name ;
2015-08-02 15:29:37 +00:00
}
2016-10-07 18:25:29 +00:00
# endif
2015-08-02 15:29:37 +00:00
2015-12-08 14:21:12 +00:00
void Node : : _validate_child_name ( Node * p_child , bool p_force_human_readable ) {
2014-02-10 01:10:30 +00:00
/* Make sure the name is unique */
2015-12-08 14:21:12 +00:00
if ( node_hrcr | | p_force_human_readable ) {
2014-02-10 01:10:30 +00:00
2014-02-22 23:28:19 +00:00
//this approach to autoset node names is human readable but very slow
//it's turned on while running in the editor
2019-01-10 21:52:47 +00:00
StringName name = p_child - > data . name ;
_generate_serial_child_name ( p_child , name ) ;
p_child - > data . name = name ;
2014-02-22 23:28:19 +00:00
} else {
//this approach to autoset node names is fast but not as readable
//it's the default and reserves the '@' character for unique names.
2017-03-05 15:44:50 +00:00
bool unique = true ;
2014-02-22 23:28:19 +00:00
2017-03-05 15:44:50 +00:00
if ( p_child - > data . name = = StringName ( ) | | p_child - > data . name . operator String ( ) [ 0 ] = = ' @ ' ) {
2014-02-22 23:28:19 +00:00
//new unique name must be assigned
2017-03-05 15:44:50 +00:00
unique = false ;
2014-02-22 23:28:19 +00:00
} else {
//check if exists
2018-01-18 20:37:17 +00:00
Node * * children = data . children . ptrw ( ) ;
2014-02-22 23:28:19 +00:00
int cc = data . children . size ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < cc ; i + + ) {
2018-01-18 20:37:17 +00:00
if ( children [ i ] = = p_child )
2014-02-26 13:08:17 +00:00
continue ;
2018-01-18 20:37:17 +00:00
if ( children [ i ] - > data . name = = p_child - > data . name ) {
2017-03-05 15:44:50 +00:00
unique = false ;
2014-02-22 23:28:19 +00:00
break ;
}
}
}
if ( ! unique ) {
2019-08-07 10:54:30 +00:00
ERR_FAIL_COND ( ! node_hrcr_count . ref ( ) ) ;
2017-03-05 15:44:50 +00:00
String name = " @ " + String ( p_child - > get_name ( ) ) + " @ " + itos ( node_hrcr_count . get ( ) ) ;
p_child - > data . name = name ;
2014-02-10 01:10:30 +00:00
}
}
}
2019-01-10 21:52:47 +00:00
// Return s + 1 as if it were an integer
String increase_numeric_string ( const String & s ) {
2016-10-07 18:25:29 +00:00
2019-01-10 21:52:47 +00:00
String res = s ;
bool carry = res . length ( ) > 0 ;
2016-10-07 18:25:29 +00:00
2019-01-10 21:52:47 +00:00
for ( int i = res . length ( ) - 1 ; i > = 0 ; i - - ) {
if ( ! carry ) {
break ;
}
CharType n = s [ i ] ;
if ( n = = ' 9 ' ) { // keep carry as true: 9 + 1
res [ i ] = ' 0 ' ;
} else {
res [ i ] = s [ i ] + 1 ;
carry = false ;
}
}
if ( carry ) {
res = " 1 " + res ;
}
return res ;
}
void Node : : _generate_serial_child_name ( const Node * p_child , StringName & name ) const {
if ( name = = StringName ( ) ) {
//no name and a new nade is needed, create one.
2016-10-07 18:25:29 +00:00
2017-01-03 02:03:46 +00:00
name = p_child - > get_class ( ) ;
2017-01-12 18:13:09 +00:00
// Adjust casing according to project setting. The current type name is expected to be in PascalCase.
2017-07-19 20:00:46 +00:00
switch ( ProjectSettings : : get_singleton ( ) - > get ( " node/name_casing " ) . operator int ( ) ) {
2017-01-12 18:13:09 +00:00
case NAME_CASING_PASCAL_CASE :
break ;
2019-01-10 21:52:47 +00:00
case NAME_CASING_CAMEL_CASE : {
String n = name ;
n [ 0 ] = n . to_lower ( ) [ 0 ] ;
name = n ;
} break ;
2017-01-12 18:13:09 +00:00
case NAME_CASING_SNAKE_CASE :
2019-01-10 21:52:47 +00:00
name = String ( name ) . camelcase_to_underscore ( true ) ;
2017-01-12 18:13:09 +00:00
break ;
}
2016-10-07 18:25:29 +00:00
}
2019-01-10 21:52:47 +00:00
//quickly test if proposed name exists
int cc = data . children . size ( ) ; //children count
const Node * const * children_ptr = data . children . ptr ( ) ;
{
bool exists = false ;
for ( int i = 0 ; i < cc ; i + + ) {
if ( children_ptr [ i ] = = p_child ) { //exclude self in renaming if its already a child
continue ;
}
if ( children_ptr [ i ] - > data . name = = name ) {
exists = true ;
}
}
if ( ! exists ) {
return ; //if it does not exist, it does not need validation
}
}
2016-10-10 11:06:13 +00:00
// Extract trailing number
2019-01-10 21:52:47 +00:00
String name_string = name ;
2016-10-07 18:25:29 +00:00
String nums ;
2019-01-10 21:52:47 +00:00
for ( int i = name_string . length ( ) - 1 ; i > = 0 ; i - - ) {
CharType n = name_string [ i ] ;
2017-03-05 15:44:50 +00:00
if ( n > = ' 0 ' & & n < = ' 9 ' ) {
2019-01-10 21:52:47 +00:00
nums = String : : chr ( name_string [ i ] ) + nums ;
2016-10-07 18:25:29 +00:00
} else {
break ;
}
}
2017-03-05 15:44:50 +00:00
String nnsep = _get_name_num_separator ( ) ;
2019-01-10 21:52:47 +00:00
int name_last_index = name_string . length ( ) - nnsep . length ( ) - nums . length ( ) ;
// Assign the base name + separator to name if we have numbers preceded by a separator
if ( nums . length ( ) > 0 & & name_string . substr ( name_last_index , nnsep . length ( ) ) = = nnsep ) {
2019-01-11 22:02:07 +00:00
name_string = name_string . substr ( 0 , name_last_index + nnsep . length ( ) ) ;
2019-01-10 21:52:47 +00:00
} else {
nums = " " ;
2016-10-07 18:25:29 +00:00
}
2017-03-05 15:44:50 +00:00
for ( ; ; ) {
2019-01-10 21:52:47 +00:00
StringName attempt = name_string + nums ;
bool exists = false ;
for ( int i = 0 ; i < cc ; i + + ) {
if ( children_ptr [ i ] = = p_child ) {
2019-01-10 21:39:49 +00:00
continue ;
2019-01-10 21:52:47 +00:00
}
if ( children_ptr [ i ] - > data . name = = attempt ) {
exists = true ;
2019-01-10 21:39:49 +00:00
}
}
2019-01-10 21:52:47 +00:00
if ( ! exists ) {
name = attempt ;
return ;
2016-10-07 18:25:29 +00:00
} else {
2019-01-10 21:52:47 +00:00
if ( nums . length ( ) = = 0 ) {
// Name was undecorated so skip to 2 for a more natural result
nums = " 2 " ;
name_string + = nnsep ; // Add separator because nums.length() > 0 was false
2016-10-10 11:06:13 +00:00
} else {
2019-01-10 21:52:47 +00:00
nums = increase_numeric_string ( nums ) ;
2016-10-10 11:06:13 +00:00
}
2016-10-07 18:25:29 +00:00
}
}
}
2017-03-05 15:44:50 +00:00
void Node : : _add_child_nocheck ( Node * p_child , const StringName & p_name ) {
2014-02-10 01:10:30 +00:00
//add a child node quickly, without name validation
2017-03-05 15:44:50 +00:00
p_child - > data . name = p_name ;
p_child - > data . pos = data . children . size ( ) ;
data . children . push_back ( p_child ) ;
p_child - > data . parent = this ;
2015-06-14 05:13:47 +00:00
p_child - > notification ( NOTIFICATION_PARENTED ) ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree ) {
p_child - > _set_tree ( data . tree ) ;
2014-02-10 01:10:30 +00:00
}
/* Notify */
2018-01-18 20:37:17 +00:00
//recognize children created in this node constructor
2017-03-05 15:44:50 +00:00
p_child - > data . parent_owned = data . in_constructor ;
2014-02-10 01:10:30 +00:00
add_child_notify ( p_child ) ;
}
2015-12-08 14:21:12 +00:00
void Node : : add_child ( Node * p_child , bool p_legible_unique_name ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL_NULL ( p_child ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_MSG ( p_child = = this , " Can't add child ' " + p_child - > get_name ( ) + " ' to itself. " ) ; // adding to itself!
ERR_FAIL_COND_MSG ( p_child - > data . parent , " Can't add child ' " + p_child - > get_name ( ) + " ' to ' " + get_name ( ) + " ', already has a parent ' " + p_child - > data . parent - > get_name ( ) + " '. " ) ; //Fail if node has a parent
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, add_node() failed. Consider using call_deferred( \" add_child \" , child) instead. " ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
/* Validate name */
2017-03-05 15:44:50 +00:00
_validate_child_name ( p_child , p_legible_unique_name ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
_add_child_nocheck ( p_child , p_child - > data . name ) ;
2014-02-10 01:10:30 +00:00
}
2016-05-13 16:09:49 +00:00
void Node : : add_child_below_node ( Node * p_node , Node * p_child , bool p_legible_unique_name ) {
2018-06-20 01:47:34 +00:00
ERR_FAIL_NULL ( p_node ) ;
ERR_FAIL_NULL ( p_child ) ;
2016-05-13 16:09:49 +00:00
add_child ( p_child , p_legible_unique_name ) ;
if ( is_a_parent_of ( p_node ) ) {
move_child ( p_child , p_node - > get_position_in_parent ( ) + 1 ) ;
} else {
2019-11-07 08:44:15 +00:00
WARN_PRINT ( " Cannot move under node " + p_node - > get_name ( ) + " as " + p_child - > get_name ( ) + " does not share a parent. " ) ;
2016-05-13 16:09:49 +00:00
}
}
2014-02-10 01:10:30 +00:00
void Node : : _propagate_validate_owner ( ) {
if ( data . owner ) {
2017-03-05 15:44:50 +00:00
bool found = false ;
2014-02-10 01:10:30 +00:00
Node * parent = data . parent ;
2017-03-05 15:44:50 +00:00
while ( parent ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( parent = = data . owner ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
found = true ;
2014-02-10 01:10:30 +00:00
break ;
}
2017-03-05 15:44:50 +00:00
parent = parent - > data . parent ;
2014-02-10 01:10:30 +00:00
}
if ( ! found ) {
data . owner - > data . owned . erase ( data . OW ) ;
2017-03-05 15:44:50 +00:00
data . owner = NULL ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
data . children [ i ] - > _propagate_validate_owner ( ) ;
}
}
void Node : : remove_child ( Node * p_child ) {
ERR_FAIL_NULL ( p_child ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, remove_node() failed. Consider using call_deferred( \" remove_child \" , child) instead. " ) ;
2016-03-08 23:00:52 +00:00
2018-11-18 14:47:19 +00:00
int child_count = data . children . size ( ) ;
Node * * children = data . children . ptrw ( ) ;
2017-03-05 15:44:50 +00:00
int idx = - 1 ;
2016-03-08 23:00:52 +00:00
2018-11-18 14:47:19 +00:00
if ( p_child - > data . pos > = 0 & & p_child - > data . pos < child_count ) {
if ( children [ p_child - > data . pos ] = = p_child ) {
idx = p_child - > data . pos ;
}
}
if ( idx = = - 1 ) { //maybe removed while unparenting or something and index was not updated, so just in case the above fails, try this.
for ( int i = 0 ; i < child_count ; i + + ) {
2016-03-08 23:00:52 +00:00
2018-11-18 14:47:19 +00:00
if ( children [ i ] = = p_child ) {
idx = i ;
break ;
}
2014-02-10 01:10:30 +00:00
}
}
2016-03-08 23:00:52 +00:00
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_MSG ( idx = = - 1 , " Cannot remove child node " + p_child - > get_name ( ) + " as it is not a child of this node. " ) ;
2015-12-29 19:06:45 +00:00
//ERR_FAIL_COND( p_child->data.blocked > 0 );
2014-02-10 01:10:30 +00:00
//if (data.scene) { does not matter
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
p_child - > _set_tree ( NULL ) ;
2014-02-10 01:10:30 +00:00
//}
2016-03-08 23:00:52 +00:00
remove_child_notify ( p_child ) ;
2014-02-10 01:10:30 +00:00
p_child - > notification ( NOTIFICATION_UNPARENTED ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . children . remove ( idx ) ;
2016-03-08 23:00:52 +00:00
2018-11-18 14:47:19 +00:00
//update pointer and size
child_count = data . children . size ( ) ;
children = data . children . ptrw ( ) ;
2016-03-08 23:00:52 +00:00
2018-11-18 14:47:19 +00:00
for ( int i = idx ; i < child_count ; i + + ) {
children [ i ] - > data . pos = i ;
children [ i ] - > notification ( NOTIFICATION_MOVED_IN_PARENT ) ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
p_child - > data . parent = NULL ;
p_child - > data . pos = - 1 ;
2014-02-10 01:10:30 +00:00
// validate owner
p_child - > _propagate_validate_owner ( ) ;
2018-09-07 18:31:19 +00:00
if ( data . inside_tree ) {
p_child - > _propagate_after_exit_tree ( ) ;
}
2014-02-10 01:10:30 +00:00
}
int Node : : get_child_count ( ) const {
2016-03-08 23:00:52 +00:00
return data . children . size ( ) ;
2014-02-10 01:10:30 +00:00
}
Node * Node : : get_child ( int p_index ) const {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_INDEX_V ( p_index , data . children . size ( ) , NULL ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return data . children [ p_index ] ;
}
2017-03-05 15:44:50 +00:00
Node * Node : : _get_child_by_name ( const StringName & p_name ) const {
2015-10-10 12:09:09 +00:00
2017-03-05 15:44:50 +00:00
int cc = data . children . size ( ) ;
Node * const * cd = data . children . ptr ( ) ;
2015-10-10 12:09:09 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < cc ; i + + ) {
if ( cd [ i ] - > data . name = = p_name )
2015-10-10 12:09:09 +00:00
return cd [ i ] ;
}
return NULL ;
}
2019-01-29 16:15:34 +00:00
Node * Node : : get_node_or_null ( const NodePath & p_path ) const {
2014-02-10 01:10:30 +00:00
2019-03-08 20:19:56 +00:00
if ( p_path . is_empty ( ) ) {
return NULL ;
}
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_V_MSG ( ! data . inside_tree & & p_path . is_absolute ( ) , NULL , " Can't use get_node() with absolute paths from outside the active scene tree. " ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
Node * current = NULL ;
Node * root = NULL ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( ! p_path . is_absolute ( ) ) {
2017-03-05 15:44:50 +00:00
current = const_cast < Node * > ( this ) ; //start from this
2014-02-10 01:10:30 +00:00
} else {
2017-03-05 15:44:50 +00:00
root = const_cast < Node * > ( this ) ;
2014-02-10 01:10:30 +00:00
while ( root - > data . parent )
2017-03-05 15:44:50 +00:00
root = root - > data . parent ; //start from root
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_path . get_name_count ( ) ; i + + ) {
2016-03-08 23:00:52 +00:00
StringName name = p_path . get_name ( i ) ;
2014-02-10 01:10:30 +00:00
Node * next = NULL ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
if ( name = = SceneStringNames : : get_singleton ( ) - > dot ) { // .
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
next = current ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
} else if ( name = = SceneStringNames : : get_singleton ( ) - > doubledot ) { // ..
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
if ( current = = NULL | | ! current - > data . parent )
2014-02-10 01:10:30 +00:00
return NULL ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
next = current - > data . parent ;
} else if ( current = = NULL ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
if ( name = = root - > get_name ( ) )
next = root ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
} else {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
next = NULL ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
for ( int j = 0 ; j < current - > data . children . size ( ) ; j + + ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
Node * child = current - > data . children [ j ] ;
2017-03-05 15:44:50 +00:00
if ( child - > data . name = = name ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
next = child ;
break ;
2016-03-08 23:00:52 +00:00
}
2014-02-10 01:10:30 +00:00
}
if ( next = = NULL ) {
return NULL ;
} ;
}
2017-03-05 15:44:50 +00:00
current = next ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return current ;
}
2017-03-05 15:44:50 +00:00
Node * Node : : get_node ( const NodePath & p_path ) const {
2014-02-10 01:10:30 +00:00
2019-01-29 16:15:34 +00:00
Node * node = get_node_or_null ( p_path ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_V_MSG ( ! node , NULL , " Node not found: " + p_path + " . " ) ;
2014-02-10 01:10:30 +00:00
return node ;
}
2017-03-05 15:44:50 +00:00
bool Node : : has_node ( const NodePath & p_path ) const {
2014-02-10 01:10:30 +00:00
2019-01-29 16:15:34 +00:00
return get_node_or_null ( p_path ) ! = NULL ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Node * Node : : find_node ( const String & p_mask , bool p_recursive , bool p_owned ) const {
2015-06-08 03:33:10 +00:00
2017-03-05 15:44:50 +00:00
Node * const * cptr = data . children . ptr ( ) ;
2015-06-08 03:33:10 +00:00
int ccount = data . children . size ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < ccount ; i + + ) {
2015-06-08 03:33:10 +00:00
if ( p_owned & & ! cptr [ i ] - > data . owner )
continue ;
if ( cptr [ i ] - > data . name . operator String ( ) . match ( p_mask ) )
return cptr [ i ] ;
if ( ! p_recursive )
continue ;
2017-03-05 15:44:50 +00:00
Node * ret = cptr [ i ] - > find_node ( p_mask , true , p_owned ) ;
2015-06-08 03:33:10 +00:00
if ( ret )
return ret ;
}
return NULL ;
}
2014-02-10 01:10:30 +00:00
Node * Node : : get_parent ( ) const {
return data . parent ;
}
2018-09-15 16:22:06 +00:00
Node * Node : : find_parent ( const String & p_mask ) const {
Node * p = data . parent ;
while ( p ) {
if ( p - > data . name . operator String ( ) . match ( p_mask ) )
return p ;
p = p - > data . parent ;
}
return NULL ;
}
2014-02-10 01:10:30 +00:00
bool Node : : is_a_parent_of ( const Node * p_node ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_NULL_V ( p_node , false ) ;
Node * p = p_node - > data . parent ;
while ( p ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
if ( p = = this )
2014-02-10 01:10:30 +00:00
return true ;
2017-03-05 15:44:50 +00:00
p = p - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return false ;
}
bool Node : : is_greater_than ( const Node * p_node ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_NULL_V ( p_node , false ) ;
ERR_FAIL_COND_V ( ! data . inside_tree , false ) ;
ERR_FAIL_COND_V ( ! p_node - > data . inside_tree , false ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( data . depth < 0 , false ) ;
ERR_FAIL_COND_V ( p_node - > data . depth < 0 , false ) ;
2014-02-10 01:10:30 +00:00
# ifdef NO_ALLOCA
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
Vector < int > this_stack ;
Vector < int > that_stack ;
this_stack . resize ( data . depth ) ;
that_stack . resize ( p_node - > data . depth ) ;
# else
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
int * this_stack = ( int * ) alloca ( sizeof ( int ) * data . depth ) ;
int * that_stack = ( int * ) alloca ( sizeof ( int ) * p_node - > data . depth ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
# endif
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
const Node * n = this ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
int idx = data . depth - 1 ;
while ( n ) {
ERR_FAIL_INDEX_V ( idx , data . depth , false ) ;
this_stack [ idx - - ] = n - > data . pos ;
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( idx ! = - 1 , false ) ;
2014-02-10 01:10:30 +00:00
n = p_node ;
2017-03-05 15:44:50 +00:00
idx = p_node - > data . depth - 1 ;
while ( n ) {
ERR_FAIL_INDEX_V ( idx , p_node - > data . depth , false ) ;
that_stack [ idx - - ] = n - > data . pos ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( idx ! = - 1 , false ) ;
idx = 0 ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
bool res ;
2017-03-05 15:44:50 +00:00
while ( true ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
// using -2 since out-of-tree or nonroot nodes have -1
2017-03-05 15:44:50 +00:00
int this_idx = ( idx > = data . depth ) ? - 2 : this_stack [ idx ] ;
int that_idx = ( idx > = p_node - > data . depth ) ? - 2 : that_stack [ idx ] ;
2014-02-10 01:10:30 +00:00
if ( this_idx > that_idx ) {
2017-03-05 15:44:50 +00:00
res = true ;
2014-02-10 01:10:30 +00:00
break ;
} else if ( this_idx < that_idx ) {
2017-03-05 15:44:50 +00:00
res = false ;
2014-02-10 01:10:30 +00:00
break ;
2017-03-05 15:44:50 +00:00
} else if ( this_idx = = - 2 ) {
res = false ; // equal
2014-02-10 01:10:30 +00:00
break ;
}
idx + + ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return res ;
}
2017-03-05 15:44:50 +00:00
void Node : : get_owned_by ( Node * p_by , List < Node * > * p_owned ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( data . owner = = p_by )
2014-02-10 01:10:30 +00:00
p_owned - > push_back ( this ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + )
get_child ( i ) - > get_owned_by ( p_by , p_owned ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : _set_owner_nocheck ( Node * p_owner ) {
2014-02-10 01:10:30 +00:00
2017-03-15 11:28:57 +00:00
if ( data . owner = = p_owner )
return ;
2015-10-16 22:11:23 +00:00
ERR_FAIL_COND ( data . owner ) ;
2017-03-05 15:44:50 +00:00
data . owner = p_owner ;
data . owner - > data . owned . push_back ( this ) ;
2014-02-10 01:10:30 +00:00
data . OW = data . owner - > data . owned . back ( ) ;
}
void Node : : set_owner ( Node * p_owner ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( data . owner ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . owner - > data . owned . erase ( data . OW ) ;
data . OW = NULL ;
data . owner = NULL ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( p_owner = = this ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( ! p_owner )
return ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
Node * check = this - > get_parent ( ) ;
bool owner_valid = false ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( check ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
if ( check = = p_owner ) {
owner_valid = true ;
2014-02-10 01:10:30 +00:00
break ;
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
check = check - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! owner_valid ) ;
_set_owner_nocheck ( p_owner ) ;
}
Node * Node : : get_owner ( ) const {
2016-03-08 23:00:52 +00:00
return data . owner ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Node * Node : : find_common_parent_with ( const Node * p_node ) const {
2016-07-19 23:04:06 +00:00
2017-03-05 15:44:50 +00:00
if ( this = = p_node )
return const_cast < Node * > ( p_node ) ;
2016-07-19 23:04:06 +00:00
2017-03-05 15:44:50 +00:00
Set < const Node * > visited ;
2016-07-19 23:04:06 +00:00
2017-03-05 15:44:50 +00:00
const Node * n = this ;
2016-07-19 23:04:06 +00:00
2017-03-05 15:44:50 +00:00
while ( n ) {
2016-07-19 23:04:06 +00:00
visited . insert ( n ) ;
2017-03-05 15:44:50 +00:00
n = n - > data . parent ;
2016-07-19 23:04:06 +00:00
}
2017-03-05 15:44:50 +00:00
const Node * common_parent = p_node ;
2016-07-19 23:04:06 +00:00
2017-03-05 15:44:50 +00:00
while ( common_parent ) {
2016-07-19 23:04:06 +00:00
if ( visited . has ( common_parent ) )
break ;
2017-03-05 15:44:50 +00:00
common_parent = common_parent - > data . parent ;
2016-07-19 23:04:06 +00:00
}
if ( ! common_parent )
return NULL ;
2017-03-05 15:44:50 +00:00
return const_cast < Node * > ( common_parent ) ;
2016-07-19 23:04:06 +00:00
}
2014-02-10 01:10:30 +00:00
NodePath Node : : get_path_to ( const Node * p_node ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_NULL_V ( p_node , NodePath ( ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( this = = p_node )
2014-02-10 01:10:30 +00:00
return NodePath ( " . " ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
Set < const Node * > visited ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
const Node * n = this ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( n ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
visited . insert ( n ) ;
2017-03-05 15:44:50 +00:00
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
const Node * common_parent = p_node ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( common_parent ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( visited . has ( common_parent ) )
break ;
2017-03-05 15:44:50 +00:00
common_parent = common_parent - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! common_parent , NodePath ( ) ) ; //nodes not in the same tree
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
visited . clear ( ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
Vector < StringName > path ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
n = p_node ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( n ! = common_parent ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
path . push_back ( n - > get_name ( ) ) ;
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
n = this ;
StringName up = String ( " .. " ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( n ! = common_parent ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
path . push_back ( up ) ;
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
path . invert ( ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
return NodePath ( path , false ) ;
2014-02-10 01:10:30 +00:00
}
NodePath Node : : get_path ( ) const {
2016-03-08 23:00:52 +00:00
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_V_MSG ( ! is_inside_tree ( ) , NodePath ( ) , " Cannot get path of node as it is not in a scene tree. " ) ;
2016-08-14 21:49:50 +00:00
if ( data . path_cache )
return * data . path_cache ;
2014-02-10 01:10:30 +00:00
const Node * n = this ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
Vector < StringName > path ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( n ) {
2014-02-10 01:10:30 +00:00
path . push_back ( n - > get_name ( ) ) ;
2017-03-05 15:44:50 +00:00
n = n - > data . parent ;
2016-03-08 23:00:52 +00:00
}
2014-02-10 01:10:30 +00:00
path . invert ( ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . path_cache = memnew ( NodePath ( path , true ) ) ;
2016-08-14 21:49:50 +00:00
return * data . path_cache ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
bool Node : : is_in_group ( const StringName & p_identifier ) const {
2014-02-10 01:10:30 +00:00
return data . grouped . has ( p_identifier ) ;
}
2017-03-05 15:44:50 +00:00
void Node : : add_to_group ( const StringName & p_identifier , bool p_persistent ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! p_identifier . operator String ( ) . length ( ) ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( data . grouped . has ( p_identifier ) )
return ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
GroupData gd ;
2016-03-08 23:00:52 +00:00
2016-06-08 01:08:12 +00:00
if ( data . tree ) {
2017-03-05 15:44:50 +00:00
gd . group = data . tree - > add_to_group ( p_identifier , this ) ;
2016-06-08 01:08:12 +00:00
} else {
2017-03-05 15:44:50 +00:00
gd . group = NULL ;
2016-06-08 01:08:12 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
gd . persistent = p_persistent ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . grouped [ p_identifier ] = gd ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : remove_from_group ( const StringName & p_identifier ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( ! data . grouped . has ( p_identifier ) ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
Map < StringName , GroupData > : : Element * E = data . grouped . find ( p_identifier ) ;
2016-06-08 01:08:12 +00:00
ERR_FAIL_COND ( ! E ) ;
2016-03-08 23:00:52 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree )
2017-03-05 15:44:50 +00:00
data . tree - > remove_from_group ( E - > key ( ) , this ) ;
2014-02-10 01:10:30 +00:00
2016-06-08 01:08:12 +00:00
data . grouped . erase ( E ) ;
2014-02-10 01:10:30 +00:00
}
2014-06-16 13:22:26 +00:00
Array Node : : _get_groups ( ) const {
Array groups ;
List < GroupInfo > gi ;
get_groups ( & gi ) ;
2017-03-05 15:44:50 +00:00
for ( List < GroupInfo > : : Element * E = gi . front ( ) ; E ; E = E - > next ( ) ) {
2014-06-16 13:22:26 +00:00
groups . push_back ( E - > get ( ) . name ) ;
}
return groups ;
}
2014-02-10 01:10:30 +00:00
void Node : : get_groups ( List < GroupInfo > * p_groups ) const {
2017-03-05 15:44:50 +00:00
for ( const Map < StringName , GroupData > : : Element * E = data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
GroupInfo gi ;
2017-03-05 15:44:50 +00:00
gi . name = E - > key ( ) ;
gi . persistent = E - > get ( ) . persistent ;
2014-02-10 01:10:30 +00:00
p_groups - > push_back ( gi ) ;
}
}
2019-08-16 20:30:31 +00:00
int Node : : get_persistent_group_count ( ) const {
int count = 0 ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( const Map < StringName , GroupData > : : Element * E = data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
2019-08-16 20:30:31 +00:00
if ( E - > get ( ) . persistent ) {
count + = 1 ;
}
2016-06-04 16:17:56 +00:00
}
2019-08-16 20:30:31 +00:00
return count ;
2016-06-04 16:17:56 +00:00
}
2019-07-10 09:54:12 +00:00
void Node : : _print_tree_pretty ( const String & prefix , const bool last ) {
2014-02-10 01:10:30 +00:00
2018-02-28 09:12:06 +00:00
String new_prefix = last ? String : : utf8 ( " ┖╴ " ) : String : : utf8 ( " ┠╴ " ) ;
print_line ( prefix + new_prefix + String ( get_name ( ) ) ) ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
new_prefix = last ? String : : utf8 ( " " ) : String : : utf8 ( " ┃ " ) ;
data . children [ i ] - > _print_tree_pretty ( prefix + new_prefix , i = = data . children . size ( ) - 1 ) ;
}
}
void Node : : print_tree_pretty ( ) {
_print_tree_pretty ( " " , true ) ;
2014-02-10 01:10:30 +00:00
}
void Node : : print_tree ( ) {
_print_tree ( this ) ;
}
2018-02-28 09:12:06 +00:00
void Node : : _print_tree ( const Node * p_node ) {
print_line ( String ( p_node - > get_path_to ( this ) ) ) ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + )
data . children [ i ] - > _print_tree ( p_node ) ;
}
2014-02-10 01:10:30 +00:00
void Node : : _propagate_reverse_notification ( int p_notification ) {
2016-03-08 23:00:52 +00:00
data . blocked + + ;
2017-03-05 15:44:50 +00:00
for ( int i = data . children . size ( ) - 1 ; i > = 0 ; i - - ) {
2016-03-08 23:00:52 +00:00
data . children [ i ] - > _propagate_reverse_notification ( p_notification ) ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
notification ( p_notification , true ) ;
2014-02-10 01:10:30 +00:00
data . blocked - - ;
}
void Node : : _propagate_deferred_notification ( int p_notification , bool p_reverse ) {
2014-11-06 00:20:42 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2014-02-10 01:10:30 +00:00
data . blocked + + ;
if ( ! p_reverse )
2017-03-05 15:44:50 +00:00
MessageQueue : : get_singleton ( ) - > push_notification ( this , p_notification ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . children [ i ] - > _propagate_deferred_notification ( p_notification , p_reverse ) ;
2014-02-10 01:10:30 +00:00
}
if ( p_reverse )
2017-03-05 15:44:50 +00:00
MessageQueue : : get_singleton ( ) - > push_notification ( this , p_notification ) ;
2014-02-10 01:10:30 +00:00
data . blocked - - ;
}
void Node : : propagate_notification ( int p_notification ) {
2016-03-08 23:00:52 +00:00
data . blocked + + ;
2014-02-10 01:10:30 +00:00
notification ( p_notification ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2016-03-08 23:00:52 +00:00
data . children [ i ] - > propagate_notification ( p_notification ) ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
data . blocked - - ;
2014-02-10 01:10:30 +00:00
}
2017-08-19 13:17:06 +00:00
void Node : : propagate_call ( const StringName & p_method , const Array & p_args , const bool p_parent_first ) {
data . blocked + + ;
if ( p_parent_first & & has_method ( p_method ) )
callv ( p_method , p_args ) ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > propagate_call ( p_method , p_args , p_parent_first ) ;
}
if ( ! p_parent_first & & has_method ( p_method ) )
callv ( p_method , p_args ) ;
data . blocked - - ;
}
2017-03-05 15:44:50 +00:00
void Node : : _propagate_replace_owner ( Node * p_owner , Node * p_by_owner ) {
if ( get_owner ( ) = = p_owner )
2014-02-10 01:10:30 +00:00
set_owner ( p_by_owner ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . blocked + + ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + )
data . children [ i ] - > _propagate_replace_owner ( p_owner , p_by_owner ) ;
2016-03-08 23:00:52 +00:00
data . blocked - - ;
2014-02-10 01:10:30 +00:00
}
int Node : : get_index ( ) const {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return data . pos ;
}
void Node : : remove_and_skip ( ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! data . parent ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
Node * new_owner = get_owner ( ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
List < Node * > children ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( true ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
bool clear = true ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2017-03-12 17:50:43 +00:00
Node * c_node = data . children [ i ] ;
if ( ! c_node - > get_owner ( ) )
2014-02-10 01:10:30 +00:00
continue ;
2016-03-08 23:00:52 +00:00
2017-03-12 17:50:43 +00:00
remove_child ( c_node ) ;
c_node - > _propagate_replace_owner ( this , NULL ) ;
children . push_back ( c_node ) ;
2017-03-05 15:44:50 +00:00
clear = false ;
2014-02-10 01:10:30 +00:00
break ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( clear )
break ;
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( ! children . empty ( ) ) {
2016-03-08 23:00:52 +00:00
2017-03-12 17:50:43 +00:00
Node * c_node = children . front ( ) - > get ( ) ;
data . parent - > add_child ( c_node ) ;
c_node - > _propagate_replace_owner ( NULL , new_owner ) ;
2014-02-10 01:10:30 +00:00
children . pop_front ( ) ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . parent - > remove_child ( this ) ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_filename ( const String & p_filename ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . filename = p_filename ;
2014-02-10 01:10:30 +00:00
}
String Node : : get_filename ( ) const {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return data . filename ;
}
2019-08-15 12:50:26 +00:00
void Node : : set_editor_description ( const String & p_editor_description ) {
set_meta ( " _editor_description_ " , p_editor_description ) ;
}
String Node : : get_editor_description ( ) const {
if ( has_meta ( " _editor_description_ " ) ) {
return get_meta ( " _editor_description_ " ) ;
} else {
return " " ;
}
}
2017-03-05 15:44:50 +00:00
void Node : : set_editable_instance ( Node * p_node , bool p_editable ) {
2015-10-10 12:09:09 +00:00
ERR_FAIL_NULL ( p_node ) ;
ERR_FAIL_COND ( ! is_a_parent_of ( p_node ) ) ;
NodePath p = get_path_to ( p_node ) ;
2017-04-07 13:48:07 +00:00
if ( ! p_editable ) {
2015-10-10 12:09:09 +00:00
data . editable_instances . erase ( p ) ;
2017-04-07 13:48:07 +00:00
// Avoid this flag being needlessly saved;
2018-02-21 16:30:55 +00:00
// also give more visual feedback if editable children is re-enabled
2017-04-07 13:48:07 +00:00
set_display_folded ( false ) ;
} else {
2017-03-05 15:44:50 +00:00
data . editable_instances [ p ] = true ;
2017-04-07 13:48:07 +00:00
}
2015-10-10 12:09:09 +00:00
}
2018-10-29 19:36:31 +00:00
bool Node : : is_editable_instance ( const Node * p_node ) const {
2015-10-10 12:09:09 +00:00
if ( ! p_node )
return false ; //easier, null is never editable :)
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! is_a_parent_of ( p_node ) , false ) ;
2015-10-10 12:09:09 +00:00
NodePath p = get_path_to ( p_node ) ;
return data . editable_instances . has ( p ) ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_editable_instances ( const HashMap < NodePath , int > & p_editable_instances ) {
2016-04-12 16:21:37 +00:00
2017-03-05 15:44:50 +00:00
data . editable_instances = p_editable_instances ;
2016-04-12 16:21:37 +00:00
}
2017-03-05 15:44:50 +00:00
HashMap < NodePath , int > Node : : get_editable_instances ( ) const {
2016-04-12 16:21:37 +00:00
return data . editable_instances ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_scene_instance_state ( const Ref < SceneState > & p_state ) {
2015-10-10 12:09:09 +00:00
2017-03-05 15:44:50 +00:00
data . instance_state = p_state ;
2015-10-10 12:09:09 +00:00
}
2017-03-05 15:44:50 +00:00
Ref < SceneState > Node : : get_scene_instance_state ( ) const {
2015-10-10 12:09:09 +00:00
return data . instance_state ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_scene_inherited_state ( const Ref < SceneState > & p_state ) {
2015-10-10 12:09:09 +00:00
2017-03-05 15:44:50 +00:00
data . inherited_state = p_state ;
2015-10-10 12:09:09 +00:00
}
2017-03-05 15:44:50 +00:00
Ref < SceneState > Node : : get_scene_inherited_state ( ) const {
2015-10-10 12:09:09 +00:00
return data . inherited_state ;
}
2015-10-16 22:11:23 +00:00
void Node : : set_scene_instance_load_placeholder ( bool p_enable ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . use_placeholder = p_enable ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
bool Node : : get_scene_instance_load_placeholder ( ) const {
2015-10-16 22:11:23 +00:00
return data . use_placeholder ;
2014-02-10 01:10:30 +00:00
}
int Node : : get_position_in_parent ( ) const {
return data . pos ;
}
2017-11-19 13:32:10 +00:00
Node * Node : : _duplicate ( int p_flags , Map < const Node * , Node * > * r_duplimap ) const {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Node * node = NULL ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
bool instanced = false ;
2015-08-02 15:29:37 +00:00
2017-08-24 20:58:51 +00:00
if ( Object : : cast_to < InstancePlaceholder > ( this ) ) {
2016-01-22 22:36:40 +00:00
2017-08-24 20:58:51 +00:00
const InstancePlaceholder * ip = Object : : cast_to < const InstancePlaceholder > ( this ) ;
2017-03-05 15:44:50 +00:00
InstancePlaceholder * nip = memnew ( InstancePlaceholder ) ;
nip - > set_instance_path ( ip - > get_instance_path ( ) ) ;
node = nip ;
2016-01-22 22:36:40 +00:00
2017-03-05 15:44:50 +00:00
} else if ( ( p_flags & DUPLICATE_USE_INSTANCING ) & & get_filename ( ) ! = String ( ) ) {
2015-08-02 15:29:37 +00:00
Ref < PackedScene > res = ResourceLoader : : load ( get_filename ( ) ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( res . is_null ( ) , NULL ) ;
2017-11-19 13:32:10 +00:00
PackedScene : : GenEditState ges = PackedScene : : GEN_EDIT_STATE_DISABLED ;
# ifdef TOOLS_ENABLED
if ( p_flags & DUPLICATE_FROM_EDITOR )
ges = PackedScene : : GEN_EDIT_STATE_INSTANCE ;
# endif
node = res - > instance ( ges ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! node , NULL ) ;
2015-08-02 15:29:37 +00:00
2017-03-05 15:44:50 +00:00
instanced = true ;
2015-08-02 15:29:37 +00:00
} else {
2014-02-10 01:10:30 +00:00
2017-01-03 02:03:46 +00:00
Object * obj = ClassDB : : instance ( get_class ( ) ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! obj , NULL ) ;
2017-08-24 20:58:51 +00:00
node = Object : : cast_to < Node > ( obj ) ;
2015-08-02 15:29:37 +00:00
if ( ! node )
memdelete ( obj ) ;
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! node , NULL ) ;
2015-08-02 15:29:37 +00:00
}
2014-02-10 01:10:30 +00:00
2017-10-13 22:03:33 +00:00
if ( get_filename ( ) ! = " " ) { //an instance
node - > set_filename ( get_filename ( ) ) ;
}
2014-02-10 01:10:30 +00:00
2017-09-06 12:21:19 +00:00
StringName script_property_name = CoreStringNames : : get_singleton ( ) - > _script ;
2017-12-08 14:05:15 +00:00
List < const Node * > hidden_roots ;
2017-10-13 22:03:33 +00:00
List < const Node * > node_tree ;
node_tree . push_front ( this ) ;
if ( instanced ) {
2017-11-25 20:13:52 +00:00
// Since nodes in the instanced hierarchy won't be duplicated explicitly, we need to make an inventory
// of all the nodes in the tree of the instanced scene in order to transfer the values of the properties
2017-10-13 22:03:33 +00:00
for ( List < const Node * > : : Element * N = node_tree . front ( ) ; N ; N = N - > next ( ) ) {
for ( int i = 0 ; i < N - > get ( ) - > get_child_count ( ) ; + + i ) {
2017-11-25 20:13:52 +00:00
2017-12-08 14:05:15 +00:00
Node * descendant = N - > get ( ) - > get_child ( i ) ;
2017-11-25 20:13:52 +00:00
// Skip nodes not really belonging to the instanced hierarchy; they'll be processed normally later
2017-12-08 14:05:15 +00:00
// but remember non-instanced nodes that are hidden below instanced ones
if ( descendant - > data . owner ! = this ) {
2018-06-30 10:35:51 +00:00
if ( descendant - > get_parent ( ) & & descendant - > get_parent ( ) ! = this & & descendant - > get_parent ( ) - > data . owner = = this & & descendant - > data . owner ! = descendant - > get_parent ( ) )
2017-12-08 14:05:15 +00:00
hidden_roots . push_back ( descendant ) ;
2017-11-25 20:13:52 +00:00
continue ;
2017-12-08 14:05:15 +00:00
}
2017-11-25 20:13:52 +00:00
2017-12-08 14:05:15 +00:00
node_tree . push_back ( descendant ) ;
2017-10-13 22:03:33 +00:00
}
2017-09-06 12:21:19 +00:00
}
}
2017-10-13 22:03:33 +00:00
for ( List < const Node * > : : Element * N = node_tree . front ( ) ; N ; N = N - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-10-13 22:03:33 +00:00
Node * current_node = node - > get_node ( get_path_to ( N - > get ( ) ) ) ;
2017-11-25 20:13:52 +00:00
ERR_CONTINUE ( ! current_node ) ;
2017-02-20 19:05:01 +00:00
2017-10-13 22:03:33 +00:00
if ( p_flags & DUPLICATE_SCRIPTS ) {
bool is_valid = false ;
Variant script = N - > get ( ) - > get ( script_property_name , & is_valid ) ;
if ( is_valid ) {
current_node - > set ( script_property_name , script ) ;
}
2017-09-11 09:34:36 +00:00
}
2017-10-13 22:03:33 +00:00
List < PropertyInfo > plist ;
N - > get ( ) - > get_property_list ( & plist ) ;
for ( List < PropertyInfo > : : Element * E = plist . front ( ) ; E ; E = E - > next ( ) ) {
if ( ! ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE ) )
continue ;
String name = E - > get ( ) . name ;
if ( name = = script_property_name )
continue ;
2018-03-09 19:16:08 +00:00
Variant value = N - > get ( ) - > get ( name ) . duplicate ( true ) ;
2017-10-13 22:03:33 +00:00
2018-01-11 18:50:33 +00:00
if ( E - > get ( ) . usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE ) {
Resource * res = Object : : cast_to < Resource > ( value ) ;
2018-07-02 18:08:35 +00:00
if ( res ) { // Duplicate only if it's a resource
2018-01-11 18:50:33 +00:00
current_node - > set ( name , res - > duplicate ( ) ) ;
2018-07-02 18:08:35 +00:00
}
2018-01-11 18:50:33 +00:00
} else {
current_node - > set ( name , value ) ;
}
2017-10-13 22:03:33 +00:00
}
2014-02-10 01:10:30 +00:00
}
2019-05-28 10:40:39 +00:00
if ( get_name ( ) ! = String ( ) ) {
node - > set_name ( get_name ( ) ) ;
}
2014-02-10 01:10:30 +00:00
2017-11-19 13:32:10 +00:00
# ifdef TOOLS_ENABLED
if ( ( p_flags & DUPLICATE_FROM_EDITOR ) & & r_duplimap )
r_duplimap - > insert ( this , node ) ;
# endif
2017-02-20 19:05:01 +00:00
if ( p_flags & DUPLICATE_GROUPS ) {
List < GroupInfo > gi ;
get_groups ( & gi ) ;
2017-03-05 15:44:50 +00:00
for ( List < GroupInfo > : : Element * E = gi . front ( ) ; E ; E = E - > next ( ) ) {
2016-01-19 23:08:04 +00:00
2017-11-19 13:32:10 +00:00
# ifdef TOOLS_ENABLED
if ( ( p_flags & DUPLICATE_FROM_EDITOR ) & & ! E - > get ( ) . persistent )
continue ;
# endif
2017-02-20 19:05:01 +00:00
node - > add_to_group ( E - > get ( ) . name , E - > get ( ) . persistent ) ;
}
2016-01-19 23:08:04 +00:00
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
if ( get_child ( i ) - > data . parent_owned )
continue ;
2017-03-05 15:44:50 +00:00
if ( instanced & & get_child ( i ) - > data . owner = = this )
2015-08-02 15:29:37 +00:00
continue ; //part of instance
2017-11-19 13:32:10 +00:00
Node * dup = get_child ( i ) - > _duplicate ( p_flags , r_duplimap ) ;
2014-02-10 01:10:30 +00:00
if ( ! dup ) {
memdelete ( node ) ;
return NULL ;
}
node - > add_child ( dup ) ;
2017-12-08 14:05:15 +00:00
if ( i < node - > get_child_count ( ) - 1 ) {
node - > move_child ( dup , i ) ;
}
}
for ( List < const Node * > : : Element * E = hidden_roots . front ( ) ; E ; E = E - > next ( ) ) {
Node * parent = node - > get_node ( get_path_to ( E - > get ( ) - > data . parent ) ) ;
if ( ! parent ) {
memdelete ( node ) ;
return NULL ;
}
Node * dup = E - > get ( ) - > _duplicate ( p_flags , r_duplimap ) ;
if ( ! dup ) {
memdelete ( node ) ;
return NULL ;
}
parent - > add_child ( dup ) ;
int pos = E - > get ( ) - > get_position_in_parent ( ) ;
if ( pos < parent - > get_child_count ( ) - 1 ) {
parent - > move_child ( dup , pos ) ;
}
2014-02-10 01:10:30 +00:00
}
return node ;
}
2017-11-19 12:05:18 +00:00
Node * Node : : duplicate ( int p_flags ) const {
Node * dupe = _duplicate ( p_flags ) ;
if ( dupe & & ( p_flags & DUPLICATE_SIGNALS ) ) {
_duplicate_signals ( this , dupe ) ;
}
return dupe ;
}
2017-11-19 13:32:10 +00:00
# ifdef TOOLS_ENABLED
Node * Node : : duplicate_from_editor ( Map < const Node * , Node * > & r_duplimap ) const {
Node * dupe = _duplicate ( DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANCING | DUPLICATE_FROM_EDITOR , & r_duplimap ) ;
// Duplication of signals must happen after all the node descendants have been copied,
// because re-targeting of connections from some descendant to another is not possible
// if the emitter node comes later in tree order than the receiver
_duplicate_signals ( this , dupe ) ;
return dupe ;
}
# endif
2017-03-05 15:44:50 +00:00
void Node : : _duplicate_and_reown ( Node * p_new_parent , const Map < Node * , Node * > & p_reown_map ) const {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( get_owner ( ) ! = get_parent ( ) - > get_owner ( ) )
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
Node * node = NULL ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( get_filename ( ) ! = " " ) {
2014-02-10 01:10:30 +00:00
Ref < PackedScene > res = ResourceLoader : : load ( get_filename ( ) ) ;
2019-09-25 08:28:50 +00:00
ERR_FAIL_COND_MSG ( res . is_null ( ) , " Cannot load scene: " + get_filename ( ) ) ;
2017-03-05 15:44:50 +00:00
node = res - > instance ( ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! node ) ;
} else {
2017-01-03 02:03:46 +00:00
Object * obj = ClassDB : : instance ( get_class ( ) ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_MSG ( ! obj , " Node: Could not duplicate: " + String ( get_class ( ) ) + " . " ) ;
2017-08-24 20:58:51 +00:00
node = Object : : cast_to < Node > ( obj ) ;
2019-08-07 10:54:30 +00:00
if ( ! node ) {
2014-02-10 01:10:30 +00:00
memdelete ( obj ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_MSG ( " Node: Could not duplicate: " + String ( get_class ( ) ) + " . " ) ;
2019-08-07 10:54:30 +00:00
}
2014-02-10 01:10:30 +00:00
}
List < PropertyInfo > plist ;
get_property_list ( & plist ) ;
2017-03-05 15:44:50 +00:00
for ( List < PropertyInfo > : : Element * E = plist . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( ! ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE ) )
2014-02-10 01:10:30 +00:00
continue ;
String name = E - > get ( ) . name ;
2017-09-11 09:34:36 +00:00
2018-03-09 19:16:08 +00:00
Variant value = get ( name ) . duplicate ( true ) ;
2017-09-11 09:34:36 +00:00
node - > set ( name , value ) ;
2014-02-10 01:10:30 +00:00
}
2018-09-14 16:13:41 +00:00
List < GroupInfo > groups ;
get_groups ( & groups ) ;
for ( List < GroupInfo > : : Element * E = groups . front ( ) ; E ; E = E - > next ( ) )
node - > add_to_group ( E - > get ( ) . name , E - > get ( ) . persistent ) ;
2014-02-10 01:10:30 +00:00
node - > set_name ( get_name ( ) ) ;
p_new_parent - > add_child ( node ) ;
2017-03-05 15:44:50 +00:00
Node * owner = get_owner ( ) ;
2014-02-10 01:10:30 +00:00
if ( p_reown_map . has ( owner ) )
2017-03-05 15:44:50 +00:00
owner = p_reown_map [ owner ] ;
2014-02-10 01:10:30 +00:00
if ( owner ) {
NodePath p = get_path_to ( owner ) ;
2017-03-05 15:44:50 +00:00
if ( owner ! = this ) {
2014-02-10 01:10:30 +00:00
Node * new_owner = node - > get_node ( p ) ;
if ( new_owner ) {
node - > set_owner ( new_owner ) ;
}
}
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
get_child ( i ) - > _duplicate_and_reown ( node , p_reown_map ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-11-19 12:05:18 +00:00
// Duplication of signals must happen after all the node descendants have been copied,
// because re-targeting of connections from some descendant to another is not possible
// if the emitter node comes later in tree order than the receiver
2017-03-05 15:44:50 +00:00
void Node : : _duplicate_signals ( const Node * p_original , Node * p_copy ) const {
2015-05-10 18:45:33 +00:00
2017-03-05 15:44:50 +00:00
if ( this ! = p_original & & ( get_owner ( ) ! = p_original & & get_owner ( ) ! = p_original - > get_owner ( ) ) )
2015-05-10 18:45:33 +00:00
return ;
List < Connection > conns ;
get_all_signal_connections ( & conns ) ;
2017-03-05 15:44:50 +00:00
for ( List < Connection > : : Element * E = conns . front ( ) ; E ; E = E - > next ( ) ) {
2016-07-07 00:43:31 +00:00
2017-03-05 15:44:50 +00:00
if ( E - > get ( ) . flags & CONNECT_PERSIST ) {
2015-05-10 18:45:33 +00:00
//user connected
NodePath p = p_original - > get_path_to ( this ) ;
Node * copy = p_copy - > get_node ( p ) ;
2017-08-24 20:58:51 +00:00
Node * target = Object : : cast_to < Node > ( E - > get ( ) . target ) ;
2016-07-07 00:43:31 +00:00
if ( ! target ) {
2015-05-10 18:45:33 +00:00
continue ;
2016-07-07 00:43:31 +00:00
}
2015-05-10 18:45:33 +00:00
NodePath ptarget = p_original - > get_path_to ( target ) ;
2018-10-03 12:59:16 +00:00
Node * copytarget = target ;
// Atempt to find a path to the duplicate target, if it seems it's not part
// of the duplicated and not yet parented hierarchy then at least try to connect
2017-11-19 12:05:18 +00:00
// to the same target as the original
2018-10-03 12:59:16 +00:00
if ( p_copy - > has_node ( ptarget ) )
copytarget = p_copy - > get_node ( ptarget ) ;
2017-11-19 12:05:18 +00:00
2018-10-10 23:30:12 +00:00
if ( copy & & copytarget & & ! copy - > is_connected ( E - > get ( ) . signal , copytarget , E - > get ( ) . method ) ) {
2017-11-21 08:46:19 +00:00
copy - > connect ( E - > get ( ) . signal , copytarget , E - > get ( ) . method , E - > get ( ) . binds , E - > get ( ) . flags ) ;
2015-05-10 18:45:33 +00:00
}
}
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
get_child ( i ) - > _duplicate_signals ( p_original , p_copy ) ;
2015-05-10 18:45:33 +00:00
}
}
2017-03-05 15:44:50 +00:00
Node * Node : : duplicate_and_reown ( const Map < Node * , Node * > & p_reown_map ) const {
2015-05-10 18:45:33 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( get_filename ( ) ! = " " , NULL ) ;
2014-02-10 01:10:30 +00:00
2017-01-03 02:03:46 +00:00
Object * obj = ClassDB : : instance ( get_class ( ) ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_V_MSG ( ! obj , NULL , " Node: Could not duplicate: " + String ( get_class ( ) ) + " . " ) ;
2014-02-10 01:10:30 +00:00
2019-08-07 10:54:30 +00:00
Node * node = Object : : cast_to < Node > ( obj ) ;
if ( ! node ) {
memdelete ( obj ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_V_MSG ( NULL , " Node: Could not duplicate: " + String ( get_class ( ) ) + " . " ) ;
2019-08-07 10:54:30 +00:00
}
2014-02-10 01:10:30 +00:00
node - > set_name ( get_name ( ) ) ;
2014-11-02 14:31:01 +00:00
List < PropertyInfo > plist ;
get_property_list ( & plist ) ;
2017-03-05 15:44:50 +00:00
for ( List < PropertyInfo > : : Element * E = plist . front ( ) ; E ; E = E - > next ( ) ) {
2014-11-02 14:31:01 +00:00
2017-03-05 15:44:50 +00:00
if ( ! ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE ) )
2014-11-02 14:31:01 +00:00
continue ;
String name = E - > get ( ) . name ;
2017-03-05 15:44:50 +00:00
node - > set ( name , get ( name ) ) ;
2014-11-02 14:31:01 +00:00
}
2018-09-14 16:13:41 +00:00
List < GroupInfo > groups ;
get_groups ( & groups ) ;
for ( List < GroupInfo > : : Element * E = groups . front ( ) ; E ; E = E - > next ( ) )
node - > add_to_group ( E - > get ( ) . name , E - > get ( ) . persistent ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2014-11-02 14:31:01 +00:00
2017-03-05 15:44:50 +00:00
get_child ( i ) - > _duplicate_and_reown ( node , p_reown_map ) ;
2014-02-10 01:10:30 +00:00
}
2017-11-19 13:32:10 +00:00
// Duplication of signals must happen after all the node descendants have been copied,
// because re-targeting of connections from some descendant to another is not possible
// if the emitter node comes later in tree order than the receiver
2017-03-05 15:44:50 +00:00
_duplicate_signals ( this , node ) ;
2014-02-10 01:10:30 +00:00
return node ;
}
2017-03-05 15:44:50 +00:00
static void find_owned_by ( Node * p_by , Node * p_node , List < Node * > * p_owned ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( p_node - > get_owner ( ) = = p_by )
2014-02-10 01:10:30 +00:00
p_owned - > push_back ( p_node ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
find_owned_by ( p_by , p_node - > get_child ( i ) , p_owned ) ;
2014-02-10 01:10:30 +00:00
}
}
struct _NodeReplaceByPair {
String name ;
Variant value ;
} ;
2017-03-05 15:44:50 +00:00
void Node : : replace_by ( Node * p_node , bool p_keep_data ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL_NULL ( p_node ) ;
ERR_FAIL_COND ( p_node - > data . parent ) ;
2017-03-05 15:44:50 +00:00
List < Node * > owned = data . owned ;
List < Node * > owned_by_owner ;
Node * owner = ( data . owner = = this ) ? p_node : data . owner ;
2014-02-10 01:10:30 +00:00
List < _NodeReplaceByPair > replace_data ;
if ( p_keep_data ) {
List < PropertyInfo > plist ;
get_property_list ( & plist ) ;
2017-03-05 15:44:50 +00:00
for ( List < PropertyInfo > : : Element * E = plist . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
_NodeReplaceByPair rd ;
2017-03-05 15:44:50 +00:00
if ( ! ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE ) )
2014-02-10 01:10:30 +00:00
continue ;
2017-03-05 15:44:50 +00:00
rd . name = E - > get ( ) . name ;
rd . value = get ( rd . name ) ;
2014-02-10 01:10:30 +00:00
}
2016-11-02 23:19:32 +00:00
List < GroupInfo > groups ;
get_groups ( & groups ) ;
2017-03-05 15:44:50 +00:00
for ( List < GroupInfo > : : Element * E = groups . front ( ) ; E ; E = E - > next ( ) )
2016-11-02 23:19:32 +00:00
p_node - > add_to_group ( E - > get ( ) . name , E - > get ( ) . persistent ) ;
2014-02-10 01:10:30 +00:00
}
2016-06-09 14:24:12 +00:00
_replace_connections_target ( p_node ) ;
2014-02-10 01:10:30 +00:00
if ( data . owner ) {
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + )
find_owned_by ( data . owner , get_child ( i ) , & owned_by_owner ) ;
2014-02-10 01:10:30 +00:00
}
Node * parent = data . parent ;
int pos_in_parent = data . pos ;
if ( data . parent ) {
parent - > remove_child ( this ) ;
parent - > add_child ( p_node ) ;
2017-03-05 15:44:50 +00:00
parent - > move_child ( p_node , pos_in_parent ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
while ( get_child_count ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Node * child = get_child ( 0 ) ;
2014-02-10 01:10:30 +00:00
remove_child ( child ) ;
2018-03-07 00:21:46 +00:00
if ( ! child - > is_owned_by_parent ( ) ) {
// add the custom children to the p_node
p_node - > add_child ( child ) ;
}
2014-02-10 01:10:30 +00:00
}
p_node - > set_owner ( owner ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < owned . size ( ) ; i + + )
2014-02-10 01:10:30 +00:00
owned [ i ] - > set_owner ( p_node ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < owned_by_owner . size ( ) ; i + + )
2014-02-10 01:10:30 +00:00
owned_by_owner [ i ] - > set_owner ( owner ) ;
p_node - > set_filename ( get_filename ( ) ) ;
2017-03-05 15:44:50 +00:00
for ( List < _NodeReplaceByPair > : : Element * E = replace_data . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
p_node - > set ( E - > get ( ) . name , E - > get ( ) . value ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
void Node : : _replace_connections_target ( Node * p_new_target ) {
2016-06-09 14:24:12 +00:00
List < Connection > cl ;
get_signals_connected_to_this ( & cl ) ;
2017-03-05 15:44:50 +00:00
for ( List < Connection > : : Element * E = cl . front ( ) ; E ; E = E - > next ( ) ) {
2016-06-09 14:24:12 +00:00
2017-03-05 15:44:50 +00:00
Connection & c = E - > get ( ) ;
2016-06-09 14:24:12 +00:00
2017-03-11 19:21:04 +00:00
if ( c . flags & CONNECT_PERSIST ) {
c . source - > disconnect ( c . signal , this , c . method ) ;
2019-04-19 20:03:00 +00:00
bool valid = p_new_target - > has_method ( c . method ) | | Ref < Script > ( p_new_target - > get_script ( ) ) . is_null ( ) | | Ref < Script > ( p_new_target - > get_script ( ) ) - > has_method ( c . method ) ;
2019-08-08 20:11:48 +00:00
ERR_CONTINUE_MSG ( ! valid , " Attempt to connect signal ' " + c . source - > get_class ( ) + " . " + c . signal + " ' to nonexistent method ' " + c . target - > get_class ( ) + " . " + c . method + " '. " ) ;
2017-03-11 19:21:04 +00:00
c . source - > connect ( c . signal , p_new_target , c . method , c . binds , c . flags ) ;
}
2016-06-09 14:24:12 +00:00
}
}
2014-02-10 01:10:30 +00:00
Vector < Variant > Node : : make_binds ( VARIANT_ARG_DECLARE ) {
Vector < Variant > ret ;
2017-03-05 15:44:50 +00:00
if ( p_arg1 . get_type ( ) = = Variant : : NIL )
2014-02-10 01:10:30 +00:00
return ret ;
else
ret . push_back ( p_arg1 ) ;
2017-03-05 15:44:50 +00:00
if ( p_arg2 . get_type ( ) = = Variant : : NIL )
2014-02-10 01:10:30 +00:00
return ret ;
else
ret . push_back ( p_arg2 ) ;
2017-03-05 15:44:50 +00:00
if ( p_arg3 . get_type ( ) = = Variant : : NIL )
2014-02-10 01:10:30 +00:00
return ret ;
else
ret . push_back ( p_arg3 ) ;
2017-03-05 15:44:50 +00:00
if ( p_arg4 . get_type ( ) = = Variant : : NIL )
2014-02-10 01:10:30 +00:00
return ret ;
else
ret . push_back ( p_arg4 ) ;
2017-03-05 15:44:50 +00:00
if ( p_arg5 . get_type ( ) = = Variant : : NIL )
2014-02-10 01:10:30 +00:00
return ret ;
else
ret . push_back ( p_arg5 ) ;
return ret ;
}
2017-03-05 15:44:50 +00:00
bool Node : : has_node_and_resource ( const NodePath & p_path ) const {
2014-02-10 01:10:30 +00:00
if ( ! has_node ( p_path ) )
return false ;
2019-06-26 13:15:11 +00:00
RES res ;
Vector < StringName > leftover_path ;
Node * node = get_node_and_resource ( p_path , res , leftover_path , false ) ;
2014-02-10 01:10:30 +00:00
2019-07-10 18:03:04 +00:00
return node ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Array Node : : _get_node_and_resource ( const NodePath & p_path ) {
2014-02-10 01:10:30 +00:00
RES res ;
2017-05-30 20:20:15 +00:00
Vector < StringName > leftover_path ;
2019-06-26 13:15:11 +00:00
Node * node = get_node_and_resource ( p_path , res , leftover_path , false ) ;
2014-02-10 01:10:30 +00:00
Array result ;
if ( node )
result . push_back ( node ) ;
else
result . push_back ( Variant ( ) ) ;
if ( res . is_valid ( ) )
result . push_back ( res ) ;
else
result . push_back ( Variant ( ) ) ;
2017-05-30 20:20:15 +00:00
result . push_back ( NodePath ( Vector < StringName > ( ) , leftover_path , false ) ) ;
2014-02-10 01:10:30 +00:00
return result ;
}
2017-05-30 20:20:15 +00:00
Node * Node : : get_node_and_resource ( const NodePath & p_path , RES & r_res , Vector < StringName > & r_leftover_subpath , bool p_last_is_property ) const {
2014-02-10 01:10:30 +00:00
Node * node = get_node ( p_path ) ;
r_res = RES ( ) ;
2017-05-30 20:20:15 +00:00
r_leftover_subpath = Vector < StringName > ( ) ;
2014-02-10 01:10:30 +00:00
if ( ! node )
return NULL ;
if ( p_path . get_subname_count ( ) ) {
2017-05-30 20:20:15 +00:00
int j = 0 ;
// If not p_last_is_property, we shouldn't consider the last one as part of the resource
2019-06-26 13:15:11 +00:00
for ( ; j < p_path . get_subname_count ( ) - ( int ) p_last_is_property ; j + + ) {
2019-07-10 18:03:04 +00:00
Variant new_res_v = j = = 0 ? node - > get ( p_path . get_subname ( j ) ) : r_res - > get ( p_path . get_subname ( j ) ) ;
if ( new_res_v . get_type ( ) = = Variant : : NIL ) { // Found nothing on that path
return NULL ;
}
RES new_res = new_res_v ;
2017-05-30 20:20:15 +00:00
2019-07-10 18:03:04 +00:00
if ( new_res . is_null ( ) ) { // No longer a resource, assume property
2017-05-30 20:20:15 +00:00
break ;
}
r_res = new_res ;
}
for ( ; j < p_path . get_subname_count ( ) ; j + + ) {
// Put the rest of the subpath in the leftover path
r_leftover_subpath . push_back ( p_path . get_subname ( j ) ) ;
2014-02-10 01:10:30 +00:00
}
}
return node ;
}
2014-11-06 00:20:42 +00:00
void Node : : _set_tree ( SceneTree * p_tree ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
SceneTree * tree_changed_a = NULL ;
SceneTree * tree_changed_b = NULL ;
2014-02-10 01:10:30 +00:00
2017-01-14 11:26:56 +00:00
//ERR_FAIL_COND(p_scene && data.parent && !data.parent->data.scene); //nobug if both are null
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree ) {
_propagate_exit_tree ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
tree_changed_a = data . tree ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
data . tree = p_tree ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree ) {
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
_propagate_enter_tree ( ) ;
2016-11-29 23:07:29 +00:00
if ( ! data . parent | | data . parent - > data . ready_notified ) { // No parent (root) or parent ready
_propagate_ready ( ) ; //reverse_notification(NOTIFICATION_READY);
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
tree_changed_b = data . tree ;
2014-02-10 01:10:30 +00:00
}
if ( tree_changed_a )
tree_changed_a - > tree_changed ( ) ;
if ( tree_changed_b )
tree_changed_b - > tree_changed ( ) ;
}
2018-10-03 14:13:34 +00:00
# ifdef DEBUG_ENABLED
2014-02-10 01:10:30 +00:00
static void _Node_debug_sn ( Object * p_obj ) {
2017-08-24 20:58:51 +00:00
Node * n = Object : : cast_to < Node > ( p_obj ) ;
2014-02-10 01:10:30 +00:00
if ( ! n )
return ;
2014-11-06 00:20:42 +00:00
if ( n - > is_inside_tree ( ) )
2014-02-10 01:10:30 +00:00
return ;
2017-03-05 15:44:50 +00:00
Node * p = n ;
while ( p - > get_parent ( ) ) {
p = p - > get_parent ( ) ;
2014-02-10 01:10:30 +00:00
}
String path ;
2017-03-05 15:44:50 +00:00
if ( p = = n )
path = n - > get_name ( ) ;
2014-02-10 01:10:30 +00:00
else
2017-03-05 15:44:50 +00:00
path = String ( p - > get_name ( ) ) + " / " + p - > get_path_to ( n ) ;
2018-08-24 07:35:07 +00:00
print_line ( itos ( p_obj - > get_instance_id ( ) ) + " - Stray Node: " + path + " (Type: " + n - > get_class ( ) + " ) " ) ;
2014-02-10 01:10:30 +00:00
}
2018-10-03 14:13:34 +00:00
# endif // DEBUG_ENABLED
2014-02-10 01:10:30 +00:00
void Node : : _print_stray_nodes ( ) {
print_stray_nodes ( ) ;
}
void Node : : print_stray_nodes ( ) {
# ifdef DEBUG_ENABLED
ObjectDB : : debug_objects ( _Node_debug_sn ) ;
# endif
}
void Node : : queue_delete ( ) {
2017-09-20 19:49:46 +00:00
if ( is_inside_tree ( ) ) {
get_tree ( ) - > queue_delete ( this ) ;
} else {
SceneTree : : get_singleton ( ) - > queue_delete ( this ) ;
}
2014-02-10 01:10:30 +00:00
}
Array Node : : _get_children ( ) const {
Array arr ;
int cc = get_child_count ( ) ;
arr . resize ( cc ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < cc ; i + + )
arr [ i ] = get_child ( i ) ;
2014-02-10 01:10:30 +00:00
return arr ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_import_path ( const NodePath & p_import_path ) {
2014-06-19 05:23:03 +00:00
2018-04-29 17:49:26 +00:00
# ifdef TOOLS_ENABLED
2017-03-05 15:44:50 +00:00
data . import_path = p_import_path ;
2018-04-29 17:49:26 +00:00
# endif
2014-06-19 05:23:03 +00:00
}
NodePath Node : : get_import_path ( ) const {
2018-04-29 17:49:26 +00:00
# ifdef TOOLS_ENABLED
2014-06-19 05:23:03 +00:00
return data . import_path ;
2018-04-29 17:49:26 +00:00
# else
return NodePath ( ) ;
2014-06-19 05:23:03 +00:00
# endif
2018-04-29 17:49:26 +00:00
}
2014-06-19 05:23:03 +00:00
2017-03-05 15:44:50 +00:00
static void _add_nodes_to_options ( const Node * p_base , const Node * p_node , List < String > * r_options ) {
2014-12-17 01:31:57 +00:00
2018-12-18 01:53:54 +00:00
# ifdef TOOLS_ENABLED
const String quote_style = EDITOR_DEF ( " text_editor/completion/use_single_quotes " , 0 ) ? " ' " : " \" " ;
# else
const String quote_style = " \" " ;
# endif
2017-03-05 15:44:50 +00:00
if ( p_node ! = p_base & & ! p_node - > get_owner ( ) )
2014-12-17 01:31:57 +00:00
return ;
String n = p_base - > get_path_to ( p_node ) ;
2018-12-18 01:53:54 +00:00
r_options - > push_back ( quote_style + n + quote_style ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_add_nodes_to_options ( p_base , p_node - > get_child ( i ) , r_options ) ;
2014-12-17 01:31:57 +00:00
}
}
2017-03-05 15:44:50 +00:00
void Node : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
2014-12-17 01:31:57 +00:00
2017-03-05 15:44:50 +00:00
String pf = p_function ;
if ( ( pf = = " has_node " | | pf = = " get_node " ) & & p_idx = = 0 ) {
2014-12-17 01:31:57 +00:00
2017-03-05 15:44:50 +00:00
_add_nodes_to_options ( this , this , r_options ) ;
2014-12-17 01:31:57 +00:00
}
2017-03-05 15:44:50 +00:00
Object : : get_argument_options ( p_function , p_idx , r_options ) ;
2014-12-17 01:31:57 +00:00
}
2014-02-10 01:10:30 +00:00
2015-06-22 03:03:19 +00:00
void Node : : clear_internal_tree_resource_paths ( ) {
clear_internal_resource_paths ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2015-06-22 03:03:19 +00:00
data . children [ i ] - > clear_internal_tree_resource_paths ( ) ;
}
}
2016-05-17 21:27:15 +00:00
String Node : : get_configuration_warning ( ) const {
2020-01-07 20:28:13 +00:00
if ( get_script_instance ( ) & & get_script_instance ( ) - > get_script ( ) . is_valid ( ) & &
get_script_instance ( ) - > get_script ( ) - > is_tool ( ) & & get_script_instance ( ) - > has_method ( " _get_configuration_warning " ) ) {
2018-08-14 19:52:40 +00:00
return get_script_instance ( ) - > call ( " _get_configuration_warning " ) ;
}
2016-05-17 21:27:15 +00:00
return String ( ) ;
}
void Node : : update_configuration_warning ( ) {
# ifdef TOOLS_ENABLED
if ( ! is_inside_tree ( ) )
return ;
2017-03-05 15:44:50 +00:00
if ( get_tree ( ) - > get_edited_scene_root ( ) & & ( get_tree ( ) - > get_edited_scene_root ( ) = = this | | get_tree ( ) - > get_edited_scene_root ( ) - > is_a_parent_of ( this ) ) ) {
get_tree ( ) - > emit_signal ( SceneStringNames : : get_singleton ( ) - > node_configuration_warning_changed , this ) ;
2016-05-17 21:27:15 +00:00
}
# endif
}
2016-06-21 01:57:07 +00:00
bool Node : : is_owned_by_parent ( ) const {
2016-06-21 11:40:56 +00:00
return data . parent_owned ;
2016-06-21 01:57:07 +00:00
}
2016-06-28 16:10:15 +00:00
void Node : : set_display_folded ( bool p_folded ) {
2017-03-05 15:44:50 +00:00
data . display_folded = p_folded ;
2016-06-28 16:10:15 +00:00
}
bool Node : : is_displayed_folded ( ) const {
return data . display_folded ;
}
2017-01-10 21:02:19 +00:00
void Node : : request_ready ( ) {
2017-03-05 15:44:50 +00:00
data . ready_first = true ;
2017-01-10 21:02:19 +00:00
}
2014-02-10 01:10:30 +00:00
void Node : : _bind_methods ( ) {
2017-03-05 15:44:50 +00:00
GLOBAL_DEF ( " node/name_num_separator " , 0 ) ;
2017-07-19 20:00:46 +00:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " node/name_num_separator " , PropertyInfo ( Variant : : INT , " node/name_num_separator " , PROPERTY_HINT_ENUM , " None,Space,Underscore,Dash " ) ) ;
2017-03-05 15:44:50 +00:00
GLOBAL_DEF ( " node/name_casing " , NAME_CASING_PASCAL_CASE ) ;
2017-07-19 20:00:46 +00:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " node/name_casing " , PropertyInfo ( Variant : : INT , " node/name_casing " , PROPERTY_HINT_ENUM , " PascalCase,camelCase,snake_case " ) ) ;
2016-10-07 18:25:29 +00:00
2017-09-05 21:39:32 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_child_below_node " , " node " , " child_node " , " legible_unique_name " ) , & Node : : add_child_below_node , DEFVAL ( false ) ) ;
2017-02-13 11:47:24 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_name " , " name " ) , & Node : : set_name ) ;
ClassDB : : bind_method ( D_METHOD ( " get_name " ) , & Node : : get_name ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_child " , " node " , " legible_unique_name " ) , & Node : : add_child , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_child " , " node " ) , & Node : : remove_child ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_child_count " ) , & Node : : get_child_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_children " ) , & Node : : _get_children ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_child " , " idx " ) , & Node : : get_child ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_node " , " path " ) , & Node : : has_node ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_node " , " path " ) , & Node : : get_node ) ;
2019-01-29 16:15:34 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_node_or_null " , " path " ) , & Node : : get_node_or_null ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_parent " ) , & Node : : get_parent ) ;
ClassDB : : bind_method ( D_METHOD ( " find_node " , " mask " , " recursive " , " owned " ) , & Node : : find_node , DEFVAL ( true ) , DEFVAL ( true ) ) ;
2018-09-15 16:22:06 +00:00
ClassDB : : bind_method ( D_METHOD ( " find_parent " , " mask " ) , & Node : : find_parent ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_node_and_resource " , " path " ) , & Node : : has_node_and_resource ) ;
ClassDB : : bind_method ( D_METHOD ( " get_node_and_resource " , " path " ) , & Node : : _get_node_and_resource ) ;
ClassDB : : bind_method ( D_METHOD ( " is_inside_tree " ) , & Node : : is_inside_tree ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_a_parent_of " , " node " ) , & Node : : is_a_parent_of ) ;
ClassDB : : bind_method ( D_METHOD ( " is_greater_than " , " node " ) , & Node : : is_greater_than ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_path " ) , & Node : : get_path ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_path_to " , " node " ) , & Node : : get_path_to ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_to_group " , " group " , " persistent " ) , & Node : : add_to_group , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_from_group " , " group " ) , & Node : : remove_from_group ) ;
ClassDB : : bind_method ( D_METHOD ( " is_in_group " , " group " ) , & Node : : is_in_group ) ;
2017-09-10 13:37:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " move_child " , " child_node " , " to_position " ) , & Node : : move_child ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_groups " ) , & Node : : _get_groups ) ;
ClassDB : : bind_method ( D_METHOD ( " raise " ) , & Node : : raise ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_owner " , " owner " ) , & Node : : set_owner ) ;
ClassDB : : bind_method ( D_METHOD ( " get_owner " ) , & Node : : get_owner ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " remove_and_skip " ) , & Node : : remove_and_skip ) ;
ClassDB : : bind_method ( D_METHOD ( " get_index " ) , & Node : : get_index ) ;
ClassDB : : bind_method ( D_METHOD ( " print_tree " ) , & Node : : print_tree ) ;
2018-02-28 09:12:06 +00:00
ClassDB : : bind_method ( D_METHOD ( " print_tree_pretty " ) , & Node : : print_tree_pretty ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_filename " , " filename " ) , & Node : : set_filename ) ;
ClassDB : : bind_method ( D_METHOD ( " get_filename " ) , & Node : : get_filename ) ;
ClassDB : : bind_method ( D_METHOD ( " propagate_notification " , " what " ) , & Node : : propagate_notification ) ;
2017-08-19 13:17:06 +00:00
ClassDB : : bind_method ( D_METHOD ( " propagate_call " , " method " , " args " , " parent_first " ) , & Node : : propagate_call , DEFVAL ( Array ( ) ) , DEFVAL ( false ) ) ;
2017-09-30 14:19:07 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_physics_process " , " enable " ) , & Node : : set_physics_process ) ;
ClassDB : : bind_method ( D_METHOD ( " get_physics_process_delta_time " ) , & Node : : get_physics_process_delta_time ) ;
ClassDB : : bind_method ( D_METHOD ( " is_physics_processing " ) , & Node : : is_physics_processing ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_process_delta_time " ) , & Node : : get_process_delta_time ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process " , " enable " ) , & Node : : set_process ) ;
2018-07-02 05:30:40 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_process_priority " , " priority " ) , & Node : : set_process_priority ) ;
2019-11-16 21:07:02 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_process_priority " ) , & Node : : get_process_priority ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_processing " ) , & Node : : is_processing ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process_input " , " enable " ) , & Node : : set_process_input ) ;
ClassDB : : bind_method ( D_METHOD ( " is_processing_input " ) , & Node : : is_processing_input ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process_unhandled_input " , " enable " ) , & Node : : set_process_unhandled_input ) ;
ClassDB : : bind_method ( D_METHOD ( " is_processing_unhandled_input " ) , & Node : : is_processing_unhandled_input ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process_unhandled_key_input " , " enable " ) , & Node : : set_process_unhandled_key_input ) ;
ClassDB : : bind_method ( D_METHOD ( " is_processing_unhandled_key_input " ) , & Node : : is_processing_unhandled_key_input ) ;
ClassDB : : bind_method ( D_METHOD ( " set_pause_mode " , " mode " ) , & Node : : set_pause_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_pause_mode " ) , & Node : : get_pause_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " can_process " ) , & Node : : can_process ) ;
ClassDB : : bind_method ( D_METHOD ( " print_stray_nodes " ) , & Node : : _print_stray_nodes ) ;
ClassDB : : bind_method ( D_METHOD ( " get_position_in_parent " ) , & Node : : get_position_in_parent ) ;
2019-04-11 17:35:23 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_display_folded " , " fold " ) , & Node : : set_display_folded ) ;
ClassDB : : bind_method ( D_METHOD ( " is_displayed_folded " ) , & Node : : is_displayed_folded ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process_internal " , " enable " ) , & Node : : set_process_internal ) ;
ClassDB : : bind_method ( D_METHOD ( " is_processing_internal " ) , & Node : : is_processing_internal ) ;
2017-09-30 14:19:07 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_physics_process_internal " , " enable " ) , & Node : : set_physics_process_internal ) ;
ClassDB : : bind_method ( D_METHOD ( " is_physics_processing_internal " ) , & Node : : is_physics_processing_internal ) ;
2017-03-05 15:44:50 +00:00
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_tree " ) , & Node : : get_tree ) ;
2017-03-05 15:44:50 +00:00
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " duplicate " , " flags " ) , & Node : : duplicate , DEFVAL ( DUPLICATE_USE_INSTANCING | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS ) ) ;
ClassDB : : bind_method ( D_METHOD ( " replace_by " , " node " , " keep_data " ) , & Node : : replace_by , DEFVAL ( false ) ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_scene_instance_load_placeholder " , " load_placeholder " ) , & Node : : set_scene_instance_load_placeholder ) ;
ClassDB : : bind_method ( D_METHOD ( " get_scene_instance_load_placeholder " ) , & Node : : get_scene_instance_load_placeholder ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_viewport " ) , & Node : : get_viewport ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " queue_free " ) , & Node : : queue_delete ) ;
ClassDB : : bind_method ( D_METHOD ( " request_ready " ) , & Node : : request_ready ) ;
2017-07-03 13:44:45 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_network_master " , " id " , " recursive " ) , & Node : : set_network_master , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_network_master " ) , & Node : : get_network_master ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_network_master " ) , & Node : : is_network_master ) ;
2018-05-08 08:51:04 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_multiplayer " ) , & Node : : get_multiplayer ) ;
ClassDB : : bind_method ( D_METHOD ( " get_custom_multiplayer " ) , & Node : : get_custom_multiplayer ) ;
ClassDB : : bind_method ( D_METHOD ( " set_custom_multiplayer " , " api " ) , & Node : : set_custom_multiplayer ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " rpc_config " , " method " , " mode " ) , & Node : : rpc_config ) ;
ClassDB : : bind_method ( D_METHOD ( " rset_config " , " property " , " mode " ) , & Node : : rset_config ) ;
2016-05-17 21:27:15 +00:00
2019-08-15 12:50:26 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_editor_description " , " editor_description " ) , & Node : : set_editor_description ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_editor_description " ) , & Node : : get_editor_description ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " editor_description " , PROPERTY_HINT_MULTILINE_TEXT , " " , PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL ) , " _set_editor_description " , " _get_editor_description " ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_import_path " , " import_path " ) , & Node : : set_import_path ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_import_path " ) , & Node : : get_import_path ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : NODE_PATH , " _import_path " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) , " _set_import_path " , " _get_import_path " ) ;
2014-06-19 05:23:03 +00:00
2016-08-14 21:49:50 +00:00
{
MethodInfo mi ;
2016-08-19 19:48:08 +00:00
2017-03-05 15:44:50 +00:00
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING , " method " ) ) ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
mi . name = " rpc " ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " rpc " , & Node : : _rpc_bind , mi ) ;
mi . name = " rpc_unreliable " ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " rpc_unreliable " , & Node : : _rpc_unreliable_bind , mi ) ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
mi . arguments . push_front ( PropertyInfo ( Variant : : INT , " peer_id " ) ) ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
mi . name = " rpc_id " ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " rpc_id " , & Node : : _rpc_id_bind , mi ) ;
mi . name = " rpc_unreliable_id " ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " rpc_unreliable_id " , & Node : : _rpc_unreliable_id_bind , mi ) ;
2016-08-14 21:49:50 +00:00
}
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " rset " , " property " , " value " ) , & Node : : rset ) ;
ClassDB : : bind_method ( D_METHOD ( " rset_id " , " peer_id " , " property " , " value " ) , & Node : : rset_id ) ;
ClassDB : : bind_method ( D_METHOD ( " rset_unreliable " , " property " , " value " ) , & Node : : rset_unreliable ) ;
ClassDB : : bind_method ( D_METHOD ( " rset_unreliable_id " , " peer_id " , " property " , " value " ) , & Node : : rset_unreliable_id ) ;
2016-08-14 21:49:50 +00:00
2019-10-17 10:20:35 +00:00
ClassDB : : bind_method ( D_METHOD ( " update_configuration_warning " ) , & Node : : update_configuration_warning ) ;
2017-03-05 15:44:50 +00:00
BIND_CONSTANT ( NOTIFICATION_ENTER_TREE ) ;
BIND_CONSTANT ( NOTIFICATION_EXIT_TREE ) ;
BIND_CONSTANT ( NOTIFICATION_MOVED_IN_PARENT ) ;
BIND_CONSTANT ( NOTIFICATION_READY ) ;
2017-10-21 18:58:02 +00:00
BIND_CONSTANT ( NOTIFICATION_PAUSED ) ;
BIND_CONSTANT ( NOTIFICATION_UNPAUSED ) ;
2017-09-30 14:19:07 +00:00
BIND_CONSTANT ( NOTIFICATION_PHYSICS_PROCESS ) ;
2017-03-05 15:44:50 +00:00
BIND_CONSTANT ( NOTIFICATION_PROCESS ) ;
BIND_CONSTANT ( NOTIFICATION_PARENTED ) ;
BIND_CONSTANT ( NOTIFICATION_UNPARENTED ) ;
BIND_CONSTANT ( NOTIFICATION_INSTANCED ) ;
BIND_CONSTANT ( NOTIFICATION_DRAG_BEGIN ) ;
BIND_CONSTANT ( NOTIFICATION_DRAG_END ) ;
BIND_CONSTANT ( NOTIFICATION_PATH_CHANGED ) ;
BIND_CONSTANT ( NOTIFICATION_INTERNAL_PROCESS ) ;
2017-09-30 14:19:07 +00:00
BIND_CONSTANT ( NOTIFICATION_INTERNAL_PHYSICS_PROCESS ) ;
2017-03-05 15:44:50 +00:00
2019-04-04 13:34:03 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_MOUSE_ENTER ) ;
BIND_CONSTANT ( NOTIFICATION_WM_MOUSE_EXIT ) ;
BIND_CONSTANT ( NOTIFICATION_WM_FOCUS_IN ) ;
BIND_CONSTANT ( NOTIFICATION_WM_FOCUS_OUT ) ;
BIND_CONSTANT ( NOTIFICATION_WM_QUIT_REQUEST ) ;
BIND_CONSTANT ( NOTIFICATION_WM_GO_BACK_REQUEST ) ;
BIND_CONSTANT ( NOTIFICATION_WM_UNFOCUS_REQUEST ) ;
BIND_CONSTANT ( NOTIFICATION_OS_MEMORY_WARNING ) ;
BIND_CONSTANT ( NOTIFICATION_TRANSLATION_CHANGED ) ;
BIND_CONSTANT ( NOTIFICATION_WM_ABOUT ) ;
BIND_CONSTANT ( NOTIFICATION_CRASH ) ;
BIND_CONSTANT ( NOTIFICATION_OS_IME_UPDATE ) ;
2019-09-09 21:42:17 +00:00
BIND_CONSTANT ( NOTIFICATION_APP_RESUMED ) ;
BIND_CONSTANT ( NOTIFICATION_APP_PAUSED ) ;
2019-04-04 13:34:03 +00:00
2017-08-20 15:45:01 +00:00
BIND_ENUM_CONSTANT ( PAUSE_MODE_INHERIT ) ;
BIND_ENUM_CONSTANT ( PAUSE_MODE_STOP ) ;
BIND_ENUM_CONSTANT ( PAUSE_MODE_PROCESS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_SIGNALS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_GROUPS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_SCRIPTS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_USE_INSTANCING ) ;
2017-03-05 15:44:50 +00:00
2018-01-20 21:57:59 +00:00
ADD_SIGNAL ( MethodInfo ( " ready " ) ) ;
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " renamed " ) ) ;
ADD_SIGNAL ( MethodInfo ( " tree_entered " ) ) ;
2018-01-12 11:28:39 +00:00
ADD_SIGNAL ( MethodInfo ( " tree_exiting " ) ) ;
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " tree_exited " ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ADD_GROUP ( " Pause " , " pause_ " ) ;
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " pause_mode " , PROPERTY_HINT_ENUM , " Inherit,Stop,Process " ) , " set_pause_mode " , " get_pause_mode " ) ;
2019-04-11 17:35:23 +00:00
# ifdef ENABLE_DEPRECATED
//no longer exists, but remains for compatibility (keep previous scenes folded
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " editor/display_folded " , PROPERTY_HINT_NONE , " " , 0 ) , " set_display_folded " , " is_displayed_folded " ) ;
# endif
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " name " , PROPERTY_HINT_NONE , " " , 0 ) , " set_name " , " get_name " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " filename " , PROPERTY_HINT_NONE , " " , 0 ) , " set_filename " , " get_filename " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " owner " , PROPERTY_HINT_RESOURCE_TYPE , " Node " , 0 ) , " set_owner " , " get_owner " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " multiplayer " , PROPERTY_HINT_RESOURCE_TYPE , " MultiplayerAPI " , 0 ) , " " , " get_multiplayer " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " custom_multiplayer " , PROPERTY_HINT_RESOURCE_TYPE , " MultiplayerAPI " , 0 ) , " set_custom_multiplayer " , " get_custom_multiplayer " ) ;
2019-11-16 21:07:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " process_priority " ) , " set_process_priority " , " get_process_priority " ) ;
2017-03-05 15:44:50 +00:00
BIND_VMETHOD ( MethodInfo ( " _process " , PropertyInfo ( Variant : : REAL , " delta " ) ) ) ;
2017-09-30 14:19:07 +00:00
BIND_VMETHOD ( MethodInfo ( " _physics_process " , PropertyInfo ( Variant : : REAL , " delta " ) ) ) ;
2017-03-05 15:44:50 +00:00
BIND_VMETHOD ( MethodInfo ( " _enter_tree " ) ) ;
BIND_VMETHOD ( MethodInfo ( " _exit_tree " ) ) ;
BIND_VMETHOD ( MethodInfo ( " _ready " ) ) ;
2017-05-20 15:38:03 +00:00
BIND_VMETHOD ( MethodInfo ( " _input " , PropertyInfo ( Variant : : OBJECT , " event " , PROPERTY_HINT_RESOURCE_TYPE , " InputEvent " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( " _unhandled_input " , PropertyInfo ( Variant : : OBJECT , " event " , PROPERTY_HINT_RESOURCE_TYPE , " InputEvent " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( " _unhandled_key_input " , PropertyInfo ( Variant : : OBJECT , " event " , PROPERTY_HINT_RESOURCE_TYPE , " InputEventKey " ) ) ) ;
2018-08-14 19:52:40 +00:00
BIND_VMETHOD ( MethodInfo ( Variant : : STRING , " _get_configuration_warning " ) ) ;
2014-02-10 01:10:30 +00:00
}
2016-10-07 18:25:29 +00:00
String Node : : _get_name_num_separator ( ) {
2017-07-19 20:00:46 +00:00
switch ( ProjectSettings : : get_singleton ( ) - > get ( " node/name_num_separator " ) . operator int ( ) ) {
2016-10-07 18:25:29 +00:00
case 0 : return " " ;
case 1 : return " " ;
case 2 : return " _ " ;
case 3 : return " - " ;
}
return " " ;
}
2014-02-10 01:10:30 +00:00
Node : : Node ( ) {
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . pos = - 1 ;
data . depth = - 1 ;
data . blocked = 0 ;
data . parent = NULL ;
data . tree = NULL ;
2017-09-30 14:19:07 +00:00
data . physics_process = false ;
2017-03-05 15:44:50 +00:00
data . idle_process = false ;
2018-07-02 05:30:40 +00:00
data . process_priority = 0 ;
2017-09-30 14:19:07 +00:00
data . physics_process_internal = false ;
2017-03-05 15:44:50 +00:00
data . idle_process_internal = false ;
data . inside_tree = false ;
data . ready_notified = false ;
data . owner = NULL ;
data . OW = NULL ;
data . input = false ;
data . unhandled_input = false ;
data . unhandled_key_input = false ;
data . pause_mode = PAUSE_MODE_INHERIT ;
data . pause_owner = NULL ;
2017-07-03 13:44:45 +00:00
data . network_master = 1 ; //server by default
2017-03-05 15:44:50 +00:00
data . path_cache = NULL ;
data . parent_owned = false ;
data . in_constructor = true ;
data . viewport = NULL ;
data . use_placeholder = false ;
data . display_folded = false ;
data . ready_first = true ;
2019-04-17 20:46:21 +00:00
orphan_node_count + + ;
2014-02-10 01:10:30 +00:00
}
Node : : ~ Node ( ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . grouped . clear ( ) ;
data . owned . clear ( ) ;
data . children . clear ( ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( data . parent ) ;
ERR_FAIL_COND ( data . children . size ( ) ) ;
2019-04-17 20:46:21 +00:00
orphan_node_count - - ;
2014-02-10 01:10:30 +00:00
}
2015-10-16 22:11:23 +00:00
////////////////////////////////