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
/*************************************************************************/
2022-01-03 20:27:34 +00:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 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
2022-02-12 01:46:22 +00:00
# include "core/config/project_settings.h"
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"
2021-10-08 12:13:06 +00:00
# include "core/multiplayer/multiplayer_api.h"
2020-11-07 22:33:38 +00:00
# include "core/object/message_queue.h"
# include "core/string/print_string.h"
2017-03-05 15:44:50 +00:00
# include "instance_placeholder.h"
2020-09-05 01:05:30 +00:00
# include "scene/animation/tween.h"
2020-02-07 01:52:05 +00:00
# include "scene/debugger/scene_debugger.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
2020-02-21 22:26:13 +00:00
# include <stdint.h>
2021-02-18 18:52:29 +00:00
VARIANT_ENUM_CAST ( Node : : ProcessMode ) ;
2021-08-25 13:49:30 +00:00
VARIANT_ENUM_CAST ( Node : : InternalMode ) ;
2014-02-10 01:10:30 +00:00
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 ) {
2017-03-05 15:44:50 +00:00
switch ( p_notification ) {
2014-02-10 01:10:30 +00:00
case NOTIFICATION_PROCESS : {
2021-08-22 01:52:44 +00:00
GDVIRTUAL_CALL ( _process , get_process_delta_time ( ) ) ;
2014-02-10 01:10:30 +00:00
} break ;
2022-02-15 17:06:48 +00:00
2017-09-30 14:19:07 +00:00
case NOTIFICATION_PHYSICS_PROCESS : {
2021-08-26 17:49:12 +00:00
GDVIRTUAL_CALL ( _physics_process , get_physics_process_delta_time ( ) ) ;
2014-02-10 01:10:30 +00:00
} break ;
2022-02-15 17:06:48 +00:00
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
2021-02-18 18:52:29 +00:00
if ( data . process_mode = = PROCESS_MODE_INHERIT ) {
2020-05-14 14:41:43 +00:00
if ( data . parent ) {
2021-02-18 18:52:29 +00:00
data . process_owner = data . parent - > data . process_owner ;
2020-05-14 14:41:43 +00:00
} else {
2021-06-22 00:49:34 +00:00
ERR_PRINT ( " The root node can't be set to Inherit process mode, reverting to Pausable instead. " ) ;
data . process_mode = PROCESS_MODE_PAUSABLE ;
data . process_owner = this ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
} else {
2021-02-18 18:52:29 +00:00
data . process_owner = this ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 14:41:43 +00:00
if ( data . input ) {
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
2022-01-11 13:59:52 +00:00
if ( data . shortcut_input ) {
add_to_group ( " _vp_shortcut_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
}
2020-05-14 14:41:43 +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 ( ) ) ) ;
2020-05-14 14:41:43 +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 ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
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 ;
2022-02-15 17:06:48 +00:00
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 + + ;
2020-05-14 14:41:43 +00:00
if ( data . input ) {
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
2022-01-11 13:59:52 +00:00
if ( data . shortcut_input ) {
remove_from_group ( " _vp_shortcut_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
}
2020-05-14 14:41:43 +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 ( ) ) ) ;
2020-05-14 14:41:43 +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 ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
2016-08-14 21:49:50 +00:00
2021-02-18 18:52:29 +00:00
data . process_owner = nullptr ;
2016-08-14 21:49:50 +00:00
if ( data . path_cache ) {
memdelete ( data . path_cache ) ;
2020-04-01 23:20:12 +00:00
data . path_cache = nullptr ;
2016-08-14 21:49:50 +00:00
}
} break ;
2022-02-15 17:06:48 +00:00
2021-09-03 22:12:37 +00:00
case NOTIFICATION_PATH_RENAMED : {
2016-08-14 21:49:50 +00:00
if ( data . path_cache ) {
memdelete ( data . path_cache ) ;
2020-04-01 23:20:12 +00:00
data . path_cache = nullptr ;
2016-08-14 21:49:50 +00:00
}
2014-02-10 01:10:30 +00:00
} break ;
2022-02-15 17:06:48 +00:00
2014-02-10 01:10:30 +00:00
case NOTIFICATION_READY : {
2021-09-04 09:14:51 +00:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _input ) ) {
set_process_input ( true ) ;
}
2017-01-10 21:02:19 +00:00
2022-01-11 13:59:52 +00:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _shortcut_input ) ) {
set_process_shortcut_input ( true ) ;
}
2021-09-04 09:14:51 +00:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _unhandled_input ) ) {
set_process_unhandled_input ( true ) ;
}
2017-01-10 21:02:19 +00:00
2021-09-04 09:14:51 +00:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _unhandled_key_input ) ) {
set_process_unhandled_key_input ( true ) ;
}
2017-01-10 21:02:19 +00:00
2021-09-04 09:14:51 +00:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _process ) ) {
set_process ( true ) ;
2014-02-10 01:10:30 +00:00
}
2021-09-04 09:14:51 +00:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _physics_process ) ) {
set_physics_process ( true ) ;
}
GDVIRTUAL_CALL ( _ready ) ;
2014-02-10 01:10:30 +00:00
} break ;
2022-02-15 17:06:48 +00:00
2014-02-10 01:10:30 +00:00
case NOTIFICATION_POSTINITIALIZE : {
2017-03-05 15:44:50 +00:00
data . in_constructor = false ;
2014-02-10 01:10:30 +00:00
} break ;
2022-02-15 17:06:48 +00:00
2014-02-10 01:10:30 +00:00
case NOTIFICATION_PREDELETE : {
if ( data . parent ) {
data . parent - > remove_child ( this ) ;
}
// kill children as cleanly as possible
2017-03-05 15:44:50 +00:00
while ( data . children . size ( ) ) {
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
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 ) ;
2020-05-14 14:41:43 +00:00
if ( ! data . viewport & & data . parent ) {
2014-04-10 03:18:27 +00:00
data . viewport = data . parent - > data . viewport ;
2020-05-14 14:41:43 +00:00
}
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
2021-08-09 20:13:42 +00:00
for ( KeyValue < StringName , GroupData > & E : data . grouped ) {
E . value . 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
2021-08-22 01:52:44 +00:00
GDVIRTUAL_CALL ( _enter_tree ) ;
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 ) ;
2022-02-02 10:22:11 +00:00
if ( data . parent ) {
Variant c = this ;
const Variant * cptr = & c ;
2022-03-09 13:58:40 +00:00
data . parent - > emit_signalp ( SNAME ( " child_entered_tree " ) , & cptr , 1 ) ;
2022-02-02 10:22:11 +00:00
}
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 + + ) {
2020-05-14 14:41:43 +00:00
if ( ! data . children [ i ] - > is_inside_tree ( ) ) { // could have been added in enter_tree
2014-11-06 00:20:42 +00:00
data . children [ i ] - > _propagate_enter_tree ( ) ;
2020-05-14 14:41:43 +00:00
}
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
2021-09-30 14:30:55 +00:00
SceneDebugger : : add_to_cache ( data . scene_file_path , this ) ;
2015-08-02 15:29:37 +00:00
# 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 ( ) {
2022-01-05 13:00:04 +00:00
// Clear owner if it was not part of the pruned branch
2021-12-01 13:28:59 +00:00
if ( data . owner ) {
2022-01-05 13:00:04 +00:00
bool found = false ;
Node * parent = data . parent ;
while ( parent ) {
if ( parent = = data . owner ) {
found = true ;
break ;
}
parent = parent - > data . parent ;
}
if ( ! found ) {
2022-04-16 10:23:32 +00:00
if ( data . unique_name_in_owner ) {
_release_unique_name_in_owner ( ) ;
}
2022-01-05 13:00:04 +00:00
data . owner - > data . owned . erase ( data . OW ) ;
data . owner = nullptr ;
}
2021-12-01 13:28:59 +00:00
}
2022-01-05 13:00:04 +00:00
2018-09-07 18:31:19 +00:00
data . blocked + + ;
2021-12-01 13:28:59 +00:00
for ( int i = data . children . size ( ) - 1 ; i > = 0 ; i - - ) {
2018-09-07 18:31:19 +00:00
data . children [ i ] - > _propagate_after_exit_tree ( ) ;
}
data . blocked - - ;
2022-01-05 13:00:04 +00:00
2018-09-07 18:31:19 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > tree_exited ) ;
}
2014-11-06 00:20:42 +00:00
void Node : : _propagate_exit_tree ( ) {
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
2021-09-30 14:30:55 +00:00
SceneDebugger : : remove_from_cache ( data . scene_file_path , this ) ;
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-11-06 00:20:42 +00:00
data . children [ i ] - > _propagate_exit_tree ( ) ;
2014-02-10 01:10:30 +00:00
}
data . blocked - - ;
2021-08-22 01:52:44 +00:00
GDVIRTUAL_CALL ( _exit_tree ) ;
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 ) ;
2020-05-14 14:41:43 +00:00
if ( data . tree ) {
2014-11-06 00:20:42 +00:00
data . tree - > node_removed ( this ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2022-02-02 10:22:11 +00:00
if ( data . parent ) {
Variant c = this ;
const Variant * cptr = & c ;
2022-06-20 07:53:44 +00:00
data . parent - > emit_signalp ( SNAME ( " child_exiting_tree " ) , & cptr , 1 ) ;
2022-02-02 10:22:11 +00:00
}
2014-02-10 01:10:30 +00:00
// exit groups
2021-08-09 20:13:42 +00:00
for ( KeyValue < StringName , GroupData > & E : data . grouped ) {
data . tree - > remove_from_group ( E . key , this ) ;
E . value . group = nullptr ;
2014-02-10 01:10:30 +00:00
}
2020-04-01 23:20:12 +00:00
data . viewport = nullptr ;
2014-04-10 03:18:27 +00:00
2020-05-14 14:41:43 +00:00
if ( data . tree ) {
2014-11-06 00:20:42 +00:00
data . tree - > tree_changed ( ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . inside_tree = false ;
data . ready_notified = false ;
2020-04-01 23:20:12 +00:00
data . tree = nullptr ;
2017-03-05 15:44:50 +00:00
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 ) {
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 - > data . parent ! = this , " Child is not a child of this node. " ) ;
2021-08-25 13:49:30 +00:00
// We need to check whether node is internal and move it only in the relevant node range.
if ( p_child - > _is_internal_front ( ) ) {
ERR_FAIL_INDEX_MSG ( p_pos , data . internal_children_front , vformat ( " Invalid new child position: %d. Child is internal. " , p_pos ) ) ;
_move_child ( p_child , p_pos ) ;
} else if ( p_child - > _is_internal_back ( ) ) {
ERR_FAIL_INDEX_MSG ( p_pos , data . internal_children_back , vformat ( " Invalid new child position: %d. Child is internal. " , p_pos ) ) ;
_move_child ( p_child , data . children . size ( ) - data . internal_children_back + p_pos ) ;
} else {
ERR_FAIL_INDEX_MSG ( p_pos , data . children . size ( ) + 1 - data . internal_children_front - data . internal_children_back , vformat ( " Invalid new child position: %d. " , p_pos ) ) ;
_move_child ( p_child , p_pos + data . internal_children_front ) ;
}
}
void Node : : _move_child ( Node * p_child , int p_pos , bool p_ignore_end ) {
2019-08-08 20:11:48 +00:00
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
2021-08-25 13:49:30 +00:00
if ( ! p_ignore_end ) { // p_ignore_end is a little hack to make back internal children work properly.
if ( p_child - > _is_internal_front ( ) ) {
if ( p_pos = = data . internal_children_front ) {
p_pos - - ;
}
} else if ( p_child - > _is_internal_back ( ) ) {
if ( p_pos = = data . children . size ( ) ) {
p_pos - - ;
}
} else {
if ( p_pos = = data . children . size ( ) - data . internal_children_back ) {
p_pos - - ;
}
}
2020-05-14 14:41:43 +00:00
}
2017-07-25 03:11:00 +00:00
2020-05-14 14:41:43 +00:00
if ( p_child - > data . pos = = p_pos ) {
2016-10-03 19:33:42 +00:00
return ; //do nothing
2020-05-14 14:41:43 +00:00
}
2016-10-03 19:33:42 +00:00
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
2021-07-03 22:17:03 +00:00
data . children . remove_at ( p_child - > data . pos ) ;
2017-03-05 15:44:50 +00:00
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 + + ) {
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
}
2022-05-31 18:28:04 +00:00
p_child - > _propagate_groups_dirty ( ) ;
2014-02-10 01:10:30 +00:00
data . blocked - - ;
}
void Node : : raise ( ) {
2020-05-14 14:41:43 +00:00
if ( ! data . parent ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2021-08-25 13:49:30 +00:00
// Internal children move within a different index range.
if ( _is_internal_front ( ) ) {
data . parent - > move_child ( this , data . parent - > data . internal_children_front - 1 ) ;
} else if ( _is_internal_back ( ) ) {
data . parent - > move_child ( this , data . parent - > data . internal_children_back - 1 ) ;
} else {
data . parent - > move_child ( this , data . parent - > get_child_count ( false ) - 1 ) ;
}
2014-02-10 01:10:30 +00:00
}
2022-05-31 18:28:04 +00:00
void Node : : _propagate_groups_dirty ( ) {
for ( const KeyValue < StringName , GroupData > & E : data . grouped ) {
if ( E . value . group ) {
E . value . group - > changed = true ;
}
}
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > _propagate_groups_dirty ( ) ;
}
}
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
}
2022-06-23 06:19:18 +00:00
void Node : : owner_changed_notify ( ) {
}
2017-09-30 14:19:07 +00:00
void Node : : set_physics_process ( bool p_process ) {
2020-05-14 14:41:43 +00:00
if ( data . physics_process = = p_process ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-09-30 14:19:07 +00:00
data . physics_process = p_process ;
2016-03-08 23:00:52 +00:00
2020-05-14 14:41:43 +00:00
if ( data . physics_process ) {
2022-07-01 18:16:05 +00:00
add_to_group ( SNAME ( " _physics_process " ) , false ) ;
2020-05-14 14:41:43 +00:00
} else {
2022-07-01 18:16:05 +00:00
remove_from_group ( SNAME ( " _physics_process " ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-09-30 14:19:07 +00:00
bool Node : : is_physics_processing ( ) const {
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 ) {
2020-05-14 14:41:43 +00:00
if ( data . physics_process_internal = = p_process_internal ) {
2017-01-10 21:02:19 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-01-10 21:02:19 +00:00
2017-09-30 14:19:07 +00:00
data . physics_process_internal = p_process_internal ;
2017-01-10 21:02:19 +00:00
2020-05-14 14:41:43 +00:00
if ( data . physics_process_internal ) {
2022-07-01 18:16:05 +00:00
add_to_group ( SNAME ( " _physics_process_internal " ) , false ) ;
2020-05-14 14:41:43 +00:00
} else {
2022-07-01 18:16:05 +00:00
remove_from_group ( SNAME ( " _physics_process_internal " ) ) ;
2020-05-14 14:41:43 +00:00
}
2017-01-10 21:02:19 +00:00
}
2017-09-30 14:19:07 +00:00
bool Node : : is_physics_processing_internal ( ) const {
return data . physics_process_internal ;
2017-01-10 21:02:19 +00:00
}
2021-02-18 18:52:29 +00:00
void Node : : set_process_mode ( ProcessMode p_mode ) {
if ( data . process_mode = = p_mode ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2021-02-18 18:52:29 +00:00
data . process_mode = p_mode ;
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2021-02-18 18:52:29 +00:00
bool prev_can_process = can_process ( ) ;
2021-06-18 01:09:40 +00:00
bool prev_enabled = _is_enabled ( ) ;
2021-02-18 18:52:29 +00:00
2021-06-22 00:49:34 +00:00
if ( p_mode = = PROCESS_MODE_INHERIT ) {
2020-05-14 14:41:43 +00:00
if ( data . parent ) {
2021-06-22 00:49:34 +00:00
data . process_owner = data . parent - > data . process_owner ;
2021-02-18 18:52:29 +00:00
} else {
2021-06-22 00:49:34 +00:00
ERR_FAIL_MSG ( " The root node can't be set to Inherit process mode. " ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
} else {
2021-02-18 18:52:29 +00:00
data . process_owner = this ;
}
2021-06-22 00:49:34 +00:00
data . process_mode = p_mode ;
2021-02-18 18:52:29 +00:00
bool next_can_process = can_process ( ) ;
2021-06-18 01:09:40 +00:00
bool next_enabled = _is_enabled ( ) ;
2021-02-18 18:52:29 +00:00
int pause_notification = 0 ;
if ( prev_can_process & & ! next_can_process ) {
pause_notification = NOTIFICATION_PAUSED ;
} else if ( ! prev_can_process & & next_can_process ) {
pause_notification = NOTIFICATION_UNPAUSED ;
}
2021-06-18 01:09:40 +00:00
int enabled_notification = 0 ;
if ( prev_enabled & & ! next_enabled ) {
enabled_notification = NOTIFICATION_DISABLED ;
} else if ( ! prev_enabled & & next_enabled ) {
enabled_notification = NOTIFICATION_ENABLED ;
}
_propagate_process_owner ( data . process_owner , pause_notification , enabled_notification ) ;
2021-02-18 18:52:29 +00:00
# ifdef TOOLS_ENABLED
// This is required for the editor to update the visibility of disabled nodes
2021-03-12 13:35:16 +00:00
// It's very expensive during runtime to change, so editor-only
2021-02-18 18:52:29 +00:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2021-07-17 21:22:52 +00:00
get_tree ( ) - > emit_signal ( SNAME ( " tree_process_mode_changed " ) ) ;
2014-02-10 01:10:30 +00:00
}
2021-02-18 18:52:29 +00:00
# endif
}
void Node : : _propagate_pause_notification ( bool p_enable ) {
bool prev_can_process = _can_process ( ! p_enable ) ;
bool next_can_process = _can_process ( p_enable ) ;
2014-02-10 01:10:30 +00:00
2021-02-18 18:52:29 +00:00
if ( prev_can_process & & ! next_can_process ) {
notification ( NOTIFICATION_PAUSED ) ;
} else if ( ! prev_can_process & & next_can_process ) {
notification ( NOTIFICATION_UNPAUSED ) ;
}
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > _propagate_pause_notification ( p_enable ) ;
}
2014-02-10 01:10:30 +00:00
}
2021-02-18 18:52:29 +00:00
Node : : ProcessMode Node : : get_process_mode ( ) const {
return data . process_mode ;
2014-02-10 01:10:30 +00:00
}
2021-06-18 01:09:40 +00:00
void Node : : _propagate_process_owner ( Node * p_owner , int p_pause_notification , int p_enabled_notification ) {
2021-02-18 18:52:29 +00:00
data . process_owner = p_owner ;
2021-06-18 01:09:40 +00:00
if ( p_pause_notification ! = 0 ) {
notification ( p_pause_notification ) ;
}
if ( p_enabled_notification ! = 0 ) {
notification ( p_enabled_notification ) ;
2020-05-14 14:41:43 +00:00
}
2021-02-18 18:52:29 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2021-02-18 18:52:29 +00:00
Node * c = data . children [ i ] ;
if ( c - > data . process_mode = = PROCESS_MODE_INHERIT ) {
2021-06-18 01:09:40 +00:00
c - > _propagate_process_owner ( p_owner , p_pause_notification , p_enabled_notification ) ;
2021-02-18 18:52:29 +00:00
}
2014-02-10 01:10:30 +00:00
}
}
2021-09-07 21:35:19 +00:00
void Node : : set_multiplayer_authority ( int p_peer_id , bool p_recursive ) {
data . multiplayer_authority = 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 + + ) {
2021-09-07 21:35:19 +00:00
data . children [ i ] - > set_multiplayer_authority ( p_peer_id , true ) ;
2017-07-03 13:44:45 +00:00
}
2016-08-14 21:49:50 +00:00
}
}
2021-09-07 21:35:19 +00:00
int Node : : get_multiplayer_authority ( ) const {
return data . multiplayer_authority ;
2016-08-14 21:49:50 +00:00
}
2021-09-07 21:35:19 +00:00
bool Node : : is_multiplayer_authority ( ) 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
2021-09-07 21:35:19 +00:00
return get_multiplayer ( ) - > get_unique_id ( ) = = data . multiplayer_authority ;
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
2021-10-06 15:25:50 +00:00
uint16_t Node : : rpc_config ( const StringName & p_method , Multiplayer : : RPCMode p_rpc_mode , bool p_call_local , Multiplayer : : TransferMode p_transfer_mode , int p_channel ) {
2021-05-26 12:07:57 +00:00
for ( int i = 0 ; i < data . rpc_methods . size ( ) ; i + + ) {
if ( data . rpc_methods [ i ] . name = = p_method ) {
2021-09-03 17:40:47 +00:00
Multiplayer : : RPCConfig & nd = data . rpc_methods . write [ i ] ;
2021-05-26 12:07:57 +00:00
nd . rpc_mode = p_rpc_mode ;
nd . transfer_mode = p_transfer_mode ;
2021-10-06 15:25:50 +00:00
nd . call_local = p_call_local ;
2021-05-26 12:07:57 +00:00
nd . channel = p_channel ;
return i | ( 1 < < 15 ) ;
}
2020-02-12 10:51:50 +00:00
}
2021-05-26 12:07:57 +00:00
// New method
2021-09-03 17:40:47 +00:00
Multiplayer : : RPCConfig nd ;
2021-05-26 12:07:57 +00:00
nd . name = p_method ;
nd . rpc_mode = p_rpc_mode ;
nd . transfer_mode = p_transfer_mode ;
nd . channel = p_channel ;
2021-10-06 15:25:50 +00:00
nd . call_local = p_call_local ;
2021-05-26 12:07:57 +00:00
data . rpc_methods . push_back ( nd ) ;
return ( ( uint16_t ) data . rpc_methods . size ( ) - 1 ) | ( 1 < < 15 ) ;
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
2022-02-22 11:15:43 +00:00
void Node : : _rpc_bind ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2017-03-05 15:44:50 +00:00
if ( p_argcount < 1 ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2017-03-05 15:44:50 +00:00
r_error . argument = 1 ;
2022-02-22 11:15:43 +00:00
return ;
2016-08-19 19:48:08 +00:00
}
2016-08-14 21:49:50 +00:00
2022-02-09 13:27:16 +00:00
Variant : : Type type = p_args [ 0 ] - > get_type ( ) ;
if ( type ! = Variant : : STRING_NAME & & type ! = Variant : : STRING ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2017-03-05 15:44:50 +00:00
r_error . argument = 0 ;
2021-05-03 13:45:36 +00:00
r_error . expected = Variant : : STRING_NAME ;
2022-02-22 11:15:43 +00:00
return ;
2016-08-19 19:48:08 +00:00
}
2016-08-14 21:49:50 +00:00
2022-02-09 13:27:16 +00:00
StringName method = ( * p_args [ 0 ] ) . operator StringName ( ) ;
2016-08-14 21:49:50 +00:00
2021-05-26 12:07:57 +00:00
rpcp ( 0 , method , & p_args [ 1 ] , p_argcount - 1 ) ;
2016-08-14 21:49:50 +00:00
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_OK ;
2016-08-14 21:49:50 +00:00
}
2022-02-22 11:15:43 +00:00
void Node : : _rpc_id_bind ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2017-03-05 15:44:50 +00:00
if ( p_argcount < 2 ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2017-03-05 15:44:50 +00:00
r_error . argument = 2 ;
2022-02-22 11:15:43 +00:00
return ;
2016-08-19 19:48:08 +00:00
}
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : INT ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2017-03-05 15:44:50 +00:00
r_error . argument = 0 ;
r_error . expected = Variant : : INT ;
2022-02-22 11:15:43 +00:00
return ;
2016-08-19 19:48:08 +00:00
}
2022-02-09 13:27:16 +00:00
Variant : : Type type = p_args [ 1 ] - > get_type ( ) ;
if ( type ! = Variant : : STRING_NAME & & type ! = Variant : : STRING ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2017-03-05 15:44:50 +00:00
r_error . argument = 1 ;
2021-05-03 13:45:36 +00:00
r_error . expected = Variant : : STRING_NAME ;
2022-02-22 11:15:43 +00:00
return ;
2016-08-19 19:48:08 +00:00
}
int peer_id = * p_args [ 0 ] ;
2022-02-09 13:27:16 +00:00
StringName method = ( * p_args [ 1 ] ) . operator StringName ( ) ;
2016-08-19 19:48:08 +00:00
2021-05-26 12:07:57 +00:00
rpcp ( peer_id , method , & p_args [ 2 ] , p_argcount - 2 ) ;
2016-08-19 19:48:08 +00:00
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_OK ;
2016-08-19 19:48:08 +00:00
}
2021-05-26 12:07:57 +00:00
void Node : : rpcp ( int p_peer_id , 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 ( ) ) ;
2021-09-03 17:40:47 +00:00
get_multiplayer ( ) - > rpcp ( this , p_peer_id , p_method , p_arg , p_argcount ) ;
2016-08-19 19:48:08 +00:00
}
2018-05-08 08:51:04 +00:00
Ref < MultiplayerAPI > Node : : get_multiplayer ( ) const {
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2018-03-03 17:30:11 +00:00
return Ref < MultiplayerAPI > ( ) ;
2020-05-14 14:41:43 +00:00
}
2022-02-05 00:43:47 +00:00
return get_tree ( ) - > get_multiplayer ( get_path ( ) ) ;
2018-03-03 17:30:11 +00:00
}
2021-09-03 17:40:47 +00:00
Vector < Multiplayer : : RPCConfig > Node : : get_node_rpc_methods ( ) const {
2021-05-26 12:07:57 +00:00
return data . rpc_methods ;
2018-03-03 17:30:11 +00:00
}
2021-05-26 12:07:57 +00:00
//////////// end of rpc
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 ) {
2020-05-10 11:00:47 +00:00
case NOTIFICATION_PHYSICS_PROCESS :
return data . physics_process ;
case NOTIFICATION_PROCESS :
2020-12-22 09:50:29 +00:00
return data . process ;
2020-05-10 11:00:47 +00:00
case NOTIFICATION_INTERNAL_PROCESS :
2020-12-22 09:50:29 +00:00
return data . process_internal ;
2020-05-10 11:00:47 +00:00
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS :
return data . physics_process_internal ;
2018-07-30 00:20:41 +00:00
}
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 ) ;
2021-02-18 18:52:29 +00:00
return _can_process ( get_tree ( ) - > is_paused ( ) ) ;
}
2014-02-10 01:10:30 +00:00
2021-02-18 18:52:29 +00:00
bool Node : : _can_process ( bool p_paused ) const {
ProcessMode process_mode ;
2014-02-10 01:10:30 +00:00
2021-02-18 18:52:29 +00:00
if ( data . process_mode = = PROCESS_MODE_INHERIT ) {
if ( ! data . process_owner ) {
process_mode = PROCESS_MODE_PAUSABLE ;
} else {
process_mode = data . process_owner - > data . process_mode ;
2014-02-10 01:10:30 +00:00
}
2021-02-18 18:52:29 +00:00
} else {
process_mode = data . process_mode ;
2014-02-10 01:10:30 +00:00
}
2021-06-22 00:49:34 +00:00
// The owner can't be set to inherit, must be a bug.
ERR_FAIL_COND_V ( process_mode = = PROCESS_MODE_INHERIT , false ) ;
2021-02-18 18:52:29 +00:00
if ( process_mode = = PROCESS_MODE_DISABLED ) {
return false ;
} else if ( process_mode = = PROCESS_MODE_ALWAYS ) {
return true ;
}
if ( p_paused ) {
return process_mode = = PROCESS_MODE_WHEN_PAUSED ;
} else {
return process_mode = = PROCESS_MODE_PAUSABLE ;
}
2014-02-10 01:10:30 +00:00
}
2021-06-18 01:09:40 +00:00
bool Node : : _is_enabled ( ) const {
ProcessMode process_mode ;
if ( data . process_mode = = PROCESS_MODE_INHERIT ) {
if ( ! data . process_owner ) {
process_mode = PROCESS_MODE_PAUSABLE ;
} else {
process_mode = data . process_owner - > data . process_mode ;
}
} else {
process_mode = data . process_mode ;
}
return ( process_mode ! = PROCESS_MODE_DISABLED ) ;
}
bool Node : : is_enabled ( ) const {
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , false ) ;
return _is_enabled ( ) ;
}
2021-02-02 02:16:37 +00:00
double Node : : get_physics_process_delta_time ( ) const {
2020-05-14 14:41:43 +00:00
if ( data . tree ) {
2017-09-30 14:19:07 +00:00
return data . tree - > get_physics_process_time ( ) ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
return 0 ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2021-02-02 02:16:37 +00:00
double Node : : get_process_delta_time ( ) const {
2020-05-14 14:41:43 +00:00
if ( data . tree ) {
2020-12-22 09:50:29 +00:00
return data . tree - > get_process_time ( ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-01-10 21:02:19 +00:00
return 0 ;
2020-05-14 14:41:43 +00:00
}
2017-01-10 21:02:19 +00:00
}
2020-12-22 09:50:29 +00:00
void Node : : set_process ( bool p_process ) {
if ( data . process = = p_process ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-12-22 09:50:29 +00:00
data . process = p_process ;
2014-02-10 01:10:30 +00:00
2020-12-22 09:50:29 +00:00
if ( data . process ) {
2022-07-01 18:16:05 +00:00
add_to_group ( SNAME ( " _process " ) , false ) ;
2020-05-14 14:41:43 +00:00
} else {
2022-07-01 18:16:05 +00:00
remove_from_group ( SNAME ( " _process " ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-01-10 21:02:19 +00:00
bool Node : : is_processing ( ) const {
2020-12-22 09:50:29 +00:00
return data . process ;
2014-02-10 01:10:30 +00:00
}
2020-12-22 09:50:29 +00:00
void Node : : set_process_internal ( bool p_process_internal ) {
if ( data . process_internal = = p_process_internal ) {
2017-01-10 21:02:19 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-01-10 21:02:19 +00:00
2020-12-22 09:50:29 +00:00
data . process_internal = p_process_internal ;
2017-01-10 21:02:19 +00:00
2020-12-22 09:50:29 +00:00
if ( data . process_internal ) {
2022-07-01 18:16:05 +00:00
add_to_group ( SNAME ( " _process_internal " ) , false ) ;
2020-05-14 14:41:43 +00:00
} else {
2022-07-01 18:16:05 +00:00
remove_from_group ( SNAME ( " _process_internal " ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-01-10 21:02:19 +00:00
bool Node : : is_processing_internal ( ) const {
2020-12-22 09:50:29 +00:00
return data . 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.
2020-04-01 23:20:12 +00:00
if ( data . tree = = nullptr ) {
2019-11-21 16:26:28 +00:00
return ;
}
2019-06-22 12:52:51 +00:00
2019-11-21 16:26:28 +00:00
if ( is_processing ( ) ) {
2022-07-01 18:16:05 +00:00
data . tree - > make_group_changed ( SNAME ( " _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 ( ) ) {
2022-07-01 18:16:05 +00:00
data . tree - > make_group_changed ( SNAME ( " _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 ( ) ) {
2022-07-01 18:16:05 +00:00
data . tree - > make_group_changed ( SNAME ( " _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 ( ) ) {
2022-07-01 18:16:05 +00:00
data . tree - > make_group_changed ( SNAME ( " _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 ) {
2020-05-14 14:41:43 +00:00
if ( p_enable = = data . input ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-04-10 03:18:27 +00:00
2017-03-05 15:44:50 +00:00
data . input = p_enable ;
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2014-04-10 03:18:27 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-04-10 03:18:27 +00:00
2020-05-14 14:41:43 +00:00
if ( p_enable ) {
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
bool Node : : is_processing_input ( ) const {
return data . input ;
}
2022-01-11 13:59:52 +00:00
void Node : : set_process_shortcut_input ( bool p_enable ) {
if ( p_enable = = data . shortcut_input ) {
return ;
}
data . shortcut_input = p_enable ;
if ( ! is_inside_tree ( ) ) {
return ;
}
if ( p_enable ) {
add_to_group ( " _vp_shortcut_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
} else {
remove_from_group ( " _vp_shortcut_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
}
}
bool Node : : is_processing_shortcut_input ( ) const {
return data . shortcut_input ;
}
2014-02-10 01:10:30 +00:00
void Node : : set_process_unhandled_input ( bool p_enable ) {
2020-05-14 14:41:43 +00:00
if ( p_enable = = data . unhandled_input ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
data . unhandled_input = p_enable ;
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2014-04-10 03:18:27 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +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 ( ) ) ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +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 ) {
2020-05-14 14:41:43 +00:00
if ( p_enable = = data . unhandled_key_input ) {
2014-04-10 03:18:27 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
data . unhandled_key_input = p_enable ;
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2014-04-10 03:18:27 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-04-10 03:18:27 +00:00
2020-05-14 14:41:43 +00:00
if ( p_enable ) {
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
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 {
return data . name ;
}
2017-03-05 15:44:50 +00:00
void Node : : _set_name_nocheck ( const StringName & p_name ) {
data . name = p_name ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : set_name ( const String & p_name ) {
2021-01-28 20:48:12 +00:00
String name = p_name . validate_node_name ( ) ;
2014-02-10 01:10:30 +00:00
2021-12-09 09:42:46 +00:00
ERR_FAIL_COND ( name . is_empty ( ) ) ;
2022-04-16 10:23:32 +00:00
if ( data . unique_name_in_owner & & data . owner ) {
_release_unique_name_in_owner ( ) ;
}
2017-03-05 15:44:50 +00:00
data . name = name ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( data . parent ) {
2021-11-15 01:05:44 +00:00
data . parent - > _validate_child_name ( this , true ) ;
2014-02-10 01:10:30 +00:00
}
2022-04-16 10:23:32 +00:00
if ( data . unique_name_in_owner & & data . owner ) {
_acquire_unique_name_in_owner ( ) ;
}
2021-09-03 22:12:37 +00:00
propagate_notification ( NOTIFICATION_PATH_RENAMED ) ;
2016-08-14 21:49:50 +00:00
2014-11-06 00:20:42 +00:00
if ( is_inside_tree ( ) ) {
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " 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
}
}
2014-02-22 23:28:19 +00:00
static SafeRefCount node_hrcr_count ;
void Node : : init_node_hrcr ( ) {
node_hrcr_count . init ( 1 ) ;
}
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 ) {
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 */
2021-10-21 14:46:07 +00:00
if ( p_force_human_readable ) {
2014-02-22 23:28:19 +00:00
//this approach to autoset node names is human readable but very slow
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
2020-07-26 13:29:50 +00:00
if ( p_child - > data . name = = StringName ( ) ) {
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 + + ) {
2020-05-14 14:41:43 +00:00
if ( children [ i ] = = p_child ) {
2014-02-26 13:08:17 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
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 ) {
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 ;
}
2020-07-27 10:43:20 +00:00
char32_t n = s [ i ] ;
2019-01-10 21:52:47 +00:00
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 ( ) ) {
2021-03-12 13:35:16 +00:00
//no name and a new name 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.
2021-02-17 16:44:49 +00:00
switch ( ProjectSettings : : get_singleton ( ) - > get ( " editor/node_naming/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 + + ) {
2021-03-12 13:35:16 +00:00
if ( children_ptr [ i ] = = p_child ) { //exclude self in renaming if it's already a child
2019-01-10 21:52:47 +00:00
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 - - ) {
2020-07-27 10:43:20 +00:00
char32_t n = name_string [ i ] ;
2022-02-04 08:32:20 +00:00
if ( is_digit ( n ) ) {
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 ;
2021-08-25 13:49:30 +00:00
if ( data . internal_children_back > 0 ) {
_move_child ( p_child , data . children . size ( ) - data . internal_children_back - 1 ) ;
}
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 ) ;
}
2021-08-25 13:49:30 +00:00
void Node : : add_child ( Node * p_child , bool p_legible_unique_name , InternalMode p_internal ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL_NULL ( p_child ) ;
2021-05-23 14:42:47 +00:00
ERR_FAIL_COND_MSG ( p_child = = this , vformat ( " Can't add child '%s' to itself. " , p_child - > get_name ( ) ) ) ; // adding to itself!
ERR_FAIL_COND_MSG ( p_child - > data . parent , vformat ( " Can't add child '%s' to '%s', already has a parent '%s'. " , p_child - > get_name ( ) , get_name ( ) , p_child - > data . parent - > get_name ( ) ) ) ; //Fail if node has a parent
# ifdef DEBUG_ENABLED
2021-06-18 22:02:50 +00:00
ERR_FAIL_COND_MSG ( p_child - > is_ancestor_of ( this ) , vformat ( " Can't add child '%s' to '%s' as it would result in a cyclic dependency since '%s' is already a parent of '%s'. " , p_child - > get_name ( ) , get_name ( ) , p_child - > get_name ( ) , get_name ( ) ) ) ;
2021-05-23 14:42:47 +00:00
# endif
2019-08-08 20:11:48 +00:00
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
2017-03-05 15:44:50 +00:00
_validate_child_name ( p_child , p_legible_unique_name ) ;
_add_child_nocheck ( p_child , p_child - > data . name ) ;
2021-08-25 13:49:30 +00:00
if ( p_internal = = INTERNAL_MODE_FRONT ) {
_move_child ( p_child , data . internal_children_front ) ;
data . internal_children_front + + ;
} else if ( p_internal = = INTERNAL_MODE_BACK ) {
if ( data . internal_children_back > 0 ) {
_move_child ( p_child , data . children . size ( ) - 1 , true ) ;
}
data . internal_children_back + + ;
}
2014-02-10 01:10:30 +00:00
}
2020-05-12 06:12:08 +00:00
void Node : : add_sibling ( Node * p_sibling , bool p_legible_unique_name ) {
ERR_FAIL_NULL ( p_sibling ) ;
2021-08-25 13:49:30 +00:00
ERR_FAIL_NULL ( data . parent ) ;
2021-05-23 14:42:47 +00:00
ERR_FAIL_COND_MSG ( p_sibling = = this , vformat ( " Can't add sibling '%s' to itself. " , p_sibling - > get_name ( ) ) ) ; // adding to itself!
2020-05-12 06:12:08 +00:00
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, add_sibling() failed. Consider using call_deferred( \" add_sibling \" , sibling) instead. " ) ;
2016-05-13 16:09:49 +00:00
2021-08-25 13:49:30 +00:00
InternalMode internal = INTERNAL_MODE_DISABLED ;
if ( _is_internal_front ( ) ) { // The sibling will have the same internal status.
internal = INTERNAL_MODE_FRONT ;
} else if ( _is_internal_back ( ) ) {
internal = INTERNAL_MODE_BACK ;
}
data . parent - > add_child ( p_sibling , p_legible_unique_name , internal ) ;
data . parent - > _move_child ( p_sibling , get_index ( ) + 1 ) ;
2016-05-13 16:09:49 +00:00
}
2014-02-10 01:10:30 +00:00
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 + + ) {
if ( children [ i ] = = p_child ) {
idx = i ;
break ;
}
2014-02-10 01:10:30 +00:00
}
}
2016-03-08 23:00:52 +00:00
2021-05-23 14:42:47 +00:00
ERR_FAIL_COND_MSG ( idx = = - 1 , vformat ( " Cannot remove child node '%s' as it is not a child of this node. " , p_child - > get_name ( ) ) ) ;
2015-12-29 19:06:45 +00:00
//ERR_FAIL_COND( p_child->data.blocked > 0 );
2014-02-10 01:10:30 +00:00
2021-08-25 13:49:30 +00:00
// If internal child, update the counter.
if ( p_child - > _is_internal_front ( ) ) {
data . internal_children_front - - ;
} else if ( p_child - > _is_internal_back ( ) ) {
data . internal_children_back - - ;
}
2016-03-08 23:00:52 +00:00
2020-04-01 23:20:12 +00:00
p_child - > _set_tree ( nullptr ) ;
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
2021-07-03 22:17:03 +00:00
data . children . remove_at ( 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
2020-04-01 23:20:12 +00:00
p_child - > data . parent = nullptr ;
2017-03-05 15:44:50 +00:00
p_child - > data . pos = - 1 ;
2014-02-10 01:10:30 +00:00
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
}
2021-08-25 13:49:30 +00:00
int Node : : get_child_count ( bool p_include_internal ) const {
if ( p_include_internal ) {
return data . children . size ( ) ;
} else {
return data . children . size ( ) - data . internal_children_front - data . internal_children_back ;
}
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2021-08-25 13:49:30 +00:00
Node * Node : : get_child ( int p_index , bool p_include_internal ) const {
if ( p_include_internal ) {
if ( p_index < 0 ) {
p_index + = data . children . size ( ) ;
}
ERR_FAIL_INDEX_V ( p_index , data . children . size ( ) , nullptr ) ;
return data . children [ p_index ] ;
} else {
if ( p_index < 0 ) {
p_index + = data . children . size ( ) - data . internal_children_front - data . internal_children_back ;
}
ERR_FAIL_INDEX_V ( p_index , data . children . size ( ) - data . internal_children_front - data . internal_children_back , nullptr ) ;
p_index + = data . internal_children_front ;
return data . children [ p_index ] ;
2020-08-25 12:46:33 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Node * Node : : _get_child_by_name ( const StringName & p_name ) const {
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 + + ) {
2020-05-14 14:41:43 +00:00
if ( cd [ i ] - > data . name = = p_name ) {
2015-10-10 12:09:09 +00:00
return cd [ i ] ;
2020-05-14 14:41:43 +00:00
}
2015-10-10 12:09:09 +00:00
}
2020-04-01 23:20:12 +00:00
return nullptr ;
2015-10-10 12:09:09 +00:00
}
2019-01-29 16:15:34 +00:00
Node * Node : : get_node_or_null ( const NodePath & p_path ) const {
2019-03-08 20:19:56 +00:00
if ( p_path . is_empty ( ) ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2019-03-08 20:19:56 +00:00
}
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V_MSG ( ! data . inside_tree & & p_path . is_absolute ( ) , nullptr , " Can't use get_node() with absolute paths from outside the active scene tree. " ) ;
2016-03-08 23:00:52 +00:00
2020-04-01 23:20:12 +00:00
Node * current = nullptr ;
Node * root = nullptr ;
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 ) ;
2020-05-14 14:41:43 +00:00
while ( root - > data . parent ) {
2017-03-05 15:44:50 +00:00
root = root - > data . parent ; //start from root
2020-05-14 14:41:43 +00:00
}
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 ) ;
2020-04-01 23:20:12 +00:00
Node * next = nullptr ;
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
2020-05-14 14:41:43 +00:00
if ( current = = nullptr | | ! current - > data . parent ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
next = current - > data . parent ;
2020-04-01 23:20:12 +00:00
} else if ( current = = nullptr ) {
2020-05-14 14:41:43 +00:00
if ( name = = root - > get_name ( ) ) {
2017-03-05 15:44:50 +00:00
next = root ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2022-04-16 10:23:32 +00:00
} else if ( name . is_node_unique_name ( ) ) {
if ( current - > data . owned_unique_nodes . size ( ) ) {
// Has unique nodes in ownership
Node * * unique = current - > data . owned_unique_nodes . getptr ( name ) ;
if ( ! unique ) {
return nullptr ;
}
next = * unique ;
} else if ( current - > data . owner ) {
Node * * unique = current - > data . owner - > data . owned_unique_nodes . getptr ( name ) ;
if ( ! unique ) {
return nullptr ;
}
next = * unique ;
} else {
return nullptr ;
}
2014-02-10 01:10:30 +00:00
} else {
2020-04-01 23:20:12 +00:00
next = nullptr ;
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 + + ) {
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 ) {
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
}
2020-04-01 23:20:12 +00:00
if ( next = = nullptr ) {
return nullptr ;
2014-02-10 01:10:30 +00:00
} ;
}
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 {
2019-01-29 16:15:34 +00:00
Node * node = get_node_or_null ( p_path ) ;
2021-02-20 01:05:19 +00:00
2022-01-19 10:33:27 +00:00
if ( unlikely ( ! node ) ) {
if ( p_path . is_absolute ( ) ) {
ERR_FAIL_V_MSG ( nullptr ,
vformat ( R " (Node not found: " % s " (absolute path attempted from " % s " ).) " , p_path , get_path ( ) ) ) ;
} else {
ERR_FAIL_V_MSG ( nullptr ,
vformat ( R " (Node not found: " % s " (relative to " % s " ).) " , p_path , get_path ( ) ) ) ;
}
2021-02-20 01:05:19 +00:00
}
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 {
2020-04-01 23:20:12 +00:00
return get_node_or_null ( p_path ) ! = nullptr ;
2014-02-10 01:10:30 +00:00
}
2022-04-25 13:16:44 +00:00
// Finds the first child node (in tree order) whose name matches the given pattern.
// Can be recursive or not, and limited to owned nodes.
Node * Node : : find_child ( const String & p_pattern , bool p_recursive , bool p_owned ) const {
ERR_FAIL_COND_V ( p_pattern . is_empty ( ) , nullptr ) ;
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_pattern ) ) {
return cptr [ i ] ;
}
if ( ! p_recursive ) {
continue ;
}
Node * ret = cptr [ i ] - > find_child ( p_pattern , true , p_owned ) ;
if ( ret ) {
return ret ;
}
}
return nullptr ;
}
// Finds child nodes based on their name using pattern matching, or class name,
// or both (either pattern or type can be left empty).
// Can be recursive or not, and limited to owned nodes.
TypedArray < Node > Node : : find_children ( const String & p_pattern , const String & p_type , bool p_recursive , bool p_owned ) const {
2021-12-17 18:04:35 +00:00
TypedArray < Node > ret ;
2022-04-25 13:16:44 +00:00
ERR_FAIL_COND_V ( p_pattern . is_empty ( ) & & p_type . is_empty ( ) , ret ) ;
2021-12-17 18:04:35 +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 + + ) {
2020-05-14 14:41:43 +00:00
if ( p_owned & & ! cptr [ i ] - > data . owner ) {
2015-06-08 03:33:10 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2021-12-17 18:04:35 +00:00
2022-04-25 13:16:44 +00:00
if ( ! p_pattern . is_empty ( ) ) {
if ( ! cptr [ i ] - > data . name . operator String ( ) . match ( p_pattern ) ) {
2021-12-17 18:04:35 +00:00
continue ;
} else if ( p_type . is_empty ( ) ) {
ret . append ( cptr [ i ] ) ;
}
2020-05-14 14:41:43 +00:00
}
2015-06-08 03:33:10 +00:00
2021-12-17 18:04:35 +00:00
if ( cptr [ i ] - > is_class ( p_type ) ) {
ret . append ( cptr [ i ] ) ;
} else if ( cptr [ i ] - > get_script_instance ( ) ) {
Ref < Script > script = cptr [ i ] - > get_script_instance ( ) - > get_script ( ) ;
while ( script . is_valid ( ) ) {
if ( ( ScriptServer : : is_global_class ( p_type ) & & ScriptServer : : get_global_class_path ( p_type ) = = script - > get_path ( ) ) | | p_type = = script - > get_path ( ) ) {
ret . append ( cptr [ i ] ) ;
break ;
}
script = script - > get_base_script ( ) ;
}
2020-05-14 14:41:43 +00:00
}
2015-06-08 03:33:10 +00:00
2021-12-17 18:04:35 +00:00
if ( p_recursive ) {
2022-04-25 13:16:44 +00:00
ret . append_array ( cptr [ i ] - > find_children ( p_pattern , p_type , true , p_owned ) ) ;
2020-05-14 14:41:43 +00:00
}
2015-06-08 03:33:10 +00:00
}
2021-12-17 18:04:35 +00:00
return ret ;
2015-06-08 03:33:10 +00:00
}
2014-02-10 01:10:30 +00:00
Node * Node : : get_parent ( ) const {
return data . parent ;
}
2022-04-25 13:16:44 +00:00
Node * Node : : find_parent ( const String & p_pattern ) const {
2018-09-15 16:22:06 +00:00
Node * p = data . parent ;
while ( p ) {
2022-04-25 13:16:44 +00:00
if ( p - > data . name . operator String ( ) . match ( p_pattern ) ) {
2018-09-15 16:22:06 +00:00
return p ;
2020-05-14 14:41:43 +00:00
}
2018-09-15 16:22:06 +00:00
p = p - > data . parent ;
}
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-09-15 16:22:06 +00:00
}
2021-06-18 22:02:50 +00:00
bool Node : : is_ancestor_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 ) {
2020-05-14 14:41:43 +00:00
if ( p = = this ) {
2014-02-10 01:10:30 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
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 ) {
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 ) {
2020-05-14 14:41:43 +00:00
if ( data . owner = = p_by ) {
2014-02-10 01:10:30 +00:00
p_owned - > push_back ( this ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2017-03-05 15:44:50 +00:00
get_child ( i ) - > get_owned_by ( p_by , p_owned ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : _set_owner_nocheck ( Node * p_owner ) {
2020-05-14 14:41:43 +00:00
if ( data . owner = = p_owner ) {
2017-03-15 11:28:57 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-03-15 11:28:57 +00:00
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 ( ) ;
2022-06-23 06:19:18 +00:00
owner_changed_notify ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-04-16 10:23:32 +00:00
void Node : : _release_unique_name_in_owner ( ) {
ERR_FAIL_NULL ( data . owner ) ; // Sanity check.
StringName key = StringName ( UNIQUE_NODE_PREFIX + data . name . operator String ( ) ) ;
Node * * which = data . owner - > data . owned_unique_nodes . getptr ( key ) ;
if ( which = = nullptr | | * which ! = this ) {
return ; // Ignore.
}
data . owner - > data . owned_unique_nodes . erase ( key ) ;
}
void Node : : _acquire_unique_name_in_owner ( ) {
ERR_FAIL_NULL ( data . owner ) ; // Sanity check.
StringName key = StringName ( UNIQUE_NODE_PREFIX + data . name . operator String ( ) ) ;
Node * * which = data . owner - > data . owned_unique_nodes . getptr ( key ) ;
if ( which ! = nullptr & & * which ! = this ) {
2022-04-25 13:16:44 +00:00
String which_path = is_inside_tree ( ) ? ( * which ) - > get_path ( ) : data . owner - > get_path_to ( * which ) ;
WARN_PRINT ( vformat ( RTR ( " Setting node name '%s' to be unique within scene for '%s', but it's already claimed by '%s'. \n '%s' is no longer set as having a unique name. " ) ,
get_name ( ) , is_inside_tree ( ) ? get_path ( ) : data . owner - > get_path_to ( this ) , which_path , which_path ) ) ;
2022-04-16 10:23:32 +00:00
data . unique_name_in_owner = false ;
return ;
}
data . owner - > data . owned_unique_nodes [ key ] = this ;
}
void Node : : set_unique_name_in_owner ( bool p_enabled ) {
if ( data . unique_name_in_owner = = p_enabled ) {
return ;
}
if ( data . unique_name_in_owner & & data . owner ! = nullptr ) {
_release_unique_name_in_owner ( ) ;
}
data . unique_name_in_owner = p_enabled ;
if ( data . unique_name_in_owner & & data . owner ! = nullptr ) {
_acquire_unique_name_in_owner ( ) ;
}
update_configuration_warnings ( ) ;
}
bool Node : : is_unique_name_in_owner ( ) const {
return data . unique_name_in_owner ;
}
2014-02-10 01:10:30 +00:00
void Node : : set_owner ( Node * p_owner ) {
if ( data . owner ) {
2022-04-16 10:23:32 +00:00
if ( data . unique_name_in_owner ) {
_release_unique_name_in_owner ( ) ;
}
2017-03-05 15:44:50 +00:00
data . owner - > data . owned . erase ( data . OW ) ;
2020-04-01 23:20:12 +00:00
data . OW = nullptr ;
data . owner = nullptr ;
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
2020-05-14 14:41:43 +00:00
if ( ! p_owner ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
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 ) {
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 ) ;
2022-04-16 10:23:32 +00:00
if ( data . unique_name_in_owner ) {
_acquire_unique_name_in_owner ( ) ;
}
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
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 {
2020-05-14 14:41:43 +00:00
if ( this = = p_node ) {
2017-03-05 15:44:50 +00:00
return const_cast < Node * > ( p_node ) ;
2020-05-14 14:41:43 +00:00
}
2016-07-19 23:04:06 +00:00
2022-05-19 15:00:06 +00:00
HashSet < 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 ) {
2020-05-14 14:41:43 +00:00
if ( visited . has ( common_parent ) ) {
2016-07-19 23:04:06 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
common_parent = common_parent - > data . parent ;
2016-07-19 23:04:06 +00:00
}
2020-05-14 14:41:43 +00:00
if ( ! common_parent ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2016-07-19 23:04:06 +00:00
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
2020-05-14 14:41:43 +00:00
if ( this = = p_node ) {
2014-02-10 01:10:30 +00:00
return NodePath ( " . " ) ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2022-05-19 15:00:06 +00:00
HashSet < 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 ) {
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 ) {
2020-05-14 14:41:43 +00:00
if ( visited . has ( common_parent ) ) {
2014-02-10 01:10:30 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
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 ) {
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 ) {
path . push_back ( up ) ;
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2021-03-14 07:21:32 +00:00
path . reverse ( ) ;
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 {
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
2020-05-14 14:41:43 +00:00
if ( data . path_cache ) {
2016-08-14 21:49:50 +00:00
return * data . path_cache ;
2020-05-14 14:41:43 +00:00
}
2016-08-14 21:49:50 +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
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
}
2021-03-14 07:21:32 +00:00
path . reverse ( ) ;
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 ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! p_identifier . operator String ( ) . length ( ) ) ;
2016-03-08 23:00:52 +00:00
2020-05-14 14:41:43 +00:00
if ( data . grouped . has ( p_identifier ) ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
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 {
2020-04-01 23:20:12 +00:00
gd . group = nullptr ;
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 ) {
ERR_FAIL_COND ( ! data . grouped . has ( p_identifier ) ) ;
2016-03-08 23:00:52 +00:00
2022-05-13 13:04:37 +00:00
HashMap < StringName , GroupData > : : Iterator 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
2020-05-14 14:41:43 +00:00
if ( data . tree ) {
2022-05-13 13:04:37 +00:00
data . tree - > remove_from_group ( E - > key , this ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2022-05-13 13:04:37 +00:00
data . grouped . remove ( 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 ) ;
2021-07-24 13:46:25 +00:00
for ( const GroupInfo & E : gi ) {
2021-07-16 03:45:57 +00:00
groups . push_back ( E . name ) ;
2014-06-16 13:22:26 +00:00
}
return groups ;
}
2014-02-10 01:10:30 +00:00
void Node : : get_groups ( List < GroupInfo > * p_groups ) const {
2021-08-09 20:13:42 +00:00
for ( const KeyValue < StringName , GroupData > & E : data . grouped ) {
2014-02-10 01:10:30 +00:00
GroupInfo gi ;
2021-08-09 20:13:42 +00:00
gi . name = E . key ;
gi . persistent = E . value . 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
2021-08-09 20:13:42 +00:00
for ( const KeyValue < StringName , GroupData > & E : data . grouped ) {
if ( E . value . persistent ) {
2019-08-16 20:30:31 +00:00
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
}
2020-05-14 12:29:06 +00:00
2019-07-10 09:54:12 +00:00
void Node : : _print_tree_pretty ( const String & prefix , const bool last ) {
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 ) ) ) ;
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2018-02-28 09:12:06 +00:00
data . children [ i ] - > _print_tree ( p_node ) ;
2020-05-14 14:41:43 +00:00
}
2018-02-28 09:12:06 +00:00
}
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 + + ;
2020-05-14 14:41:43 +00:00
if ( ! p_reverse ) {
2017-03-05 15:44:50 +00:00
MessageQueue : : get_singleton ( ) - > push_notification ( this , p_notification ) ;
2020-05-14 14:41:43 +00:00
}
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 + + ) {
data . children [ i ] - > _propagate_deferred_notification ( p_notification , p_reverse ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 14:41:43 +00:00
if ( p_reverse ) {
2017-03-05 15:44:50 +00:00
MessageQueue : : get_singleton ( ) - > push_notification ( this , p_notification ) ;
2020-05-14 14:41:43 +00:00
}
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 + + ;
2020-05-14 14:41:43 +00:00
if ( p_parent_first & & has_method ( p_method ) ) {
2017-08-19 13:17:06 +00:00
callv ( p_method , p_args ) ;
2020-05-14 14:41:43 +00:00
}
2017-08-19 13:17:06 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > propagate_call ( p_method , p_args , p_parent_first ) ;
}
2020-05-14 14:41:43 +00:00
if ( ! p_parent_first & & has_method ( p_method ) ) {
2017-08-19 13:17:06 +00:00
callv ( p_method , p_args ) ;
2020-05-14 14:41:43 +00:00
}
2017-08-19 13:17:06 +00:00
data . blocked - - ;
}
2017-03-05 15:44:50 +00:00
void Node : : _propagate_replace_owner ( Node * p_owner , Node * p_by_owner ) {
2020-05-14 14:41:43 +00:00
if ( get_owner ( ) = = p_owner ) {
2014-02-10 01:10:30 +00:00
set_owner ( p_by_owner ) ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . blocked + + ;
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2017-03-05 15:44:50 +00:00
data . children [ i ] - > _propagate_replace_owner ( p_owner , p_by_owner ) ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
data . blocked - - ;
2014-02-10 01:10:30 +00:00
}
2021-08-25 13:49:30 +00:00
int Node : : get_index ( bool p_include_internal ) const {
// p_include_internal = false doesn't make sense if the node is internal.
ERR_FAIL_COND_V_MSG ( ! p_include_internal & & ( _is_internal_front ( ) | | _is_internal_back ( ) ) , - 1 , " Node is internal. Can't get index with 'include_internal' being false. " ) ;
if ( data . parent & & ! p_include_internal ) {
return data . pos - data . parent - > data . internal_children_front ;
}
2014-02-10 01:10:30 +00:00
return data . pos ;
}
2020-04-05 23:06:10 +00:00
2020-09-05 01:05:30 +00:00
Ref < Tween > Node : : create_tween ( ) {
ERR_FAIL_COND_V_MSG ( ! data . tree , nullptr , " Can't create Tween when not inside scene tree. " ) ;
Ref < Tween > tween = get_tree ( ) - > create_tween ( ) ;
tween - > bind_node ( this ) ;
return tween ;
}
2014-02-10 01:10:30 +00:00
void Node : : remove_and_skip ( ) {
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 ) {
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 ] ;
2020-05-14 14:41:43 +00:00
if ( ! c_node - > get_owner ( ) ) {
2014-02-10 01:10:30 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-12 17:50:43 +00:00
remove_child ( c_node ) ;
2020-04-01 23:20:12 +00:00
c_node - > _propagate_replace_owner ( this , nullptr ) ;
2017-03-12 17:50:43 +00:00
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
2020-05-14 14:41:43 +00:00
if ( clear ) {
2014-02-10 01:10:30 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2020-12-15 12:04:21 +00:00
while ( ! children . is_empty ( ) ) {
2017-03-12 17:50:43 +00:00
Node * c_node = children . front ( ) - > get ( ) ;
data . parent - > add_child ( c_node ) ;
2020-04-01 23:20:12 +00:00
c_node - > _propagate_replace_owner ( nullptr , 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 ) ;
}
2021-09-30 14:30:55 +00:00
void Node : : set_scene_file_path ( const String & p_scene_file_path ) {
data . scene_file_path = p_scene_file_path ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2021-09-30 14:30:55 +00:00
String Node : : get_scene_file_path ( ) const {
return data . scene_file_path ;
2014-02-10 01:10:30 +00:00
}
2019-08-15 12:50:26 +00:00
void Node : : set_editor_description ( const String & p_editor_description ) {
2021-02-18 18:52:29 +00:00
data . editor_description = p_editor_description ;
2019-08-15 12:50:26 +00:00
}
2020-05-14 12:29:06 +00:00
2019-08-15 12:50:26 +00:00
String Node : : get_editor_description ( ) const {
2021-02-18 18:52:29 +00:00
return data . editor_description ;
2019-08-15 12:50:26 +00:00
}
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 ) ;
2021-06-18 22:02:50 +00:00
ERR_FAIL_COND ( ! is_ancestor_of ( p_node ) ) ;
2017-04-07 13:48:07 +00:00
if ( ! p_editable ) {
2021-01-17 22:37:40 +00:00
p_node - > data . editable_instance = false ;
2017-04-07 13:48:07 +00:00
// Avoid this flag being needlessly saved;
2021-03-12 13:35:16 +00:00
// also give more visual feedback if editable children are re-enabled
2017-04-07 13:48:07 +00:00
set_display_folded ( false ) ;
} else {
2021-01-17 22:37:40 +00:00
p_node - > data . editable_instance = 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 {
2020-05-14 14:41:43 +00:00
if ( ! p_node ) {
2021-01-17 22:37:40 +00:00
return false ; // Easier, null is never editable. :)
2020-05-14 14:41:43 +00:00
}
2021-06-18 22:02:50 +00:00
ERR_FAIL_COND_V ( ! is_ancestor_of ( p_node ) , false ) ;
2021-01-17 22:37:40 +00:00
return p_node - > data . editable_instance ;
2016-04-12 16:21:37 +00:00
}
2021-02-21 08:19:48 +00:00
Node * Node : : get_deepest_editable_node ( Node * p_start_node ) const {
ERR_FAIL_NULL_V ( p_start_node , nullptr ) ;
2021-06-18 22:02:50 +00:00
ERR_FAIL_COND_V ( ! is_ancestor_of ( p_start_node ) , p_start_node ) ;
2021-02-21 08:19:48 +00:00
Node const * iterated_item = p_start_node ;
Node * node = p_start_node ;
while ( iterated_item - > get_owner ( ) & & iterated_item - > get_owner ( ) ! = this ) {
2021-04-05 12:09:59 +00:00
if ( ! is_editable_instance ( iterated_item - > get_owner ( ) ) ) {
2021-02-21 08:19:48 +00:00
node = iterated_item - > get_owner ( ) ;
2021-04-05 12:09:59 +00:00
}
2021-02-21 08:19:48 +00:00
iterated_item = iterated_item - > get_owner ( ) ;
}
return node ;
}
2021-10-26 19:12:25 +00:00
# ifdef TOOLS_ENABLED
void Node : : set_property_pinned ( const String & p_property , bool p_pinned ) {
bool current_pinned = false ;
2022-04-01 18:30:23 +00:00
Array pinned = get_meta ( " _edit_pinned_properties_ " , Array ( ) ) ;
StringName psa = get_property_store_alias ( p_property ) ;
current_pinned = pinned . has ( psa ) ;
2021-10-26 19:12:25 +00:00
if ( current_pinned ! = p_pinned ) {
if ( p_pinned ) {
pinned . append ( psa ) ;
} else {
pinned . erase ( psa ) ;
}
}
2022-04-01 18:30:23 +00:00
if ( pinned . is_empty ( ) ) {
remove_meta ( " _edit_pinned_properties_ " ) ;
} else {
set_meta ( " _edit_pinned_properties_ " , pinned ) ;
}
2021-10-26 19:12:25 +00:00
}
bool Node : : is_property_pinned ( const StringName & p_property ) const {
2022-04-01 18:30:23 +00:00
Array pinned = get_meta ( " _edit_pinned_properties_ " , Array ( ) ) ;
StringName psa = get_property_store_alias ( p_property ) ;
2021-10-26 19:12:25 +00:00
return pinned . has ( psa ) ;
}
StringName Node : : get_property_store_alias ( const StringName & p_property ) const {
return p_property ;
}
# endif
2022-05-19 15:00:06 +00:00
void Node : : get_storable_properties ( HashSet < StringName > & r_storable_properties ) const {
2021-10-26 19:12:25 +00:00
List < PropertyInfo > pi ;
get_property_list ( & pi ) ;
for ( List < PropertyInfo > : : Element * E = pi . front ( ) ; E ; E = E - > next ( ) ) {
if ( ( E - > get ( ) . usage & PROPERTY_USAGE_STORAGE ) ) {
r_storable_properties . insert ( E - > get ( ) . name ) ;
}
}
}
2021-07-11 14:40:18 +00:00
String Node : : to_string ( ) {
if ( get_script_instance ( ) ) {
bool valid ;
String ret = get_script_instance ( ) - > to_string ( & valid ) ;
if ( valid ) {
return ret ;
}
}
return ( get_name ( ) ? String ( get_name ( ) ) + " : " : " " ) + Object : : to_string ( ) ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_scene_instance_state ( const Ref < SceneState > & p_state ) {
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 ) {
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 ) {
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
}
2022-05-13 13:04:37 +00:00
Node * Node : : _duplicate ( int p_flags , HashMap < const Node * , Node * > * r_duplimap ) const {
2020-04-01 23:20:12 +00:00
Node * node = nullptr ;
2014-02-10 01:10:30 +00:00
2021-06-17 22:03:09 +00:00
bool instantiated = false ;
2015-08-02 15:29:37 +00:00
2017-08-24 20:58:51 +00:00
if ( Object : : cast_to < InstancePlaceholder > ( this ) ) {
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
2021-12-09 09:42:46 +00:00
} else if ( ( p_flags & DUPLICATE_USE_INSTANCING ) & & ! get_scene_file_path ( ) . is_empty ( ) ) {
2021-09-30 14:30:55 +00:00
Ref < PackedScene > res = ResourceLoader : : load ( get_scene_file_path ( ) ) ;
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V ( res . is_null ( ) , nullptr ) ;
2017-11-19 13:32:10 +00:00
PackedScene : : GenEditState ges = PackedScene : : GEN_EDIT_STATE_DISABLED ;
# ifdef TOOLS_ENABLED
2020-05-14 14:41:43 +00:00
if ( p_flags & DUPLICATE_FROM_EDITOR ) {
2017-11-19 13:32:10 +00:00
ges = PackedScene : : GEN_EDIT_STATE_INSTANCE ;
2020-05-14 14:41:43 +00:00
}
2017-11-19 13:32:10 +00:00
# endif
2021-06-17 22:03:09 +00:00
node = res - > instantiate ( ges ) ;
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V ( ! node , nullptr ) ;
2022-01-16 07:08:03 +00:00
node - > set_scene_instance_load_placeholder ( get_scene_instance_load_placeholder ( ) ) ;
2015-08-02 15:29:37 +00:00
2021-06-17 22:03:09 +00:00
instantiated = true ;
2015-08-02 15:29:37 +00:00
} else {
2021-06-17 22:03:09 +00:00
Object * obj = ClassDB : : instantiate ( get_class ( ) ) ;
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V ( ! obj , nullptr ) ;
2017-08-24 20:58:51 +00:00
node = Object : : cast_to < Node > ( obj ) ;
2020-05-14 14:41:43 +00:00
if ( ! node ) {
2015-08-02 15:29:37 +00:00
memdelete ( obj ) ;
2020-05-14 14:41:43 +00:00
}
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V ( ! node , nullptr ) ;
2015-08-02 15:29:37 +00:00
}
2014-02-10 01:10:30 +00:00
2021-12-09 09:42:46 +00:00
if ( ! get_scene_file_path ( ) . is_empty ( ) ) { //an instance
2021-09-30 14:30:55 +00:00
node - > set_scene_file_path ( get_scene_file_path ( ) ) ;
2021-02-28 16:19:01 +00:00
node - > data . editable_instance = data . editable_instance ;
2017-10-13 22:03:33 +00:00
}
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 ) ;
2021-06-17 22:03:09 +00:00
if ( instantiated ) {
// Since nodes in the instantiated hierarchy won't be duplicated explicitly, we need to make an inventory
// of all the nodes in the tree of the instantiated scene in order to transfer the values of the properties
2017-11-25 20:13:52 +00:00
2021-02-22 15:50:44 +00:00
Vector < const Node * > instance_roots ;
instance_roots . push_back ( this ) ;
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-12-08 14:05:15 +00:00
Node * descendant = N - > get ( ) - > get_child ( i ) ;
2021-06-17 22:03:09 +00:00
// Skip nodes not really belonging to the instantiated hierarchy; they'll be processed normally later
// but remember non-instantiated nodes that are hidden below instantiated ones
2021-02-22 15:50:44 +00:00
if ( ! instance_roots . has ( descendant - > get_owner ( ) ) ) {
if ( descendant - > get_parent ( ) & & descendant - > get_parent ( ) ! = this & & descendant - > data . owner ! = descendant - > get_parent ( ) ) {
2017-12-08 14:05:15 +00:00
hidden_roots . push_back ( descendant ) ;
2020-05-14 14:41:43 +00:00
}
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 ) ;
2021-02-22 15:50:44 +00:00
2021-12-09 09:42:46 +00:00
if ( ! descendant - > get_scene_file_path ( ) . is_empty ( ) & & instance_roots . has ( descendant - > get_owner ( ) ) ) {
2021-02-22 15:50:44 +00:00
instance_roots . 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 ( ) ) {
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 ) ;
2021-07-24 13:46:25 +00:00
for ( const PropertyInfo & E : plist ) {
2021-07-16 03:45:57 +00:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2017-10-13 22:03:33 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2021-07-16 03:45:57 +00:00
String name = E . name ;
2020-05-14 14:41:43 +00:00
if ( name = = script_property_name ) {
2017-10-13 22:03:33 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2017-10-13 22:03:33 +00:00
2018-03-09 19:16:08 +00:00
Variant value = N - > get ( ) - > get ( name ) . duplicate ( true ) ;
2017-10-13 22:03:33 +00:00
2021-07-16 03:45:57 +00:00
if ( E . usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE ) {
2018-01-11 18:50:33 +00:00
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
2020-05-14 14:41:43 +00:00
if ( ( p_flags & DUPLICATE_FROM_EDITOR ) & & r_duplimap ) {
2017-11-19 13:32:10 +00:00
r_duplimap - > insert ( this , node ) ;
2020-05-14 14:41:43 +00:00
}
2017-11-19 13:32:10 +00:00
# endif
2017-02-20 19:05:01 +00:00
if ( p_flags & DUPLICATE_GROUPS ) {
List < GroupInfo > gi ;
get_groups ( & gi ) ;
2021-07-24 13:46:25 +00:00
for ( const GroupInfo & E : gi ) {
2017-11-19 13:32:10 +00:00
# ifdef TOOLS_ENABLED
2021-07-16 03:45:57 +00:00
if ( ( p_flags & DUPLICATE_FROM_EDITOR ) & & ! E . persistent ) {
2017-11-19 13:32:10 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2017-11-19 13:32:10 +00:00
# endif
2021-07-16 03:45:57 +00:00
node - > add_to_group ( E . name , E . persistent ) ;
2017-02-20 19:05:01 +00:00
}
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 + + ) {
2020-05-14 14:41:43 +00:00
if ( get_child ( i ) - > data . parent_owned ) {
2014-02-10 01:10:30 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2021-06-17 22:03:09 +00:00
if ( instantiated & & get_child ( i ) - > data . owner = = this ) {
2015-08-02 15:29:37 +00:00
continue ; //part of instance
2020-05-14 14:41:43 +00:00
}
2015-08-02 15:29:37 +00:00
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 ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2014-02-10 01:10:30 +00:00
}
node - > add_child ( dup ) ;
2017-12-08 14:05:15 +00:00
if ( i < node - > get_child_count ( ) - 1 ) {
node - > move_child ( dup , i ) ;
}
}
2021-07-16 03:45:57 +00:00
for ( const Node * & E : hidden_roots ) {
Node * parent = node - > get_node ( get_path_to ( E - > data . parent ) ) ;
2017-12-08 14:05:15 +00:00
if ( ! parent ) {
memdelete ( node ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2017-12-08 14:05:15 +00:00
}
2021-07-16 03:45:57 +00:00
Node * dup = E - > _duplicate ( p_flags , r_duplimap ) ;
2017-12-08 14:05:15 +00:00
if ( ! dup ) {
memdelete ( node ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2017-12-08 14:05:15 +00:00
}
parent - > add_child ( dup ) ;
2021-07-16 03:45:57 +00:00
int pos = E - > get_index ( ) ;
2017-12-08 14:05:15 +00:00
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
2022-05-13 13:04:37 +00:00
Node * Node : : duplicate_from_editor ( HashMap < const Node * , Node * > & r_duplimap ) const {
return duplicate_from_editor ( r_duplimap , HashMap < Ref < Resource > , Ref < Resource > > ( ) ) ;
2021-02-12 16:36:37 +00:00
}
2022-05-13 13:04:37 +00:00
Node * Node : : duplicate_from_editor ( HashMap < const Node * , Node * > & r_duplimap , const HashMap < Ref < Resource > , Ref < Resource > > & p_resource_remap ) const {
2017-11-19 13:32:10 +00:00
Node * dupe = _duplicate ( DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANCING | DUPLICATE_FROM_EDITOR , & r_duplimap ) ;
2021-02-12 16:36:37 +00:00
// This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated.
if ( ! p_resource_remap . is_empty ( ) ) {
remap_node_resources ( dupe , p_resource_remap ) ;
}
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
_duplicate_signals ( this , dupe ) ;
return dupe ;
}
2021-02-12 16:36:37 +00:00
2022-05-13 13:04:37 +00:00
void Node : : remap_node_resources ( Node * p_node , const HashMap < Ref < Resource > , Ref < Resource > > & p_resource_remap ) const {
2021-02-12 16:36:37 +00:00
List < PropertyInfo > props ;
p_node - > get_property_list ( & props ) ;
2021-07-24 13:46:25 +00:00
for ( const PropertyInfo & E : props ) {
2021-07-16 03:45:57 +00:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2021-02-12 16:36:37 +00:00
continue ;
}
2021-07-16 03:45:57 +00:00
Variant v = p_node - > get ( E . name ) ;
2021-08-26 19:37:17 +00:00
if ( v . is_ref_counted ( ) ) {
2022-05-02 23:43:50 +00:00
Ref < Resource > res = v ;
2021-02-12 16:36:37 +00:00
if ( res . is_valid ( ) ) {
if ( p_resource_remap . has ( res ) ) {
2021-07-16 03:45:57 +00:00
p_node - > set ( E . name , p_resource_remap [ res ] ) ;
2021-02-12 16:36:37 +00:00
remap_nested_resources ( res , p_resource_remap ) ;
}
}
}
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
remap_node_resources ( p_node - > get_child ( i ) , p_resource_remap ) ;
}
}
2022-05-13 13:04:37 +00:00
void Node : : remap_nested_resources ( Ref < Resource > p_resource , const HashMap < Ref < Resource > , Ref < Resource > > & p_resource_remap ) const {
2021-02-12 16:36:37 +00:00
List < PropertyInfo > props ;
p_resource - > get_property_list ( & props ) ;
2021-07-24 13:46:25 +00:00
for ( const PropertyInfo & E : props ) {
2021-07-16 03:45:57 +00:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2021-02-12 16:36:37 +00:00
continue ;
}
2021-07-16 03:45:57 +00:00
Variant v = p_resource - > get ( E . name ) ;
2021-08-26 19:37:17 +00:00
if ( v . is_ref_counted ( ) ) {
2022-05-02 23:43:50 +00:00
Ref < Resource > res = v ;
2021-02-12 16:36:37 +00:00
if ( res . is_valid ( ) ) {
if ( p_resource_remap . has ( res ) ) {
2021-07-16 03:45:57 +00:00
p_resource - > set ( E . name , p_resource_remap [ res ] ) ;
2021-02-12 16:36:37 +00:00
remap_nested_resources ( res , p_resource_remap ) ;
}
}
}
}
}
2017-11-19 13:32:10 +00:00
# endif
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 {
2021-06-18 22:02:50 +00:00
if ( ( this ! = p_original ) & & ! ( p_original - > is_ancestor_of ( this ) ) ) {
2015-05-10 18:45:33 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2015-05-10 18:45:33 +00:00
2020-06-08 09:19:50 +00:00
List < const Node * > process_list ;
process_list . push_back ( this ) ;
2020-12-15 12:04:21 +00:00
while ( ! process_list . is_empty ( ) ) {
2020-06-08 09:19:50 +00:00
const Node * n = process_list . front ( ) - > get ( ) ;
process_list . pop_front ( ) ;
2015-05-10 18:45:33 +00:00
2020-06-08 09:19:50 +00:00
List < Connection > conns ;
n - > get_all_signal_connections ( & conns ) ;
2015-05-10 18:45:33 +00:00
2021-07-24 13:46:25 +00:00
for ( const Connection & E : conns ) {
2021-07-16 03:45:57 +00:00
if ( E . flags & CONNECT_PERSIST ) {
2020-06-08 09:19:50 +00:00
//user connected
NodePath p = p_original - > get_path_to ( n ) ;
Node * copy = p_copy - > get_node ( p ) ;
2015-05-10 18:45:33 +00:00
2021-07-16 03:45:57 +00:00
Node * target = Object : : cast_to < Node > ( E . callable . get_object ( ) ) ;
2020-06-08 09:19:50 +00:00
if ( ! target ) {
continue ;
}
NodePath ptarget = p_original - > get_path_to ( target ) ;
2018-10-03 12:59:16 +00:00
2020-06-08 09:19:50 +00:00
Node * copytarget = target ;
2018-10-03 12:59:16 +00:00
2020-06-08 09:19:50 +00:00
// Attempt 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
// to the same target as the original
2017-11-19 12:05:18 +00:00
2020-06-08 09:19:50 +00:00
if ( p_copy - > has_node ( ptarget ) ) {
copytarget = p_copy - > get_node ( ptarget ) ;
}
if ( copy & & copytarget ) {
2021-07-16 03:45:57 +00:00
const Callable copy_callable = Callable ( copytarget , E . callable . get_method ( ) ) ;
if ( ! copy - > is_connected ( E . signal . get_name ( ) , copy_callable ) ) {
copy - > connect ( E . signal . get_name ( ) , copy_callable , E . binds , E . flags ) ;
2020-06-08 09:19:50 +00:00
}
2020-02-21 22:26:13 +00:00
}
2015-05-10 18:45:33 +00:00
}
}
2020-06-08 09:19:50 +00:00
for ( int i = 0 ; i < n - > get_child_count ( ) ; i + + ) {
process_list . push_back ( n - > get_child ( i ) ) ;
}
2015-05-10 18:45:33 +00:00
}
}
2017-03-05 15:44:50 +00:00
static void find_owned_by ( Node * p_by , Node * p_node , List < Node * > * p_owned ) {
2020-05-14 14:41:43 +00:00
if ( p_node - > get_owner ( ) = = p_by ) {
2014-02-10 01:10:30 +00:00
p_owned - > push_back ( p_node ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
find_owned_by ( p_by , p_node - > get_child ( i ) , p_owned ) ;
2014-02-10 01:10:30 +00:00
}
}
2021-01-31 12:55:13 +00:00
void Node : : replace_by ( Node * p_node , bool p_keep_groups ) {
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
2021-01-31 12:55:13 +00:00
if ( p_keep_groups ) {
2016-11-02 23:19:32 +00:00
List < GroupInfo > groups ;
get_groups ( & groups ) ;
2021-07-24 13:46:25 +00:00
for ( const GroupInfo & E : groups ) {
2021-07-16 03:45:57 +00:00
p_node - > add_to_group ( E . name , E . persistent ) ;
2020-05-14 14:41:43 +00:00
}
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 ) {
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2017-03-05 15:44:50 +00:00
find_owned_by ( data . owner , get_child ( i ) , & owned_by_owner ) ;
2020-05-14 14:41:43 +00:00
}
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 ( ) ) {
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 ) ;
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < owned . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
owned [ i ] - > set_owner ( p_node ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +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 ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2021-09-30 14:30:55 +00:00
p_node - > set_scene_file_path ( get_scene_file_path ( ) ) ;
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 ) ;
2021-07-24 13:46:25 +00:00
for ( const Connection & c : cl ) {
2017-03-11 19:21:04 +00:00
if ( c . flags & CONNECT_PERSIST ) {
2020-02-21 22:26:13 +00:00
c . signal . get_object ( ) - > disconnect ( c . signal . get_name ( ) , Callable ( this , c . callable . get_method ( ) ) ) ;
2020-02-19 19:27:19 +00:00
bool valid = p_new_target - > has_method ( c . callable . get_method ( ) ) | | Ref < Script > ( p_new_target - > get_script ( ) ) . is_null ( ) | | Ref < Script > ( p_new_target - > get_script ( ) ) - > has_method ( c . callable . get_method ( ) ) ;
2021-05-23 14:42:47 +00:00
ERR_CONTINUE_MSG ( ! valid , vformat ( " Attempt to connect signal '%s.%s' to nonexistent method '%s.%s'. " , c . signal . get_object ( ) - > get_class ( ) , c . signal . get_name ( ) , c . callable . get_object ( ) - > get_class ( ) , c . callable . get_method ( ) ) ) ;
2020-02-21 22:26:13 +00:00
c . signal . get_object ( ) - > connect ( c . signal . get_name ( ) , Callable ( p_new_target , c . callable . get_method ( ) ) , c . binds , c . flags ) ;
2017-03-11 19:21:04 +00:00
}
2016-06-09 14:24:12 +00:00
}
}
2017-03-05 15:44:50 +00:00
bool Node : : has_node_and_resource ( const NodePath & p_path ) const {
2020-05-14 14:41:43 +00:00
if ( ! has_node ( p_path ) ) {
2014-02-10 01:10:30 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2022-05-02 23:43:50 +00:00
Ref < Resource > res ;
2019-06-26 13:15:11 +00:00
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 ) {
2022-05-02 23:43:50 +00:00
Ref < Resource > 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 ;
2020-05-14 14:41:43 +00:00
if ( node ) {
2014-02-10 01:10:30 +00:00
result . push_back ( node ) ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
result . push_back ( Variant ( ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( res . is_valid ( ) ) {
2014-02-10 01:10:30 +00:00
result . push_back ( res ) ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
result . push_back ( Variant ( ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
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 ;
}
2022-05-02 23:43:50 +00:00
Node * Node : : get_node_and_resource ( const NodePath & p_path , Ref < Resource > & 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 ) ;
2022-05-02 23:43:50 +00:00
r_res = Ref < Resource > ( ) ;
2017-05-30 20:20:15 +00:00
r_leftover_subpath = Vector < StringName > ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! node ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
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 + + ) {
2022-05-16 17:40:59 +00:00
bool is_valid = false ;
Variant new_res_v = j = = 0 ? node - > get ( p_path . get_subname ( j ) , & is_valid ) : r_res - > get ( p_path . get_subname ( j ) , & is_valid ) ;
2019-07-10 18:03:04 +00:00
2022-05-16 17:40:59 +00:00
if ( ! is_valid ) { // Found nothing on that path
2020-04-01 23:20:12 +00:00
return nullptr ;
2019-07-10 18:03:04 +00:00
}
2022-05-02 23:43:50 +00:00
Ref < Resource > 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 ) {
2020-04-01 23:20:12 +00:00
SceneTree * tree_changed_a = nullptr ;
SceneTree * tree_changed_b = nullptr ;
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 ) {
_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
}
2020-05-14 14:41:43 +00:00
if ( tree_changed_a ) {
2014-02-10 01:10:30 +00:00
tree_changed_a - > tree_changed ( ) ;
2020-05-14 14:41:43 +00:00
}
if ( tree_changed_b ) {
2014-02-10 01:10:30 +00:00
tree_changed_b - > tree_changed ( ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
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 ) ;
2020-05-14 14:41:43 +00:00
if ( ! n ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( n - > is_inside_tree ( ) ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
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 ;
2020-05-14 14:41:43 +00:00
if ( p = = n ) {
2017-03-05 15:44:50 +00:00
path = n - > get_name ( ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-03-05 15:44:50 +00:00
path = String ( p - > get_name ( ) ) + " / " + p - > get_path_to ( n ) ;
2020-05-14 14:41:43 +00:00
}
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
2022-03-27 17:30:49 +00:00
void Node : : _print_orphan_nodes ( ) {
print_orphan_nodes ( ) ;
2014-02-10 01:10:30 +00:00
}
2022-03-27 17:30:49 +00:00
void Node : : print_orphan_nodes ( ) {
2014-02-10 01:10:30 +00:00
# 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
}
2021-08-25 13:49:30 +00:00
TypedArray < Node > Node : : _get_children ( bool p_include_internal ) const {
2020-04-20 22:06:00 +00:00
TypedArray < Node > arr ;
2021-08-25 13:49:30 +00:00
int cc = get_child_count ( p_include_internal ) ;
2014-02-10 01:10:30 +00:00
arr . resize ( cc ) ;
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < cc ; i + + ) {
2021-08-25 13:49:30 +00:00
arr [ i ] = get_child ( i , p_include_internal ) ;
2020-05-14 14:41:43 +00:00
}
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 ) {
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 ) {
2020-05-14 14:41:43 +00:00
if ( p_node ! = p_base & & ! p_node - > get_owner ( ) ) {
2014-12-17 01:31:57 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-12-17 01:31:57 +00:00
String n = p_base - > get_path_to ( p_node ) ;
2021-10-01 15:06:48 +00:00
r_options - > push_back ( n . quote ( ) ) ;
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 {
String pf = p_function ;
if ( ( pf = = " has_node " | | pf = = " get_node " ) & & p_idx = = 0 ) {
_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 ( ) ;
}
}
2020-10-29 10:01:28 +00:00
TypedArray < String > Node : : get_configuration_warnings ( ) const {
2022-04-16 10:23:32 +00:00
TypedArray < String > ret ;
2021-08-22 15:37:22 +00:00
Vector < String > warnings ;
if ( GDVIRTUAL_CALL ( _get_configuration_warnings , warnings ) ) {
for ( int i = 0 ; i < warnings . size ( ) ; i + + ) {
2022-04-16 10:23:32 +00:00
ret . push_back ( warnings [ i ] ) ;
2021-08-22 15:37:22 +00:00
}
2018-08-14 19:52:40 +00:00
}
2022-04-16 10:23:32 +00:00
return ret ;
2016-05-17 21:27:15 +00:00
}
2020-10-29 10:01:28 +00:00
String Node : : get_configuration_warnings_as_string ( ) const {
TypedArray < String > warnings = get_configuration_warnings ( ) ;
String all_warnings = String ( ) ;
for ( int i = 0 ; i < warnings . size ( ) ; i + + ) {
if ( i > 0 ) {
all_warnings + = " \n \n " ;
}
2021-07-06 17:36:05 +00:00
// Format as a bullet point list to make multiple warnings easier to distinguish
// from each other.
all_warnings + = String : : utf8 ( " • " ) + String ( warnings [ i ] ) ;
2020-10-29 10:01:28 +00:00
}
return all_warnings ;
}
void Node : : update_configuration_warnings ( ) {
2016-05-17 21:27:15 +00:00
# ifdef TOOLS_ENABLED
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2016-05-17 21:27:15 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2021-06-18 22:02:50 +00:00
if ( get_tree ( ) - > get_edited_scene_root ( ) & & ( get_tree ( ) - > get_edited_scene_root ( ) = = this | | get_tree ( ) - > get_edited_scene_root ( ) - > is_ancestor_of ( this ) ) ) {
2017-03-05 15:44:50 +00:00
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
}
2021-08-22 15:37:22 +00:00
void Node : : _call_input ( const Ref < InputEvent > & p_event ) {
GDVIRTUAL_CALL ( _input , p_event ) ;
if ( ! is_inside_tree ( ) | | ! get_viewport ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
return ;
}
input ( p_event ) ;
}
2022-01-11 13:59:52 +00:00
void Node : : _call_shortcut_input ( const Ref < InputEvent > & p_event ) {
GDVIRTUAL_CALL ( _shortcut_input , p_event ) ;
if ( ! is_inside_tree ( ) | | ! get_viewport ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
return ;
}
shortcut_input ( p_event ) ;
}
2021-08-22 15:37:22 +00:00
void Node : : _call_unhandled_input ( const Ref < InputEvent > & p_event ) {
GDVIRTUAL_CALL ( _unhandled_input , p_event ) ;
if ( ! is_inside_tree ( ) | | ! get_viewport ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
return ;
}
unhandled_input ( p_event ) ;
}
2022-01-11 13:59:52 +00:00
2021-08-22 15:37:22 +00:00
void Node : : _call_unhandled_key_input ( const Ref < InputEvent > & p_event ) {
GDVIRTUAL_CALL ( _unhandled_key_input , p_event ) ;
if ( ! is_inside_tree ( ) | | ! get_viewport ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
return ;
}
unhandled_key_input ( p_event ) ;
}
void Node : : input ( const Ref < InputEvent > & p_event ) {
}
2022-01-11 13:59:52 +00:00
void Node : : shortcut_input ( const Ref < InputEvent > & p_key_event ) {
}
2021-08-22 15:37:22 +00:00
void Node : : unhandled_input ( const Ref < InputEvent > & p_event ) {
}
void Node : : unhandled_key_input ( const Ref < InputEvent > & p_key_event ) {
}
2014-02-10 01:10:30 +00:00
void Node : : _bind_methods ( ) {
2021-02-17 16:44:49 +00:00
GLOBAL_DEF ( " editor/node_naming/name_num_separator " , 0 ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " editor/node_naming/name_num_separator " , PropertyInfo ( Variant : : INT , " editor/node_naming/name_num_separator " , PROPERTY_HINT_ENUM , " None,Space,Underscore,Dash " ) ) ;
GLOBAL_DEF ( " editor/node_naming/name_casing " , NAME_CASING_PASCAL_CASE ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " editor/node_naming/name_casing " , PropertyInfo ( Variant : : INT , " editor/node_naming/name_casing " , PROPERTY_HINT_ENUM , " PascalCase,camelCase,snake_case " ) ) ;
2016-10-07 18:25:29 +00:00
2020-05-12 06:12:08 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_sibling " , " sibling " , " legible_unique_name " ) , & Node : : add_sibling , 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 ) ;
2021-08-25 13:49:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_child " , " node " , " legible_unique_name " , " internal " ) , & Node : : add_child , DEFVAL ( false ) , DEFVAL ( 0 ) ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " remove_child " , " node " ) , & Node : : remove_child ) ;
2021-08-25 13:49:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_child_count " , " include_internal " ) , & Node : : get_child_count , DEFVAL ( false ) ) ; // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript.
ClassDB : : bind_method ( D_METHOD ( " get_children " , " include_internal " ) , & Node : : _get_children , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_child " , " idx " , " include_internal " ) , & Node : : get_child , DEFVAL ( false ) ) ;
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 ) ;
2022-04-25 13:16:44 +00:00
ClassDB : : bind_method ( D_METHOD ( " find_child " , " pattern " , " recursive " , " owned " ) , & Node : : find_child , DEFVAL ( true ) , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " find_children " , " pattern " , " type " , " recursive " , " owned " ) , & Node : : find_children , DEFVAL ( " " ) , DEFVAL ( true ) , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " find_parent " , " pattern " ) , & 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 ) ;
2021-06-18 22:02:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_ancestor_of " , " node " ) , & Node : : is_ancestor_of ) ;
2017-08-09 11:19:41 +00:00
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 ) ;
2021-08-25 13:49:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_index " , " include_internal " ) , & Node : : get_index , DEFVAL ( false ) ) ;
2017-03-05 15:44:50 +00:00
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 ) ;
2021-09-30 14:30:55 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_scene_file_path " , " scene_file_path " ) , & Node : : set_scene_file_path ) ;
ClassDB : : bind_method ( D_METHOD ( " get_scene_file_path " ) , & Node : : get_scene_file_path ) ;
2017-03-05 15:44:50 +00:00
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 ) ;
2022-01-11 13:59:52 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_process_shortcut_input " , " enable " ) , & Node : : set_process_shortcut_input ) ;
ClassDB : : bind_method ( D_METHOD ( " is_processing_shortcut_input " ) , & Node : : is_processing_shortcut_input ) ;
2017-03-05 15:44:50 +00:00
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 ) ;
2021-02-18 18:52:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_process_mode " , " mode " ) , & Node : : set_process_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_process_mode " ) , & Node : : get_process_mode ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " can_process " ) , & Node : : can_process ) ;
2022-03-27 17:30:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " print_orphan_nodes " ) , & Node : : _print_orphan_nodes ) ;
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 ) ;
2020-09-05 01:05:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " create_tween " ) , & Node : : create_tween ) ;
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 ) ) ;
2021-01-31 12:55:13 +00:00
ClassDB : : bind_method ( D_METHOD ( " replace_by " , " node " , " keep_groups " ) , & 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 ) ;
2021-08-23 02:18:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_editable_instance " , " node " , " is_editable " ) , & Node : : set_editable_instance ) ;
ClassDB : : bind_method ( D_METHOD ( " is_editable_instance " , " node " ) , & Node : : is_editable_instance ) ;
2017-03-05 15:44:50 +00:00
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 ) ;
2021-09-07 21:35:19 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_multiplayer_authority " , " id " , " recursive " ) , & Node : : set_multiplayer_authority , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_multiplayer_authority " ) , & Node : : get_multiplayer_authority ) ;
2017-03-05 15:44:50 +00:00
2021-09-07 21:35:19 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_multiplayer_authority " ) , & Node : : is_multiplayer_authority ) ;
2017-03-05 15:44:50 +00:00
2018-05-08 08:51:04 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_multiplayer " ) , & Node : : get_multiplayer ) ;
2021-10-06 15:25:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " rpc_config " , " method " , " rpc_mode " , " call_local " , " transfer_mode " , " channel " ) , & Node : : rpc_config , DEFVAL ( false ) , DEFVAL ( Multiplayer : : TRANSFER_MODE_RELIABLE ) , DEFVAL ( 0 ) ) ;
2016-05-17 21:27:15 +00:00
2021-02-18 18:52:29 +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 ) ;
2019-08-15 12:50:26 +00:00
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 ) ;
2021-02-18 18:52:29 +00:00
2022-04-16 10:23:32 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_unique_name_in_owner " , " enable " ) , & Node : : set_unique_name_in_owner ) ;
ClassDB : : bind_method ( D_METHOD ( " is_unique_name_in_owner " ) , & Node : : is_unique_name_in_owner ) ;
2021-10-26 19:12:25 +00:00
# ifdef TOOLS_ENABLED
ClassDB : : bind_method ( D_METHOD ( " _set_property_pinned " , " property " , " pinned " ) , & Node : : set_property_pinned ) ;
# endif
2021-11-03 22:06:17 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : NODE_PATH , " _import_path " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR | 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
2020-02-20 21:58:05 +00:00
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " 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 ) ;
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 ) ;
2016-08-14 21:49:50 +00:00
}
2020-10-29 10:01:28 +00:00
ClassDB : : bind_method ( D_METHOD ( " update_configuration_warnings " ) , & Node : : update_configuration_warnings ) ;
2019-10-17 10:20:35 +00:00
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 ) ;
2021-09-03 22:12:37 +00:00
BIND_CONSTANT ( NOTIFICATION_PATH_RENAMED ) ;
2017-03-05 15:44:50 +00:00
BIND_CONSTANT ( NOTIFICATION_INTERNAL_PROCESS ) ;
2017-09-30 14:19:07 +00:00
BIND_CONSTANT ( NOTIFICATION_INTERNAL_PHYSICS_PROCESS ) ;
2020-08-12 11:31:32 +00:00
BIND_CONSTANT ( NOTIFICATION_POST_ENTER_TREE ) ;
2021-06-18 01:09:40 +00:00
BIND_CONSTANT ( NOTIFICATION_DISABLED ) ;
BIND_CONSTANT ( NOTIFICATION_ENABLED ) ;
2017-03-05 15:44:50 +00:00
New and improved IK system for Skeleton2D
This PR and commit adds a new IK system for 2D with the Skeleton2D node
that adds several new IK solvers, a way to control bones in a Skeleton2D
node similar to that in Skeleton3D. It also adds additional changes
and functionality.
This work was sponsored by GSoC 2020 and TwistedTwigleg.
Full list of changes:
* Adds a SkeletonModifier2D resource
* This resource is the base where all IK code is written and executed
* Has a function for clamping angles, since it is so commonly used
* Modifiers are unique when duplicated so it works with instancing
* Adds a SkeletonModifierStack2D resource
* This resource manages a series of SkeletonModification2Ds
* This is what the Skeleton2D directly interfaces with to make IK possible
* Adds SkeletonModifier2D resources for LookAt, CCDIK, FABRIK, Jiggle, and TwoBoneIK
* Each modification is in its own file
* There is also a SkeletonModifier2D resource that acts as a stack for using multiple stacks together
* Adds a PhysicalBone2D node
* Works similar to the PhysicalBone3D node, but uses a RigidBody2D node
* Changes to Skeleton2D listed below:
* Skeleton2D now holds a single SkeletonModificationStack2D for IK
* Skeleton2D now has a local_pose_override, which overrides the Bone2D position similar to how the overrides work in Skeleton3D
* Changes to Bone2D listed below:
* The default_length property has been changed to length. Length is the length of the bone to its child bone node
* New bone_angle property, which is the angle the bone has to its first child bone node
* Bone2D caches its transform when not modified by IK for IK interpolation purposes
* Bone2D draws its own editor gizmo, though this is stated to change in the future
* Changes to CanvasItemEditor listed below:
* Bone2D gizmo drawing code removed
* The 2D IK code is removed. Now Bone2D is the only bone system for 2D
* Transform2D now has a looking_at function for rotating to face a position
* Two new node notifications: NOTIFICATION_EDITOR_PRE_SAVE and NOTIFICATION_EDITOR_POST_SAVE
* These notifications only are called in the editor right before and after saving a scene
* Needed for not saving the IK position when executing IK in the editor
* Documentation for all the changes listed above.
2020-08-03 18:02:24 +00:00
BIND_CONSTANT ( NOTIFICATION_EDITOR_PRE_SAVE ) ;
BIND_CONSTANT ( NOTIFICATION_EDITOR_POST_SAVE ) ;
2019-04-04 13:34:03 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_MOUSE_ENTER ) ;
BIND_CONSTANT ( NOTIFICATION_WM_MOUSE_EXIT ) ;
2020-06-29 23:47:18 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_WINDOW_FOCUS_IN ) ;
BIND_CONSTANT ( NOTIFICATION_WM_WINDOW_FOCUS_OUT ) ;
2020-03-04 16:36:09 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_CLOSE_REQUEST ) ;
2019-04-04 13:34:03 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_GO_BACK_REQUEST ) ;
2020-03-06 17:00:16 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_SIZE_CHANGED ) ;
2022-02-15 21:14:39 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_DPI_CHANGE ) ;
BIND_CONSTANT ( NOTIFICATION_VP_MOUSE_ENTER ) ;
BIND_CONSTANT ( NOTIFICATION_VP_MOUSE_EXIT ) ;
2019-04-04 13:34:03 +00:00
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 ) ;
2020-06-29 23:47:18 +00:00
BIND_CONSTANT ( NOTIFICATION_APPLICATION_RESUMED ) ;
BIND_CONSTANT ( NOTIFICATION_APPLICATION_PAUSED ) ;
BIND_CONSTANT ( NOTIFICATION_APPLICATION_FOCUS_IN ) ;
BIND_CONSTANT ( NOTIFICATION_APPLICATION_FOCUS_OUT ) ;
2020-09-03 11:22:16 +00:00
BIND_CONSTANT ( NOTIFICATION_TEXT_SERVER_CHANGED ) ;
2019-04-04 13:34:03 +00:00
2021-02-18 18:52:29 +00:00
BIND_ENUM_CONSTANT ( PROCESS_MODE_INHERIT ) ;
BIND_ENUM_CONSTANT ( PROCESS_MODE_PAUSABLE ) ;
BIND_ENUM_CONSTANT ( PROCESS_MODE_WHEN_PAUSED ) ;
BIND_ENUM_CONSTANT ( PROCESS_MODE_ALWAYS ) ;
BIND_ENUM_CONSTANT ( PROCESS_MODE_DISABLED ) ;
2017-08-20 15:45:01 +00:00
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
2021-08-25 13:49:30 +00:00
BIND_ENUM_CONSTANT ( INTERNAL_MODE_DISABLED ) ;
BIND_ENUM_CONSTANT ( INTERNAL_MODE_FRONT ) ;
BIND_ENUM_CONSTANT ( INTERNAL_MODE_BACK ) ;
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 " ) ) ;
2022-02-02 10:22:11 +00:00
ADD_SIGNAL ( MethodInfo ( " child_entered_tree " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT , " Node " ) ) ) ;
2022-06-20 07:53:44 +00:00
ADD_SIGNAL ( MethodInfo ( " child_exiting_tree " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT , " Node " ) ) ) ;
2014-02-10 01:10:30 +00:00
2021-06-17 23:10:18 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING_NAME , " name " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " set_name " , " get_name " ) ;
2022-04-25 13:16:44 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " unique_name_in_owner " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NO_EDITOR ) , " set_unique_name_in_owner " , " is_unique_name_in_owner " ) ;
2021-09-30 14:30:55 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " scene_file_path " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " set_scene_file_path " , " get_scene_file_path " ) ;
2021-06-17 23:10:18 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " owner " , PROPERTY_HINT_RESOURCE_TYPE , " Node " , PROPERTY_USAGE_NONE ) , " set_owner " , " get_owner " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " multiplayer " , PROPERTY_HINT_RESOURCE_TYPE , " MultiplayerAPI " , PROPERTY_USAGE_NONE ) , " " , " get_multiplayer " ) ;
2021-02-18 18:52:29 +00:00
ADD_GROUP ( " Process " , " process_ " ) ;
2021-05-22 02:30:58 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " process_mode " , PROPERTY_HINT_ENUM , " Inherit,Pausable,When Paused,Always,Disabled " ) , " set_process_mode " , " get_process_mode " ) ;
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
2021-02-18 18:52:29 +00:00
ADD_GROUP ( " Editor Description " , " editor_ " ) ;
2021-06-18 13:49:30 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " editor_description " , PROPERTY_HINT_MULTILINE_TEXT ) , " set_editor_description " , " get_editor_description " ) ;
2021-02-18 18:52:29 +00:00
2021-08-22 01:52:44 +00:00
GDVIRTUAL_BIND ( _process , " delta " ) ;
GDVIRTUAL_BIND ( _physics_process , " delta " ) ;
GDVIRTUAL_BIND ( _enter_tree ) ;
GDVIRTUAL_BIND ( _exit_tree ) ;
GDVIRTUAL_BIND ( _ready ) ;
GDVIRTUAL_BIND ( _get_configuration_warnings ) ;
2021-08-22 15:37:22 +00:00
GDVIRTUAL_BIND ( _input , " event " ) ;
2022-01-11 13:59:52 +00:00
GDVIRTUAL_BIND ( _shortcut_input , " event " ) ;
2021-08-22 15:37:22 +00:00
GDVIRTUAL_BIND ( _unhandled_input , " event " ) ;
GDVIRTUAL_BIND ( _unhandled_key_input , " event " ) ;
2014-02-10 01:10:30 +00:00
}
2016-10-07 18:25:29 +00:00
String Node : : _get_name_num_separator ( ) {
2021-02-17 16:44:49 +00:00
switch ( ProjectSettings : : get_singleton ( ) - > get ( " editor/node_naming/name_num_separator " ) . operator int ( ) ) {
2020-05-10 11:00:47 +00:00
case 0 :
return " " ;
case 1 :
return " " ;
case 2 :
return " _ " ;
case 3 :
return " - " ;
2016-10-07 18:25:29 +00:00
}
return " " ;
}
2014-02-10 01:10:30 +00:00
Node : : Node ( ) {
2019-04-17 20:46:21 +00:00
orphan_node_count + + ;
2014-02-10 01:10:30 +00:00
}
Node : : ~ Node ( ) {
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
////////////////////////////////