2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* node.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
2016-01-01 13:50:53 +00:00
/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
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. */
/*************************************************************************/
# include "node.h"
# include "print_string.h"
# include "message_queue.h"
# include "scene/scene_string_names.h"
# include "scene/resources/packed_scene.h"
# include "io/resource_loader.h"
2014-04-10 03:18:27 +00:00
# include "viewport.h"
2016-01-22 22:36:40 +00:00
# include "instance_placeholder.h"
2014-02-10 01:10:30 +00:00
VARIANT_ENUM_CAST ( Node : : PauseMode ) ;
void Node : : _notification ( int p_notification ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
switch ( p_notification ) {
case NOTIFICATION_PROCESS : {
if ( get_script_instance ( ) ) {
Variant time = get_process_delta_time ( ) ;
const Variant * ptr [ 1 ] = { & time } ;
Variant : : CallError err ;
get_script_instance ( ) - > call_multilevel ( SceneStringNames : : get_singleton ( ) - > _process , ptr , 1 ) ;
}
} break ;
case NOTIFICATION_FIXED_PROCESS : {
if ( get_script_instance ( ) ) {
Variant time = get_fixed_process_delta_time ( ) ;
const Variant * ptr [ 1 ] = { & time } ;
Variant : : CallError err ;
get_script_instance ( ) - > call_multilevel ( SceneStringNames : : get_singleton ( ) - > _fixed_process , ptr , 1 ) ;
}
} break ;
2014-11-06 00:20:42 +00:00
case NOTIFICATION_ENTER_TREE : {
2014-02-10 01:10:30 +00:00
if ( data . pause_mode = = PAUSE_MODE_INHERIT ) {
if ( data . parent )
data . pause_owner = data . parent - > data . pause_owner ;
else
data . pause_owner = NULL ;
} else {
data . pause_owner = this ;
}
2014-04-10 03:18:27 +00:00
if ( data . input )
add_to_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
if ( data . unhandled_input )
add_to_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
if ( data . unhandled_key_input )
add_to_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
2014-11-06 00:20:42 +00:00
get_tree ( ) - > node_count + + ;
2014-02-10 01:10:30 +00:00
} break ;
2014-11-06 00:20:42 +00:00
case NOTIFICATION_EXIT_TREE : {
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
get_tree ( ) - > node_count - - ;
2014-04-10 03:18:27 +00:00
if ( data . input )
remove_from_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
if ( data . unhandled_input )
remove_from_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
if ( data . unhandled_key_input )
remove_from_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_READY : {
if ( get_script_instance ( ) ) {
Variant : : CallError err ;
get_script_instance ( ) - > call_multilevel_reversed ( SceneStringNames : : get_singleton ( ) - > _ready , NULL , 0 ) ;
}
2014-11-06 00:20:42 +00:00
//emit_signal(SceneStringNames::get_singleton()->enter_tree);
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_POSTINITIALIZE : {
data . in_constructor = false ;
} break ;
case NOTIFICATION_PREDELETE : {
set_owner ( NULL ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +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
while ( data . children . size ( ) ) {
2016-03-08 23:00:52 +00:00
Node * child = data . children [ 0 ] ;
2014-02-10 01:10:30 +00:00
remove_child ( child ) ;
memdelete ( child ) ;
}
} break ;
}
}
void Node : : _propagate_ready ( ) {
data . blocked + + ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > _propagate_ready ( ) ;
}
data . blocked - - ;
notification ( NOTIFICATION_READY ) ;
}
2014-11-06 00:20:42 +00:00
void Node : : _propagate_enter_tree ( ) {
// this needs to happen to all childs before any enter_tree
2014-02-10 01:10:30 +00:00
if ( data . parent ) {
2014-11-06 00:20:42 +00:00
data . tree = data . parent - > data . tree ;
2014-02-10 01:10:30 +00:00
data . depth = data . parent - > data . depth + 1 ;
} else {
data . depth = 1 ;
}
2016-03-08 23:00:52 +00:00
2014-04-10 03:18:27 +00:00
data . viewport = cast_to < Viewport > ( ) ;
if ( ! data . viewport )
data . viewport = data . parent - > data . viewport ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
data . inside_tree = true ;
2014-02-10 01:10:30 +00:00
2016-06-08 01:08:12 +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-04-10 03:18:27 +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 ( ) ) {
Variant : : CallError err ;
2014-11-06 00:20:42 +00:00
get_script_instance ( ) - > call_multilevel_reversed ( SceneStringNames : : get_singleton ( ) - > _enter_tree , NULL , 0 ) ;
2014-02-10 01:10:30 +00:00
}
2014-11-06 00:20:42 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > enter_tree ) ;
2014-02-10 01:10:30 +00:00
data . blocked + + ;
//block while adding children
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
if ( ScriptDebugger : : get_singleton ( ) & & data . filename ! = String ( ) ) {
//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
}
2014-11-06 00:20:42 +00:00
void Node : : _propagate_exit_tree ( ) {
2014-02-10 01:10:30 +00:00
//block while removing children
2015-08-02 15:29:37 +00:00
# ifdef DEBUG_ENABLED
if ( ScriptDebugger : : get_singleton ( ) & & data . filename ! = String ( ) ) {
//used for live edit
Map < String , Set < Node * > > : : Element * E = data . tree - > live_scene_edit_cache . find ( data . filename ) ;
if ( E ) {
E - > get ( ) . erase ( this ) ;
if ( E - > get ( ) . size ( ) = = 0 ) {
data . tree - > live_scene_edit_cache . erase ( E ) ;
}
}
2015-08-02 23:28:10 +00:00
Map < Node * , Map < ObjectID , Node * > > : : Element * F = data . tree - > live_edit_remove_list . find ( this ) ;
if ( F ) {
for ( Map < ObjectID , Node * > : : Element * G = F - > get ( ) . front ( ) ; G ; G = G - > next ( ) ) {
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 + + ;
for ( int i = data . children . size ( ) - 1 ; i > = 0 ; i - - ) {
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 ( ) ) {
Variant : : CallError err ;
2014-11-06 00:20:42 +00:00
get_script_instance ( ) - > call_multilevel ( SceneStringNames : : get_singleton ( ) - > _exit_tree , NULL , 0 ) ;
2014-02-10 01:10:30 +00:00
}
2014-11-06 00:20:42 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > exit_tree ) ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
notification ( NOTIFICATION_EXIT_TREE , true ) ;
if ( data . tree )
data . tree - > node_removed ( this ) ;
2014-02-10 01:10:30 +00:00
// exit groups
2016-06-08 01:08:12 +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
}
2016-06-08 01:08:12 +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
2014-11-06 00:20:42 +00:00
data . inside_tree = false ;
data . tree = NULL ;
2014-02-10 01:10:30 +00:00
data . depth = - 1 ;
}
2016-03-08 23:00:52 +00:00
void Node : : move_child ( Node * p_child , int p_pos ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL_NULL ( p_child ) ;
ERR_EXPLAIN ( " Invalid new child position: " + itos ( p_pos ) ) ;
ERR_FAIL_INDEX ( p_pos , data . children . size ( ) + 1 ) ;
ERR_EXPLAIN ( " child is not a child of this node. " ) ;
ERR_FAIL_COND ( p_child - > data . parent ! = this ) ;
2016-06-14 01:46:18 +00:00
if ( data . blocked > 0 ) {
ERR_EXPLAIN ( " 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). " ) ;
ERR_FAIL_COND ( data . blocked > 0 ) ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . children . remove ( p_child - > data . pos ) ;
data . children . insert ( p_pos , p_child ) ;
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
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . children [ i ] - > data . pos = i ;
}
// notification second
2014-12-03 05:29:28 +00:00
move_child_notify ( p_child ) ;
2014-02-10 01:10:30 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > notification ( NOTIFICATION_MOVED_IN_PARENT ) ;
}
2016-06-08 01:08:12 +00:00
for ( const Map < StringName , GroupData > : : Element * E = p_child - > data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
E - > get ( ) . group - > changed = true ;
}
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
2014-02-10 01:10:30 +00:00
data . parent - > move_child ( this , data . parent - > data . children . size ( ) - 1 ) ;
}
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
}
2015-04-09 03:49:48 +00:00
/*
2014-02-10 01:10:30 +00:00
void Node : : remove_and_delete_child ( Node * p_child ) {
ERR_FAIL_NULL ( p_child ) ;
ERR_FAIL_COND ( p_child - > get_parent ( ) ! = this ) ;
remove_child ( p_child ) ;
memdelete ( p_child ) ;
}
2015-04-09 03:49:48 +00:00
*/
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
}
2014-02-10 01:10:30 +00:00
void Node : : set_fixed_process ( bool p_process ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( data . fixed_process = = p_process )
return ;
data . fixed_process = p_process ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( data . fixed_process )
add_to_group ( " fixed_process " , false ) ;
else
remove_from_group ( " fixed_process " ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . fixed_process = p_process ;
_change_notify ( " fixed_process " ) ;
}
void Node : : set_pause_mode ( PauseMode p_mode ) {
if ( data . pause_mode = = p_mode )
return ;
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
if ( ( data . pause_mode = = PAUSE_MODE_INHERIT ) = = prev_inherits )
return ; ///nothing changed
Node * owner = NULL ;
if ( data . pause_mode = = PAUSE_MODE_INHERIT ) {
if ( data . parent )
2014-04-10 03:18:27 +00:00
owner = data . parent - > data . pause_owner ;
2014-02-10 01:10:30 +00:00
} else {
owner = this ;
}
_propagate_pause_owner ( owner ) ;
}
Node : : PauseMode Node : : get_pause_mode ( ) const {
return data . pause_mode ;
}
void Node : : _propagate_pause_owner ( Node * p_owner ) {
if ( data . pause_mode ! = PAUSE_MODE_INHERIT )
return ;
data . pause_owner = p_owner ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > _propagate_pause_owner ( p_owner ) ;
}
}
bool Node : : can_process ( ) const {
2014-11-06 00:20:42 +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
2014-12-27 16:28:02 +00:00
if ( data . pause_mode = = PAUSE_MODE_STOP )
return false ;
2014-02-10 01:10:30 +00:00
if ( data . pause_mode = = PAUSE_MODE_PROCESS )
return true ;
if ( data . pause_mode = = PAUSE_MODE_INHERIT ) {
if ( ! data . pause_owner )
return false ; //clearly no pause owner by default
if ( data . pause_owner - > data . pause_mode = = PAUSE_MODE_PROCESS )
return true ;
2014-12-27 16:28:02 +00:00
if ( data . pause_owner - > data . pause_mode = = PAUSE_MODE_STOP )
return false ;
2014-02-10 01:10:30 +00:00
}
}
return true ;
}
float Node : : get_fixed_process_delta_time ( ) const {
2016-03-08 23:00:52 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree )
return data . tree - > get_fixed_process_time ( ) ;
2014-02-10 01:10:30 +00:00
else
return 0 ;
}
void Node : : set_process ( bool p_idle_process ) {
if ( data . idle_process = = p_idle_process )
return ;
data . idle_process = p_idle_process ;
if ( data . idle_process )
add_to_group ( " idle_process " , false ) ;
else
remove_from_group ( " idle_process " ) ;
data . idle_process = p_idle_process ;
_change_notify ( " idle_process " ) ;
}
float Node : : get_process_delta_time ( ) const {
2014-11-06 00:20:42 +00:00
if ( data . tree )
return data . tree - > get_idle_process_time ( ) ;
2014-02-10 01:10:30 +00:00
else
return 0 ;
}
bool Node : : is_fixed_processing ( ) const {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return data . fixed_process ;
}
bool Node : : is_processing ( ) const {
return data . idle_process ;
}
void Node : : set_process_input ( bool p_enable ) {
if ( p_enable = = data . input )
return ;
2014-04-10 03:18:27 +00:00
2014-02-10 01:10:30 +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 )
2014-04-10 03:18:27 +00:00
add_to_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
2014-02-10 01:10:30 +00:00
else
2014-04-10 03:18:27 +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 ) {
if ( p_enable = = data . unhandled_input )
return ;
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 )
2014-04-10 03:18:27 +00:00
add_to_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
2014-02-10 01:10:30 +00:00
else
2014-04-10 03:18:27 +00:00
remove_from_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
2014-02-10 01:10:30 +00:00
}
2014-04-10 03:18:27 +00:00
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 ) {
if ( p_enable = = data . unhandled_key_input )
return ;
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 )
add_to_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
else
remove_from_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_ID ( ) ) ) ;
}
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 ;
}
void Node : : _set_name_nocheck ( const StringName & p_name ) {
data . name = p_name ;
}
void Node : : set_name ( const String & p_name ) {
2016-03-08 23:00:52 +00:00
2014-02-22 23:28:19 +00:00
String name = p_name . replace ( " : " , " " ) . replace ( " / " , " " ) . replace ( " @ " , " " ) ;
2014-02-10 01:10:30 +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 ) ;
}
2014-11-06 00:20:42 +00:00
if ( is_inside_tree ( ) ) {
2014-02-10 01:10:30 +00:00
emit_signal ( " renamed " ) ;
2014-11-06 00:20:42 +00:00
get_tree ( ) - > tree_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
}
2014-02-22 23:28:19 +00:00
static bool node_hrcr = false ;
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 ) {
node_hrcr = p_enabled ;
}
2015-08-02 15:29:37 +00:00
String Node : : validate_child_name ( const String & p_name ) const {
//this approach to autoset node names is human readable but very slow
//it's turned on while running in the editor
String basename = p_name ;
if ( basename = = String ( ) ) {
return String ( ) ;
}
int val = 1 ;
for ( ; ; ) {
String attempted = val > 1 ? ( basename + " " + itos ( val ) ) : basename ;
bool found = false ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
//if (data.children[i]==p_child)
// continue;
if ( data . children [ i ] - > get_name ( ) = = attempted ) {
found = true ;
break ;
}
}
if ( found ) {
val + + ;
continue ;
}
return attempted ;
break ;
}
return basename ;
}
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
String basename = p_child - > data . name ;
if ( basename = = " " ) {
basename = p_child - > get_type ( ) ;
}
int val = 1 ;
for ( ; ; ) {
String attempted = val > 1 ? ( basename + " " + itos ( val ) ) : basename ;
bool found = false ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
if ( data . children [ i ] = = p_child )
continue ;
if ( data . children [ i ] - > get_name ( ) = = attempted ) {
found = true ;
break ;
}
}
if ( found ) {
val + + ;
2014-02-10 01:10:30 +00:00
continue ;
}
2014-02-22 23:28:19 +00:00
p_child - > data . name = attempted ;
break ;
2014-02-10 01:10:30 +00:00
}
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.
bool unique = true ;
if ( p_child - > data . name = = StringName ( ) | | p_child - > data . name . operator String ( ) [ 0 ] = = ' @ ' ) {
//new unique name must be assigned
unique = false ;
} else {
//check if exists
Node * * childs = data . children . ptr ( ) ;
int cc = data . children . size ( ) ;
for ( int i = 0 ; i < cc ; i + + ) {
2014-02-26 13:08:17 +00:00
if ( childs [ i ] = = p_child )
continue ;
2014-02-22 23:28:19 +00:00
if ( childs [ i ] - > data . name = = p_child - > data . name ) {
unique = false ;
break ;
}
}
}
if ( ! unique ) {
node_hrcr_count . ref ( ) ;
2015-12-08 14:33:30 +00:00
String name = " @ " + String ( p_child - > get_name ( ) ) + " @ " + itos ( node_hrcr_count . get ( ) ) ;
2014-02-22 23:28:19 +00:00
p_child - > data . name = name ;
2014-02-10 01:10:30 +00:00
}
}
}
void Node : : _add_child_nocheck ( Node * p_child , const StringName & p_name ) {
//add a child node quickly, without name validation
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 */
//recognize childs created in this node constructor
p_child - > data . parent_owned = data . in_constructor ;
add_child_notify ( p_child ) ;
}
2014-02-22 23:28:19 +00:00
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 ) ;
/* Fail if node has a parent */
2015-12-08 14:21:12 +00:00
if ( p_child = = this ) {
ERR_EXPLAIN ( " Can't add child " + p_child - > get_name ( ) + " to itself. " )
ERR_FAIL_COND ( p_child = = this ) ; // adding to itself!
}
2014-02-10 01:10:30 +00:00
ERR_EXPLAIN ( " Can't add child, already has a parent " ) ;
ERR_FAIL_COND ( p_child - > data . parent ) ;
2016-06-14 01:46:18 +00:00
if ( data . blocked > 0 ) {
ERR_EXPLAIN ( " Parent node is busy setting up children, add_node() failed. Consider using call_deferred( \" add_child \" ,child) instead. " ) ;
ERR_FAIL_COND ( data . blocked > 0 ) ;
}
2014-02-10 01:10:30 +00:00
ERR_EXPLAIN ( " Can't add child while a notification is happening " ) ;
ERR_FAIL_COND ( data . blocked > 0 ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
/* Validate name */
2015-12-08 14:21:12 +00:00
_validate_child_name ( p_child , p_legible_unique_name ) ;
2014-02-10 01:10:30 +00:00
_add_child_nocheck ( p_child , p_child - > data . name ) ;
2016-03-08 23:00:52 +00:00
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 ) {
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 {
WARN_PRINTS ( " Cannot move under node " + p_node - > get_name ( ) + " as " + p_child - > get_name ( ) + " does not share a parent " )
}
}
2015-12-08 14:21:12 +00:00
2014-02-10 01:10:30 +00:00
void Node : : _propagate_validate_owner ( ) {
if ( data . owner ) {
bool found = false ;
Node * parent = data . parent ;
while ( parent ) {
if ( parent = = data . owner ) {
found = true ;
break ;
}
parent = parent - > data . parent ;
}
if ( ! found ) {
data . owner - > data . owned . erase ( data . OW ) ;
data . owner = NULL ;
}
}
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > _propagate_validate_owner ( ) ;
}
}
void Node : : remove_child ( Node * p_child ) {
ERR_FAIL_NULL ( p_child ) ;
2016-06-14 01:46:18 +00:00
if ( data . blocked > 0 ) {
ERR_EXPLAIN ( " Parent node is busy setting up children, remove_node() failed. Consider using call_deferred( \" remove_child \" ,child) instead. " ) ;
ERR_FAIL_COND ( data . blocked > 0 ) ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
int idx = - 1 ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( data . children [ i ] = = p_child ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
idx = i ;
break ;
}
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( idx = = - 1 ) ;
2015-12-29 19:06:45 +00:00
//ERR_FAIL_COND( p_child->data.blocked > 0 );
2014-02-10 01:10:30 +00:00
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
//if (data.scene) { does not matter
2016-03-08 23:00:52 +00:00
2014-11-06 00:20:42 +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
2014-02-10 01:10:30 +00:00
for ( int i = idx ; i < data . children . size ( ) ; i + + ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . children [ i ] - > data . pos = i ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
p_child - > data . parent = NULL ;
p_child - > data . pos = - 1 ;
// validate owner
p_child - > _propagate_validate_owner ( ) ;
2016-03-08 23:00:52 +00:00
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
2014-02-10 01:10:30 +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 ] ;
}
2015-10-10 12:09:09 +00:00
Node * Node : : _get_child_by_name ( const StringName & p_name ) const {
int cc = data . children . size ( ) ;
Node * const * cd = data . children . ptr ( ) ;
for ( int i = 0 ; i < cc ; i + + ) {
if ( cd [ i ] - > data . name = = p_name )
return cd [ i ] ;
}
return NULL ;
}
2014-02-10 01:10:30 +00:00
Node * Node : : _get_node ( const NodePath & p_path ) const {
2015-12-28 18:59:20 +00:00
if ( ! data . inside_tree & & p_path . is_absolute ( ) ) {
ERR_EXPLAIN ( " Can't use get_node() with absolute paths from outside the active scene tree. " ) ;
ERR_FAIL_V ( NULL ) ;
}
2016-03-08 23:00:52 +00:00
Node * current = NULL ;
2014-02-10 01:10:30 +00:00
Node * root = NULL ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( ! p_path . is_absolute ( ) ) {
current = const_cast < Node * > ( this ) ; //start from this
} else {
root = const_cast < Node * > ( this ) ; ;
while ( root - > data . parent )
root = root - > data . parent ; //start from root
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +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
2014-02-10 01:10:30 +00:00
if ( name = = SceneStringNames : : get_singleton ( ) - > dot ) { // .
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
next = current ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
} else if ( name = = SceneStringNames : : get_singleton ( ) - > doubledot ) { // ..
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( current = = NULL | | ! current - > data . parent )
return NULL ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
next = current - > data . parent ;
} else if ( current = = NULL ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +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
2014-02-10 01:10:30 +00:00
next = NULL ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +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 ] ;
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 ;
} ;
}
current = next ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return current ;
}
Node * Node : : get_node ( const NodePath & p_path ) const {
Node * node = _get_node ( p_path ) ;
2015-10-10 12:09:09 +00:00
if ( ! node ) {
ERR_EXPLAIN ( " Node not found: " + p_path ) ;
ERR_FAIL_COND_V ( ! node , NULL ) ;
}
2014-02-10 01:10:30 +00:00
return node ;
}
bool Node : : has_node ( const NodePath & p_path ) const {
return _get_node ( p_path ) ! = NULL ;
}
2015-06-08 03:33:10 +00:00
Node * Node : : find_node ( const String & p_mask , bool p_recursive , bool p_owned ) const {
Node * const * cptr = data . children . ptr ( ) ;
int ccount = data . children . size ( ) ;
for ( int i = 0 ; i < ccount ; i + + ) {
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 ;
Node * ret = cptr [ i ] - > find_node ( p_mask , true , p_owned ) ;
if ( ret )
return ret ;
}
return NULL ;
}
2014-02-10 01:10:30 +00:00
Node * Node : : get_parent ( ) const {
return data . parent ;
}
bool Node : : is_a_parent_of ( const Node * p_node ) const {
ERR_FAIL_NULL_V ( p_node , false ) ;
Node * p = p_node - > data . parent ;
while ( p ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( p = = this )
return true ;
p = p - > data . parent ;
}
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 {
ERR_FAIL_NULL_V ( p_node , false ) ;
2014-11-06 00:20:42 +00:00
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
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND_V ( data . depth < 0 , false ) ;
ERR_FAIL_COND_V ( p_node - > data . depth < 0 , false ) ;
# 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
2014-02-10 01:10:30 +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
2014-02-10 01:10:30 +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 ;
}
ERR_FAIL_COND_V ( idx ! = - 1 , false ) ;
n = p_node ;
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
2014-02-10 01:10:30 +00:00
n = n - > data . parent ;
}
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 ;
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
int this_idx = ( idx > = data . depth ) ? - 2 : this_stack [ idx ] ;
int that_idx = ( idx > = p_node - > data . depth ) ? - 2 : that_stack [ idx ] ;
if ( this_idx > that_idx ) {
res = true ;
break ;
} else if ( this_idx < that_idx ) {
res = false ;
break ;
} else if ( this_idx = = - 2 ) {
res = false ; // equal
break ;
}
idx + + ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return res ;
}
void Node : : get_owned_by ( Node * p_by , List < Node * > * p_owned ) {
if ( data . owner = = p_by )
p_owned - > push_back ( this ) ;
for ( int i = 0 ; i < get_child_count ( ) ; i + + )
get_child ( i ) - > get_owned_by ( p_by , p_owned ) ;
}
void Node : : _set_owner_nocheck ( Node * p_owner ) {
2015-10-16 22:11:23 +00:00
ERR_FAIL_COND ( data . owner ) ;
2014-02-10 01:10:30 +00:00
data . owner = p_owner ;
data . owner - > data . owned . push_back ( this ) ;
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
2014-02-10 01:10:30 +00:00
data . owner - > data . owned . erase ( data . OW ) ;
data . OW = NULL ;
data . owner = NULL ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +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
2014-02-10 01:10:30 +00:00
Node * check = this - > get_parent ( ) ;
bool owner_valid = false ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
while ( check ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( check = = p_owner ) {
owner_valid = true ;
break ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
check = check - > data . parent ;
}
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
}
2016-07-19 23:04:06 +00:00
Node * Node : : find_common_parent_with ( const Node * p_node ) const {
if ( this = = p_node )
return const_cast < Node * > ( p_node ) ;
Set < const Node * > visited ;
const Node * n = this ;
while ( n ) {
visited . insert ( n ) ;
n = n - > data . parent ;
}
const Node * common_parent = p_node ;
while ( common_parent ) {
if ( visited . has ( common_parent ) )
break ;
common_parent = common_parent - > data . parent ;
}
if ( ! common_parent )
return NULL ;
return const_cast < Node * > ( common_parent ) ;
}
2014-02-10 01:10:30 +00:00
NodePath Node : : get_path_to ( const Node * p_node ) const {
ERR_FAIL_NULL_V ( p_node , NodePath ( ) ) ;
if ( this = = p_node )
return NodePath ( " . " ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
Set < const Node * > visited ;
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
2014-02-10 01:10:30 +00:00
while ( n ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
visited . insert ( n ) ;
n = n - > data . parent ;
}
const Node * common_parent = p_node ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +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 ;
common_parent = common_parent - > data . parent ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +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
2014-02-10 01:10:30 +00:00
n = p_node ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
while ( n ! = common_parent ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
path . push_back ( n - > get_name ( ) ) ;
n = n - > data . parent ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
n = this ;
2016-03-08 23:00:52 +00:00
StringName up = String ( " .. " ) ;
2014-02-10 01:10:30 +00:00
while ( n ! = common_parent ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
path . push_back ( up ) ;
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
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
2014-11-06 00:20:42 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , NodePath ( ) ) ;
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
2014-02-10 01:10:30 +00:00
while ( n ) {
path . push_back ( n - > get_name ( ) ) ;
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
2014-02-10 01:10:30 +00:00
return NodePath ( path , true ) ;
}
bool Node : : is_in_group ( const StringName & p_identifier ) const {
return data . grouped . has ( p_identifier ) ;
}
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 ) {
gd . group = data . tree - > add_to_group ( p_identifier , this ) ;
} else {
gd . group = NULL ;
}
2014-02-10 01:10:30 +00:00
2016-03-08 23:00:52 +00:00
gd . persistent = p_persistent ;
2014-02-10 01:10:30 +00:00
data . grouped [ p_identifier ] = gd ;
}
void Node : : remove_from_group ( const StringName & p_identifier ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! data . grouped . has ( p_identifier ) ) ;
2016-03-08 23:00:52 +00:00
2016-06-08 01:08:12 +00:00
Map < StringName , GroupData > : : Element * E = data . grouped . find ( p_identifier ) ;
ERR_FAIL_COND ( ! E ) ;
2016-03-08 23:00:52 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree )
2016-06-08 01:08:12 +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 ) ;
for ( List < GroupInfo > : : Element * E = gi . front ( ) ; E ; E = E - > next ( ) ) {
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 {
2016-03-08 23:00:52 +00:00
2016-06-08 01:08:12 +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 ;
2016-06-08 01:08:12 +00:00
gi . name = E - > key ( ) ;
gi . persistent = E - > get ( ) . persistent ;
2014-02-10 01:10:30 +00:00
p_groups - > push_back ( gi ) ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
}
2016-06-04 16:17:56 +00:00
bool Node : : has_persistent_groups ( ) const {
2014-02-10 01:10:30 +00:00
2016-06-04 16:17:56 +00:00
2016-06-08 01:08:12 +00:00
for ( const Map < StringName , GroupData > : : Element * E = data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
if ( E - > get ( ) . persistent )
2016-06-04 16:17:56 +00:00
return true ;
}
2016-06-08 01:08:12 +00:00
2016-06-04 16:17:56 +00:00
return false ;
2016-06-08 01:08:12 +00:00
2016-06-04 16:17:56 +00:00
}
2014-02-10 01:10:30 +00:00
void Node : : _print_tree ( const Node * p_node ) {
2014-09-21 04:43:42 +00:00
print_line ( String ( p_node - > get_path_to ( this ) ) ) ;
2014-02-10 01:10:30 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + )
data . children [ i ] - > _print_tree ( p_node ) ;
}
void Node : : print_tree ( ) {
_print_tree ( this ) ;
}
void Node : : _propagate_reverse_notification ( int p_notification ) {
2016-03-08 23:00:52 +00:00
data . blocked + + ;
2014-02-10 01:10:30 +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
2014-02-10 01:10:30 +00:00
notification ( p_notification , true ) ;
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 )
MessageQueue : : get_singleton ( ) - > push_notification ( this , p_notification ) ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > _propagate_deferred_notification ( p_notification , p_reverse ) ;
}
if ( p_reverse )
MessageQueue : : get_singleton ( ) - > push_notification ( this , p_notification ) ;
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
2014-02-10 01:10:30 +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
}
2016-03-08 23:00:52 +00:00
void Node : : _propagate_replace_owner ( Node * p_owner , Node * p_by_owner ) {
2014-02-10 01:10:30 +00:00
if ( get_owner ( ) = = p_owner )
set_owner ( p_by_owner ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . blocked + + ;
2016-03-08 23:00:52 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + )
2014-02-10 01:10:30 +00:00
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
2014-02-10 01:10:30 +00:00
Node * new_owner = get_owner ( ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
List < Node * > children ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
while ( true ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
bool clear = true ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
if ( ! data . children [ i ] - > get_owner ( ) )
continue ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
remove_child ( data . children [ i ] ) ;
data . children [ i ] - > _propagate_replace_owner ( this , NULL ) ;
2016-03-08 23:00:52 +00:00
children . push_back ( data . children [ i ] ) ;
2014-02-10 01:10:30 +00:00
clear = false ;
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
2014-02-10 01:10:30 +00:00
while ( ! children . empty ( ) ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
Node * c = children . front ( ) - > get ( ) ;
data . parent - > add_child ( c ) ;
2016-03-08 23:00:52 +00:00
c - > _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 ) ;
}
void Node : : set_filename ( const String & p_filename ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . filename = p_filename ;
}
String Node : : get_filename ( ) const {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return data . filename ;
}
2015-10-10 12:09:09 +00:00
void Node : : set_editable_instance ( Node * p_node , bool p_editable ) {
ERR_FAIL_NULL ( p_node ) ;
ERR_FAIL_COND ( ! is_a_parent_of ( p_node ) ) ;
NodePath p = get_path_to ( p_node ) ;
if ( ! p_editable )
data . editable_instances . erase ( p ) ;
else
data . editable_instances [ p ] = true ;
}
bool Node : : is_editable_instance ( Node * p_node ) const {
if ( ! p_node )
return false ; //easier, null is never editable :)
ERR_FAIL_COND_V ( ! is_a_parent_of ( p_node ) , false ) ;
NodePath p = get_path_to ( p_node ) ;
return data . editable_instances . has ( p ) ;
}
2016-04-12 16:21:37 +00:00
void Node : : set_editable_instances ( const HashMap < NodePath , int > & p_editable_instances ) {
data . editable_instances = p_editable_instances ;
}
HashMap < NodePath , int > Node : : get_editable_instances ( ) const {
return data . editable_instances ;
}
2014-02-10 01:10:30 +00:00
2015-10-10 12:09:09 +00:00
#if 0
2014-02-10 01:10:30 +00:00
void Node : : generate_instance_state ( ) {
List < PropertyInfo > properties ;
get_property_list ( & properties ) ;
data . instance_state . clear ( ) ;
for ( List < PropertyInfo > : : Element * E = properties . front ( ) ; E ; E = E - > next ( ) ) {
PropertyInfo & pi = E - > get ( ) ;
2014-11-02 14:31:01 +00:00
if ( ( pi . usage & PROPERTY_USAGE_NO_INSTANCE_STATE ) | | ! ( pi . usage & PROPERTY_USAGE_EDITOR ) | | ! ( pi . usage & PROPERTY_USAGE_STORAGE ) )
2014-02-10 01:10:30 +00:00
continue ;
data . instance_state [ pi . name ] = get ( pi . name ) ;
}
List < GroupInfo > groups ;
get_groups ( & groups ) ;
for ( List < GroupInfo > : : Element * E = groups . front ( ) ; E ; E = E - > next ( ) ) {
if ( ! E - > get ( ) . persistent )
continue ;
data . instance_groups . push_back ( E - > get ( ) . name ) ;
}
List < MethodInfo > signal_list ;
get_signal_list ( & signal_list ) ;
for ( List < MethodInfo > : : Element * E = signal_list . front ( ) ; E ; E = E - > next ( ) ) {
StringName name = E - > get ( ) . name ;
List < Connection > connections ;
get_signal_connection_list ( name , & connections ) ;
for ( List < Connection > : : Element * F = connections . front ( ) ; F ; F = F - > next ( ) ) {
if ( F - > get ( ) . flags & CONNECT_PERSIST )
data . instance_connections . push_back ( F - > get ( ) ) ;
}
}
}
Dictionary Node : : get_instance_state ( ) const {
return data . instance_state ;
}
2015-10-10 12:09:09 +00:00
# endif
void Node : : set_scene_instance_state ( const Ref < SceneState > & p_state ) {
data . instance_state = p_state ;
}
Ref < SceneState > Node : : get_scene_instance_state ( ) const {
return data . instance_state ;
}
void Node : : set_scene_inherited_state ( const Ref < SceneState > & p_state ) {
data . inherited_state = p_state ;
}
Ref < SceneState > Node : : get_scene_inherited_state ( ) const {
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
2015-10-16 22:11:23 +00:00
data . use_placeholder = p_enable ;
2014-02-10 01:10:30 +00:00
}
2015-10-16 22:11:23 +00:00
bool Node : : get_scene_instance_load_placeholder ( ) const {
return data . use_placeholder ;
2014-02-10 01:10:30 +00:00
}
int Node : : get_position_in_parent ( ) const {
return data . pos ;
}
2016-07-07 00:43:31 +00:00
Node * Node : : _duplicate ( bool p_use_instancing ) const {
2014-02-10 01:10:30 +00:00
Node * node = NULL ;
2015-08-02 15:29:37 +00:00
bool instanced = false ;
2016-01-22 22:36:40 +00:00
if ( cast_to < InstancePlaceholder > ( ) ) {
const InstancePlaceholder * ip = cast_to < const InstancePlaceholder > ( ) ;
InstancePlaceholder * nip = memnew ( InstancePlaceholder ) ;
nip - > set_instance_path ( ip - > get_instance_path ( ) ) ;
node = nip ;
} else if ( p_use_instancing & & get_filename ( ) ! = String ( ) ) {
2015-08-02 15:29:37 +00:00
Ref < PackedScene > res = ResourceLoader : : load ( get_filename ( ) ) ;
ERR_FAIL_COND_V ( res . is_null ( ) , NULL ) ;
node = res - > instance ( ) ;
ERR_FAIL_COND_V ( ! node , NULL ) ;
instanced = true ;
} else {
2014-02-10 01:10:30 +00:00
2015-08-02 15:29:37 +00:00
Object * obj = ObjectTypeDB : : instance ( get_type ( ) ) ;
ERR_FAIL_COND_V ( ! obj , NULL ) ;
node = obj - > cast_to < Node > ( ) ;
if ( ! node )
memdelete ( obj ) ;
ERR_FAIL_COND_V ( ! node , NULL ) ;
}
2014-02-10 01:10:30 +00:00
if ( get_filename ( ) ! = " " ) { //an instance
node - > set_filename ( get_filename ( ) ) ;
}
List < PropertyInfo > plist ;
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 ;
node - > set ( name , get ( name ) ) ;
}
node - > set_name ( get_name ( ) ) ;
2016-01-19 23:08:04 +00:00
List < GroupInfo > gi ;
get_groups ( & gi ) ;
for ( List < GroupInfo > : : Element * E = gi . front ( ) ; E ; E = E - > next ( ) ) {
node - > add_to_group ( E - > get ( ) . name , E - > get ( ) . persistent ) ;
}
_duplicate_signals ( this , node ) ;
2014-02-10 01:10:30 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
if ( get_child ( i ) - > data . parent_owned )
continue ;
2015-08-02 15:29:37 +00:00
if ( instanced & & get_child ( i ) - > data . owner = = this )
continue ; //part of instance
Node * dup = get_child ( i ) - > duplicate ( p_use_instancing ) ;
2014-02-10 01:10:30 +00:00
if ( ! dup ) {
memdelete ( node ) ;
return NULL ;
}
node - > add_child ( dup ) ;
}
2016-07-07 00:43:31 +00:00
2014-02-10 01:10:30 +00:00
return node ;
}
2016-07-07 00:43:31 +00:00
Node * Node : : duplicate ( bool p_use_instancing ) const {
Node * dupe = _duplicate ( p_use_instancing ) ;
if ( dupe ) {
_duplicate_signals ( this , dupe ) ;
}
return dupe ;
}
2014-02-10 01:10:30 +00:00
void Node : : _duplicate_and_reown ( Node * p_new_parent , const Map < Node * , Node * > & p_reown_map ) const {
if ( get_owner ( ) ! = get_parent ( ) - > get_owner ( ) )
return ;
Node * node = NULL ;
if ( get_filename ( ) ! = " " ) {
Ref < PackedScene > res = ResourceLoader : : load ( get_filename ( ) ) ;
ERR_FAIL_COND ( res . is_null ( ) ) ;
node = res - > instance ( ) ;
ERR_FAIL_COND ( ! node ) ;
} else {
Object * obj = ObjectTypeDB : : instance ( get_type ( ) ) ;
if ( ! obj ) {
print_line ( " could not duplicate: " + String ( get_type ( ) ) ) ;
}
ERR_FAIL_COND ( ! obj ) ;
node = obj - > cast_to < Node > ( ) ;
if ( ! node )
memdelete ( obj ) ;
}
List < PropertyInfo > plist ;
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 ;
node - > set ( name , get ( name ) ) ;
}
node - > set_name ( get_name ( ) ) ;
p_new_parent - > add_child ( node ) ;
Node * owner = get_owner ( ) ;
if ( p_reown_map . has ( owner ) )
owner = p_reown_map [ owner ] ;
if ( owner ) {
NodePath p = get_path_to ( owner ) ;
if ( owner ! = this ) {
Node * new_owner = node - > get_node ( p ) ;
if ( new_owner ) {
node - > set_owner ( new_owner ) ;
}
}
}
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
get_child ( i ) - > _duplicate_and_reown ( node , p_reown_map ) ;
}
}
2015-05-10 18:45:33 +00:00
void Node : : _duplicate_signals ( const Node * p_original , Node * p_copy ) const {
2016-07-07 00:43:31 +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 ) ;
2016-07-07 00:43:31 +00:00
2015-05-10 18:45:33 +00:00
for ( List < Connection > : : Element * E = conns . front ( ) ; E ; E = E - > next ( ) ) {
if ( E - > get ( ) . flags & CONNECT_PERSIST ) {
//user connected
NodePath p = p_original - > get_path_to ( this ) ;
Node * copy = p_copy - > get_node ( p ) ;
Node * target = E - > get ( ) . target - > cast_to < Node > ( ) ;
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 ) ;
Node * copytarget = p_copy - > get_node ( ptarget ) ;
2016-07-07 00:43:31 +00:00
2015-05-10 18:45:33 +00:00
if ( copy & & copytarget ) {
copy - > connect ( E - > get ( ) . signal , copytarget , E - > get ( ) . method , E - > get ( ) . binds , CONNECT_PERSIST ) ;
}
2016-07-07 00:43:31 +00:00
2015-05-10 18:45:33 +00:00
}
}
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
get_child ( i ) - > _duplicate_signals ( p_original , p_copy ) ;
}
}
2014-02-10 01:10:30 +00:00
Node * Node : : duplicate_and_reown ( const Map < Node * , Node * > & p_reown_map ) const {
ERR_FAIL_COND_V ( get_filename ( ) ! = " " , NULL ) ;
Node * node = NULL ;
Object * obj = ObjectTypeDB : : instance ( get_type ( ) ) ;
if ( ! obj ) {
print_line ( " could not duplicate: " + String ( get_type ( ) ) ) ;
}
ERR_FAIL_COND_V ( ! obj , NULL ) ;
node = obj - > cast_to < Node > ( ) ;
if ( ! node )
memdelete ( obj ) ;
ERR_FAIL_COND_V ( ! node , NULL ) ;
node - > set_name ( get_name ( ) ) ;
2014-11-02 14:31:01 +00:00
List < PropertyInfo > plist ;
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 ;
node - > set ( name , get ( name ) ) ;
}
2014-02-10 01:10:30 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
get_child ( i ) - > _duplicate_and_reown ( node , p_reown_map ) ;
}
2015-05-10 18:45:33 +00:00
_duplicate_signals ( this , node ) ;
2014-02-10 01:10:30 +00:00
return node ;
}
static void find_owned_by ( Node * p_by , Node * p_node , List < Node * > * p_owned ) {
if ( p_node - > get_owner ( ) = = p_by )
p_owned - > push_back ( p_node ) ;
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
find_owned_by ( p_by , p_node - > get_child ( i ) , p_owned ) ;
}
}
struct _NodeReplaceByPair {
String name ;
Variant value ;
} ;
void Node : : replace_by ( Node * p_node , bool p_keep_data ) {
ERR_FAIL_NULL ( p_node ) ;
ERR_FAIL_COND ( p_node - > data . parent ) ;
List < Node * > owned = data . owned ;
List < Node * > owned_by_owner ;
Node * owner = ( data . owner = = this ) ? p_node : data . owner ;
List < _NodeReplaceByPair > replace_data ;
if ( p_keep_data ) {
List < PropertyInfo > plist ;
get_property_list ( & plist ) ;
for ( List < PropertyInfo > : : Element * E = plist . front ( ) ; E ; E = E - > next ( ) ) {
_NodeReplaceByPair rd ;
if ( ! ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE ) )
continue ;
rd . name = E - > get ( ) . name ;
rd . value = get ( rd . name ) ;
}
}
2016-06-09 14:24:12 +00:00
_replace_connections_target ( p_node ) ;
2014-02-10 01:10:30 +00:00
if ( data . owner ) {
for ( int i = 0 ; i < get_child_count ( ) ; i + + )
find_owned_by ( data . owner , get_child ( i ) , & owned_by_owner ) ;
}
Node * parent = data . parent ;
int pos_in_parent = data . pos ;
if ( data . parent ) {
parent - > remove_child ( this ) ;
parent - > add_child ( p_node ) ;
parent - > move_child ( p_node , pos_in_parent ) ;
}
while ( get_child_count ( ) ) {
Node * child = get_child ( 0 ) ;
remove_child ( child ) ;
p_node - > add_child ( child ) ;
}
p_node - > set_owner ( owner ) ;
for ( int i = 0 ; i < owned . size ( ) ; i + + )
owned [ i ] - > set_owner ( p_node ) ;
for ( int i = 0 ; i < owned_by_owner . size ( ) ; i + + )
owned_by_owner [ i ] - > set_owner ( owner ) ;
p_node - > set_filename ( get_filename ( ) ) ;
for ( List < _NodeReplaceByPair > : : Element * E = replace_data . front ( ) ; E ; E = E - > next ( ) ) {
p_node - > set ( E - > get ( ) . name , E - > get ( ) . value ) ;
}
}
2016-06-09 14:24:12 +00:00
void Node : : _replace_connections_target ( Node * p_new_target ) {
List < Connection > cl ;
get_signals_connected_to_this ( & cl ) ;
for ( List < Connection > : : Element * E = cl . front ( ) ; E ; E = E - > next ( ) ) {
Connection & c = E - > get ( ) ;
c . source - > disconnect ( c . signal , this , c . method ) ;
c . source - > connect ( c . signal , p_new_target , c . method , c . binds , c . flags ) ;
}
}
2014-02-10 01:10:30 +00:00
Vector < Variant > Node : : make_binds ( VARIANT_ARG_DECLARE ) {
Vector < Variant > ret ;
if ( p_arg1 . get_type ( ) = = Variant : : NIL )
return ret ;
else
ret . push_back ( p_arg1 ) ;
if ( p_arg2 . get_type ( ) = = Variant : : NIL )
return ret ;
else
ret . push_back ( p_arg2 ) ;
if ( p_arg3 . get_type ( ) = = Variant : : NIL )
return ret ;
else
ret . push_back ( p_arg3 ) ;
if ( p_arg4 . get_type ( ) = = Variant : : NIL )
return ret ;
else
ret . push_back ( p_arg4 ) ;
if ( p_arg5 . get_type ( ) = = Variant : : NIL )
return ret ;
else
ret . push_back ( p_arg5 ) ;
return ret ;
}
bool Node : : has_node_and_resource ( const NodePath & p_path ) const {
if ( ! has_node ( p_path ) )
return false ;
Node * node = get_node ( p_path ) ;
if ( p_path . get_subname_count ( ) ) {
RES r ;
for ( int j = 0 ; j < p_path . get_subname_count ( ) ; j + + ) {
r = j = = 0 ? node - > get ( p_path . get_subname ( j ) ) : r - > get ( p_path . get_subname ( j ) ) ;
if ( r . is_null ( ) )
return false ;
}
}
return true ;
}
Array Node : : _get_node_and_resource ( const NodePath & p_path ) {
Node * node ;
RES res ;
node = get_node_and_resource ( p_path , res ) ;
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 ( ) ) ;
return result ;
}
Node * Node : : get_node_and_resource ( const NodePath & p_path , RES & r_res ) const {
Node * node = get_node ( p_path ) ;
r_res = RES ( ) ;
if ( ! node )
return NULL ;
if ( p_path . get_subname_count ( ) ) {
for ( int j = 0 ; j < p_path . get_subname_count ( ) ; j + + ) {
r_res = j = = 0 ? node - > get ( p_path . get_subname ( j ) ) : r_res - > get ( p_path . get_subname ( j ) ) ;
ERR_FAIL_COND_V ( r_res . is_null ( ) , node ) ;
}
}
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
2014-11-06 00:20:42 +00:00
SceneTree * tree_changed_a = NULL ;
SceneTree * tree_changed_b = NULL ;
2014-02-10 01:10:30 +00:00
// ERR_FAIL_COND(p_scene && data.parent && !data.parent->data.scene); //nobug if both are null
2014-11-06 00:20:42 +00:00
if ( data . tree ) {
_propagate_exit_tree ( ) ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
tree_changed_a = data . tree ;
2014-02-10 01:10:30 +00:00
}
2014-11-06 00:20:42 +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 ( ) ;
2014-02-10 01:10:30 +00:00
_propagate_ready ( ) ; //reverse_notification(NOTIFICATION_READY);
2014-11-06 00:20:42 +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 ( ) ;
}
static void _Node_debug_sn ( Object * p_obj ) {
Node * n = p_obj - > cast_to < Node > ( ) ;
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 ;
Node * p = n ;
while ( p - > get_parent ( ) ) {
p = p - > get_parent ( ) ;
}
String path ;
if ( p = = n )
path = n - > get_name ( ) ;
else
path = String ( p - > get_name ( ) ) + " / " + p - > get_path_to ( n ) ;
print_line ( itos ( p_obj - > get_instance_ID ( ) ) + " - Stray Node: " + path + " (Type: " + n - > get_type ( ) + " ) " ) ;
}
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 ( ) {
2014-11-06 00:20:42 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
get_tree ( ) - > 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 ) ;
for ( int i = 0 ; i < cc ; i + + )
arr [ i ] = get_child ( i ) ;
return arr ;
}
2014-06-19 05:23:03 +00:00
# ifdef TOOLS_ENABLED
void Node : : set_import_path ( const NodePath & p_import_path ) {
data . import_path = p_import_path ;
}
NodePath Node : : get_import_path ( ) const {
return data . import_path ;
}
# endif
2014-12-17 01:31:57 +00:00
static void _add_nodes_to_options ( const Node * p_base , const Node * p_node , List < String > * r_options ) {
if ( p_node ! = p_base & & ! p_node - > get_owner ( ) )
return ;
String n = p_base - > get_path_to ( p_node ) ;
r_options - > push_back ( " \" " + n + " \" " ) ;
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_add_nodes_to_options ( p_base , p_node - > get_child ( i ) , r_options ) ;
}
}
void Node : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
String pf = p_function ;
if ( ( pf = = " has_node " | | pf = = " get_node " ) & & p_idx = = 0 ) {
_add_nodes_to_options ( this , this , r_options ) ;
}
Object : : get_argument_options ( p_function , p_idx , r_options ) ;
}
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 ( ) ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > clear_internal_tree_resource_paths ( ) ;
}
}
2016-05-17 21:27:15 +00:00
String Node : : get_configuration_warning ( ) const {
return String ( ) ;
}
void Node : : update_configuration_warning ( ) {
# ifdef TOOLS_ENABLED
if ( ! is_inside_tree ( ) )
return ;
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 ) ;
}
# 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 ) {
data . display_folded = p_folded ;
}
bool Node : : is_displayed_folded ( ) const {
return data . display_folded ;
}
2014-02-10 01:10:30 +00:00
void Node : : _bind_methods ( ) {
2016-05-13 16:09:49 +00:00
ObjectTypeDB : : bind_method ( _MD ( " _add_child_below_node " , " node:Node " , " child_node:Node " , " legible_unique_name " ) , & Node : : add_child_below_node , DEFVAL ( false ) ) ;
2014-02-10 01:10:30 +00:00
ObjectTypeDB : : bind_method ( _MD ( " set_name " , " name " ) , & Node : : set_name ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_name " ) , & Node : : get_name ) ;
2015-12-08 14:21:12 +00:00
ObjectTypeDB : : bind_method ( _MD ( " add_child " , " node:Node " , " legible_unique_name " ) , & Node : : add_child , DEFVAL ( false ) ) ;
2014-02-10 01:10:30 +00:00
ObjectTypeDB : : bind_method ( _MD ( " remove_child " , " node:Node " ) , & Node : : remove_child ) ;
2015-04-09 03:49:48 +00:00
//ObjectTypeDB::bind_method(_MD("remove_and_delete_child","node:Node"),&Node::remove_and_delete_child);
2014-02-10 01:10:30 +00:00
ObjectTypeDB : : bind_method ( _MD ( " get_child_count " ) , & Node : : get_child_count ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_children " ) , & Node : : _get_children ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_child:Node " , " idx " ) , & Node : : get_child ) ;
ObjectTypeDB : : bind_method ( _MD ( " has_node " , " path " ) , & Node : : has_node ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node:Node " , " path " ) , & Node : : get_node ) ;
2016-05-04 13:15:51 +00:00
ObjectTypeDB : : bind_method ( _MD ( " get_parent:Node " ) , & Node : : get_parent ) ;
2015-09-30 12:55:31 +00:00
ObjectTypeDB : : bind_method ( _MD ( " find_node:Node " , " mask " , " recursive " , " owned " ) , & Node : : find_node , DEFVAL ( true ) , DEFVAL ( true ) ) ;
2014-02-10 01:10:30 +00:00
ObjectTypeDB : : bind_method ( _MD ( " has_node_and_resource " , " path " ) , & Node : : has_node_and_resource ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_node_and_resource " , " path " ) , & Node : : _get_node_and_resource ) ;
2014-11-06 00:20:42 +00:00
ObjectTypeDB : : bind_method ( _MD ( " is_inside_tree " ) , & Node : : is_inside_tree ) ;
2014-02-10 01:10:30 +00:00
ObjectTypeDB : : bind_method ( _MD ( " is_a_parent_of " , " node:Node " ) , & Node : : is_a_parent_of ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_greater_than " , " node:Node " ) , & Node : : is_greater_than ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_path " ) , & Node : : get_path ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_path_to " , " node:Node " ) , & Node : : get_path_to ) ;
2015-12-28 01:13:05 +00:00
ObjectTypeDB : : bind_method ( _MD ( " add_to_group " , " group " , " persistent " ) , & Node : : add_to_group , DEFVAL ( false ) ) ;
2014-02-10 01:10:30 +00:00
ObjectTypeDB : : bind_method ( _MD ( " remove_from_group " , " group " ) , & Node : : remove_from_group ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_in_group " , " group " ) , & Node : : is_in_group ) ;
ObjectTypeDB : : bind_method ( _MD ( " move_child " , " child_node:Node " , " to_pos " ) , & Node : : move_child ) ;
2014-06-16 13:22:26 +00:00
ObjectTypeDB : : bind_method ( _MD ( " get_groups " ) , & Node : : _get_groups ) ;
2014-02-10 01:10:30 +00:00
ObjectTypeDB : : bind_method ( _MD ( " raise " ) , & Node : : raise ) ;
ObjectTypeDB : : bind_method ( _MD ( " set_owner " , " owner:Node " ) , & Node : : set_owner ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_owner:Node " ) , & Node : : get_owner ) ;
ObjectTypeDB : : bind_method ( _MD ( " remove_and_skip " ) , & Node : : remove_and_skip ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_index " ) , & Node : : get_index ) ;
ObjectTypeDB : : bind_method ( _MD ( " print_tree " ) , & Node : : print_tree ) ;
ObjectTypeDB : : bind_method ( _MD ( " set_filename " , " filename " ) , & Node : : set_filename ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_filename " ) , & Node : : get_filename ) ;
ObjectTypeDB : : bind_method ( _MD ( " propagate_notification " , " what " ) , & Node : : propagate_notification ) ;
ObjectTypeDB : : bind_method ( _MD ( " set_fixed_process " , " enable " ) , & Node : : set_fixed_process ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_fixed_process_delta_time " ) , & Node : : get_fixed_process_delta_time ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_fixed_processing " ) , & Node : : is_fixed_processing ) ;
ObjectTypeDB : : bind_method ( _MD ( " set_process " , " enable " ) , & Node : : set_process ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_process_delta_time " ) , & Node : : get_process_delta_time ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_processing " ) , & Node : : is_processing ) ;
ObjectTypeDB : : bind_method ( _MD ( " set_process_input " , " enable " ) , & Node : : set_process_input ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_processing_input " ) , & Node : : is_processing_input ) ;
ObjectTypeDB : : bind_method ( _MD ( " set_process_unhandled_input " , " enable " ) , & Node : : set_process_unhandled_input ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_processing_unhandled_input " ) , & Node : : is_processing_unhandled_input ) ;
2014-04-10 03:18:27 +00:00
ObjectTypeDB : : bind_method ( _MD ( " set_process_unhandled_key_input " , " enable " ) , & Node : : set_process_unhandled_key_input ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_processing_unhandled_key_input " ) , & Node : : is_processing_unhandled_key_input ) ;
2014-02-10 01:10:30 +00:00
ObjectTypeDB : : bind_method ( _MD ( " set_pause_mode " , " mode " ) , & Node : : set_pause_mode ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_pause_mode " ) , & Node : : get_pause_mode ) ;
ObjectTypeDB : : bind_method ( _MD ( " can_process " ) , & Node : : can_process ) ;
ObjectTypeDB : : bind_method ( _MD ( " print_stray_nodes " ) , & Node : : _print_stray_nodes ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_position_in_parent " ) , & Node : : get_position_in_parent ) ;
2016-06-28 16:10:15 +00:00
ObjectTypeDB : : bind_method ( _MD ( " set_display_folded " , " fold " ) , & Node : : set_display_folded ) ;
ObjectTypeDB : : bind_method ( _MD ( " is_displayed_folded " ) , & Node : : is_displayed_folded ) ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
ObjectTypeDB : : bind_method ( _MD ( " get_tree:SceneTree " ) , & Node : : get_tree ) ;
2014-02-10 01:10:30 +00:00
2015-08-02 15:29:37 +00:00
ObjectTypeDB : : bind_method ( _MD ( " duplicate:Node " , " use_instancing " ) , & Node : : duplicate , DEFVAL ( false ) ) ;
2014-02-10 01:10:30 +00:00
ObjectTypeDB : : bind_method ( _MD ( " replace_by " , " node:Node " , " keep_data " ) , & Node : : replace_by , DEFVAL ( false ) ) ;
2015-11-14 14:14:17 +00:00
ObjectTypeDB : : bind_method ( _MD ( " set_scene_instance_load_placeholder " , " load_placeholder " ) , & Node : : set_scene_instance_load_placeholder ) ;
ObjectTypeDB : : bind_method ( _MD ( " get_scene_instance_load_placeholder " ) , & Node : : get_scene_instance_load_placeholder ) ;
2014-04-10 03:18:27 +00:00
ObjectTypeDB : : bind_method ( _MD ( " get_viewport " ) , & Node : : get_viewport ) ;
2014-02-10 01:10:30 +00:00
ObjectTypeDB : : bind_method ( _MD ( " queue_free " ) , & Node : : queue_delete ) ;
2016-05-17 21:27:15 +00:00
2014-06-19 05:23:03 +00:00
# ifdef TOOLS_ENABLED
ObjectTypeDB : : bind_method ( _MD ( " _set_import_path " , " import_path " ) , & Node : : set_import_path ) ;
ObjectTypeDB : : bind_method ( _MD ( " _get_import_path " ) , & Node : : get_import_path ) ;
2015-06-29 03:29:49 +00:00
ADD_PROPERTYNZ ( PropertyInfo ( Variant : : NODE_PATH , " _import_path " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR ) , _SCS ( " _set_import_path " ) , _SCS ( " _get_import_path " ) ) ;
2014-06-19 05:23:03 +00:00
# endif
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
BIND_CONSTANT ( NOTIFICATION_ENTER_TREE ) ;
BIND_CONSTANT ( NOTIFICATION_EXIT_TREE ) ;
2014-02-10 01:10:30 +00:00
BIND_CONSTANT ( NOTIFICATION_MOVED_IN_PARENT ) ;
//BIND_CONSTANT( NOTIFICATION_PARENT_DECONFIGURED );
BIND_CONSTANT ( NOTIFICATION_READY ) ;
BIND_CONSTANT ( NOTIFICATION_FIXED_PROCESS ) ;
BIND_CONSTANT ( NOTIFICATION_PROCESS ) ;
BIND_CONSTANT ( NOTIFICATION_PARENTED ) ;
BIND_CONSTANT ( NOTIFICATION_UNPARENTED ) ;
BIND_CONSTANT ( NOTIFICATION_PAUSED ) ;
BIND_CONSTANT ( NOTIFICATION_UNPAUSED ) ;
2016-01-03 15:54:58 +00:00
BIND_CONSTANT ( NOTIFICATION_INSTANCED ) ;
2016-05-11 14:46:08 +00:00
BIND_CONSTANT ( NOTIFICATION_DRAG_BEGIN ) ;
BIND_CONSTANT ( NOTIFICATION_DRAG_END ) ;
2016-01-03 15:54:58 +00:00
2014-02-10 01:10:30 +00:00
BIND_CONSTANT ( PAUSE_MODE_INHERIT ) ;
BIND_CONSTANT ( PAUSE_MODE_STOP ) ;
BIND_CONSTANT ( PAUSE_MODE_PROCESS ) ;
ADD_SIGNAL ( MethodInfo ( " renamed " ) ) ;
2014-11-06 00:20:42 +00:00
ADD_SIGNAL ( MethodInfo ( " enter_tree " ) ) ;
ADD_SIGNAL ( MethodInfo ( " exit_tree " ) ) ;
2014-02-10 01:10:30 +00:00
// ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/process" ),_SCS("set_process"),_SCS("is_processing") );
// ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/fixed_process" ), _SCS("set_fixed_process"),_SCS("is_fixed_processing") );
//ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/input" ), _SCS("set_process_input"),_SCS("is_processing_input" ) );
//ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), _SCS("set_process_unhandled_input"),_SCS("is_processing_unhandled_input" ) );
ADD_PROPERTYNZ ( PropertyInfo ( Variant : : INT , " process/pause_mode " , PROPERTY_HINT_ENUM , " Inherit,Stop,Process " ) , _SCS ( " set_pause_mode " ) , _SCS ( " get_pause_mode " ) ) ;
2016-06-28 16:10:15 +00:00
ADD_PROPERTYNZ ( PropertyInfo ( Variant : : BOOL , " editor/display_folded " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR ) , _SCS ( " set_display_folded " ) , _SCS ( " is_displayed_folded " ) ) ;
2014-02-10 01:10:30 +00:00
BIND_VMETHOD ( MethodInfo ( " _process " , PropertyInfo ( Variant : : REAL , " delta " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( " _fixed_process " , PropertyInfo ( Variant : : REAL , " delta " ) ) ) ;
2014-11-06 00:20:42 +00:00
BIND_VMETHOD ( MethodInfo ( " _enter_tree " ) ) ;
BIND_VMETHOD ( MethodInfo ( " _exit_tree " ) ) ;
2014-02-10 01:10:30 +00:00
BIND_VMETHOD ( MethodInfo ( " _ready " ) ) ;
BIND_VMETHOD ( MethodInfo ( " _input " , PropertyInfo ( Variant : : INPUT_EVENT , " event " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( " _unhandled_input " , PropertyInfo ( Variant : : INPUT_EVENT , " event " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( " _unhandled_key_input " , PropertyInfo ( Variant : : INPUT_EVENT , " key_event " ) ) ) ;
//ObjectTypeDB::bind_method(_MD("get_child",&Node::get_child,PH("index")));
//ObjectTypeDB::bind_method(_MD("get_node",&Node::get_node,PH("path")));
}
Node : : Node ( ) {
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . pos = - 1 ;
data . depth = - 1 ;
data . blocked = 0 ;
data . parent = NULL ;
2014-11-06 00:20:42 +00:00
data . tree = NULL ;
2014-02-10 01:10:30 +00:00
data . fixed_process = false ;
data . idle_process = false ;
2014-11-06 00:20:42 +00:00
data . inside_tree = false ;
2014-02-10 01:10:30 +00:00
data . owner = NULL ;
2014-04-10 03:18:27 +00:00
data . OW = NULL ;
2014-02-10 01:10:30 +00:00
data . input = false ;
data . unhandled_input = false ;
2014-04-10 03:18:27 +00:00
data . unhandled_key_input = false ;
2014-02-10 01:10:30 +00:00
data . pause_mode = PAUSE_MODE_INHERIT ;
data . pause_owner = NULL ;
data . parent_owned = false ;
data . in_constructor = true ;
2014-04-10 03:18:27 +00:00
data . viewport = NULL ;
2015-10-16 22:11:23 +00:00
data . use_placeholder = false ;
2016-06-28 16:10:15 +00:00
data . display_folded = false ;
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
2016-06-28 16:10:15 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( data . parent ) ;
ERR_FAIL_COND ( data . children . size ( ) ) ;
}
2015-10-16 22:11:23 +00:00
////////////////////////////////