2023-01-05 12:25:55 +00:00
/**************************************************************************/
/* node.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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"
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"
2022-07-12 21:12:42 +00:00
# include "scene/main/multiplayer_api.h"
2023-01-10 07:40:44 +00:00
# include "scene/main/window.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 ) ;
2023-04-10 16:45:53 +00:00
VARIANT_ENUM_CAST ( Node : : ProcessThreadGroup ) ;
VARIANT_BITFIELD_CAST ( Node : : ProcessThreadMessages ) ;
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 ;
2023-04-10 16:45:53 +00:00
thread_local Node * Node : : current_process_thread_group = nullptr ;
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 : {
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL ( get_viewport ( ) ) ;
ERR_FAIL_NULL ( get_tree ( ) ) ;
2014-02-10 01:10:30 +00:00
2023-04-10 16:45:53 +00:00
// Update process mode.
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
}
2023-04-10 16:45:53 +00:00
{ // Update threaded process mode.
if ( data . process_thread_group = = PROCESS_THREAD_GROUP_INHERIT ) {
if ( data . parent ) {
data . process_thread_group_owner = data . parent - > data . process_thread_group_owner ;
}
if ( data . process_thread_group_owner ) {
data . process_group = data . process_thread_group_owner - > data . process_group ;
} else {
data . process_group = & data . tree - > default_process_group ;
}
} else {
data . process_thread_group_owner = this ;
_add_process_group ( ) ;
}
if ( _is_any_processing ( ) ) {
_add_to_process_thread_group ( ) ;
}
}
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
2023-04-10 16:45:53 +00:00
get_tree ( ) - > nodes_in_tree_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 : {
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL ( get_viewport ( ) ) ;
ERR_FAIL_NULL ( get_tree ( ) ) ;
2014-02-10 01:10:30 +00:00
2023-04-10 16:45:53 +00:00
get_tree ( ) - > nodes_in_tree_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
2023-04-10 16:45:53 +00:00
// Remove from processing first
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
}
// Remove the process group
if ( data . process_thread_group_owner = = this ) {
_remove_process_group ( ) ;
}
data . process_thread_group_owner = nullptr ;
2021-02-18 18:52:29 +00:00
data . process_owner = nullptr ;
2023-04-10 16:45:53 +00:00
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 : {
2023-04-10 16:45:53 +00:00
if ( data . inside_tree & & ! Thread : : is_main_thread ( ) ) {
cancel_free ( ) ;
ERR_PRINT ( " Attempted to free a node that is currently added to the SceneTree from a thread. This is not permitted, use queue_free() instead. Node has not been freed. " ) ;
return ;
}
2023-02-27 08:16:51 +00:00
if ( data . owner ) {
_clean_up_owner ( ) ;
}
2014-02-10 01:10:30 +00:00
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 ( ) ) {
2023-04-03 20:31:47 +00:00
Node * child = data . children . last ( ) - > value ; // 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 + + ;
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _propagate_ready ( ) ;
2014-02-10 01:10:30 +00:00
}
2023-04-03 20:31:47 +00:00
2014-02-10 01:10:30 +00:00
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
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
if ( ! K . value - > is_inside_tree ( ) ) { // could have been added in enter_tree
K . value - > _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 ) {
2023-02-27 08:16:51 +00:00
_clean_up_owner ( ) ;
2022-01-05 13:00:04 +00:00
}
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 + + ;
2023-04-03 20:31:47 +00:00
for ( HashMap < StringName , Node * > : : Iterator I = data . children . last ( ) ; I ; - - I ) {
I - > value - > _propagate_after_exit_tree ( ) ;
2018-09-07 18:31:19 +00:00
}
2023-04-03 20:31:47 +00:00
2018-09-07 18:31:19 +00:00
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
2023-01-07 11:12:24 +00:00
if ( ! data . scene_file_path . is_empty ( ) ) {
// Only remove if file path is set (optimization).
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 + + ;
2023-04-03 20:31:47 +00:00
for ( HashMap < StringName , Node * > : : Iterator I = data . children . last ( ) ; I ; - - I ) {
I - > value - > _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
}
2022-10-14 18:21:41 +00:00
void Node : : move_child ( Node * p_child , int p_index ) {
2023-04-10 16:45:53 +00:00
ERR_FAIL_COND_MSG ( data . inside_tree & & ! Thread : : is_main_thread ( ) , " Moving child node positions inside the SceneTree is only allowed from the main thread. Use call_deferred( \" move_child \" ,child,index). " ) ;
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
2023-04-03 20:31:47 +00:00
_update_children_cache ( ) ;
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.
2023-04-03 20:31:47 +00:00
if ( p_child - > data . internal_mode = = INTERNAL_MODE_FRONT ) {
2022-10-14 18:21:41 +00:00
if ( p_index < 0 ) {
2023-04-03 20:31:47 +00:00
p_index + = data . internal_children_front_count_cache ;
2022-09-10 01:54:04 +00:00
}
2023-04-03 20:31:47 +00:00
ERR_FAIL_INDEX_MSG ( p_index , data . internal_children_front_count_cache , vformat ( " Invalid new child index: %d. Child is internal. " , p_index ) ) ;
2022-10-14 18:21:41 +00:00
_move_child ( p_child , p_index ) ;
2023-04-03 20:31:47 +00:00
} else if ( p_child - > data . internal_mode = = INTERNAL_MODE_BACK ) {
2022-10-14 18:21:41 +00:00
if ( p_index < 0 ) {
2023-04-03 20:31:47 +00:00
p_index + = data . internal_children_back_count_cache ;
2022-09-10 01:54:04 +00:00
}
2023-04-03 20:31:47 +00:00
ERR_FAIL_INDEX_MSG ( p_index , data . internal_children_back_count_cache , vformat ( " Invalid new child index: %d. Child is internal. " , p_index ) ) ;
_move_child ( p_child , ( int ) data . children_cache . size ( ) - data . internal_children_back_count_cache + p_index ) ;
2021-08-25 13:49:30 +00:00
} else {
2022-10-14 18:21:41 +00:00
if ( p_index < 0 ) {
p_index + = get_child_count ( false ) ;
2022-09-10 01:54:04 +00:00
}
2023-04-03 20:31:47 +00:00
ERR_FAIL_INDEX_MSG ( p_index , ( int ) data . children_cache . size ( ) + 1 - data . internal_children_front_count_cache - data . internal_children_back_count_cache , vformat ( " Invalid new child index: %d. " , p_index ) ) ;
_move_child ( p_child , p_index + data . internal_children_front_count_cache ) ;
2021-08-25 13:49:30 +00:00
}
}
2022-10-14 18:21:41 +00:00
void Node : : _move_child ( Node * p_child , int p_index , bool p_ignore_end ) {
2022-11-12 16:16:45 +00:00
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, `move_child()` failed. Consider using `move_child.call_deferred(child, index)` instead (or `popup.call_deferred()` 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
2022-10-14 18:21:41 +00:00
// means the same as moving to the last index
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.
2023-04-03 20:31:47 +00:00
if ( p_child - > data . internal_mode = = INTERNAL_MODE_FRONT ) {
if ( p_index = = data . internal_children_front_count_cache ) {
2022-10-14 18:21:41 +00:00
p_index - - ;
2021-08-25 13:49:30 +00:00
}
2023-04-03 20:31:47 +00:00
} else if ( p_child - > data . internal_mode = = INTERNAL_MODE_BACK ) {
if ( p_index = = ( int ) data . children_cache . size ( ) ) {
2022-10-14 18:21:41 +00:00
p_index - - ;
2021-08-25 13:49:30 +00:00
}
} else {
2023-04-03 20:31:47 +00:00
if ( p_index = = ( int ) data . children_cache . size ( ) - data . internal_children_back_count_cache ) {
2022-10-14 18:21:41 +00:00
p_index - - ;
2021-08-25 13:49:30 +00:00
}
}
2020-05-14 14:41:43 +00:00
}
2017-07-25 03:11:00 +00:00
2023-04-03 20:31:47 +00:00
int child_index = p_child - > get_index ( ) ;
if ( child_index = = p_index ) {
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
2023-04-03 20:31:47 +00:00
int motion_from = MIN ( p_index , child_index ) ;
int motion_to = MAX ( p_index , child_index ) ;
2016-10-03 19:33:42 +00:00
2023-04-03 20:31:47 +00:00
data . children_cache . remove_at ( child_index ) ;
data . children_cache . insert ( p_index , 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 + + ) {
2023-04-03 20:31:47 +00:00
if ( data . children_cache [ i ] - > data . internal_mode = = INTERNAL_MODE_DISABLED ) {
data . children_cache [ i ] - > data . index = i - data . internal_children_front_count_cache ;
} else if ( data . children_cache [ i ] - > data . internal_mode = = INTERNAL_MODE_BACK ) {
data . children_cache [ i ] - > data . index = i - data . internal_children_front_count_cache - data . external_children_count_cache ;
} else {
data . children_cache [ i ] - > data . index = i ;
}
2014-02-10 01:10:30 +00:00
}
// notification second
2014-12-03 05:29:28 +00:00
move_child_notify ( p_child ) ;
2023-04-05 16:53:32 +00:00
notification ( NOTIFICATION_CHILD_ORDER_CHANGED ) ;
emit_signal ( SNAME ( " child_order_changed " ) ) ;
2022-05-31 18:28:04 +00:00
p_child - > _propagate_groups_dirty ( ) ;
2014-02-10 01:10:30 +00:00
data . blocked - - ;
}
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 ;
}
}
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _propagate_groups_dirty ( ) ;
2022-05-31 18:28:04 +00:00
}
}
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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
2023-04-10 16:45:53 +00:00
if ( ! is_inside_tree ( ) ) {
data . physics_process = p_process ;
return ;
}
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
}
2017-09-30 14:19:07 +00:00
data . physics_process = p_process ;
2016-03-08 23:00:52 +00:00
2023-04-10 16:45:53 +00:00
if ( _is_any_processing ( ) ) {
_add_to_process_thread_group ( ) ;
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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
2023-04-10 16:45:53 +00:00
if ( ! is_inside_tree ( ) ) {
data . physics_process_internal = p_process_internal ;
return ;
}
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
}
2017-09-30 14:19:07 +00:00
data . physics_process_internal = p_process_internal ;
2017-01-10 21:02:19 +00:00
2023-04-10 16:45:53 +00:00
if ( _is_any_processing ( ) ) {
_add_to_process_thread_group ( ) ;
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2021-02-18 18:52:29 +00:00
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 ) ;
}
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _propagate_pause_notification ( p_enable ) ;
2021-02-18 18:52:29 +00:00
}
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
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
Node * c = K . value ;
2021-02-18 18:52:29 +00:00
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2021-09-07 21:35:19 +00:00
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 ) {
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > 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
2022-07-12 21:12:42 +00:00
void Node : : rpc_config ( const StringName & p_method , const Variant & p_config ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2022-07-12 21:12:42 +00:00
if ( data . rpc_config . get_type ( ) ! = Variant : : DICTIONARY ) {
data . rpc_config = Dictionary ( ) ;
}
Dictionary node_config = data . rpc_config ;
if ( p_config . get_type ( ) = = Variant : : NIL ) {
node_config . erase ( p_method ) ;
} else {
ERR_FAIL_COND ( p_config . get_type ( ) ! = Variant : : DICTIONARY ) ;
node_config [ p_method ] = p_config ;
2020-02-12 10:51:50 +00:00
}
2022-07-12 21:12:42 +00:00
}
const Variant Node : : get_node_rpc_config ( ) const {
return data . rpc_config ;
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-07-12 21:12:42 +00:00
Error 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-07-12 21:12:42 +00:00
return ERR_INVALID_PARAMETER ;
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-07-12 21:12:42 +00:00
return ERR_INVALID_PARAMETER ;
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
2022-07-12 21:12:42 +00:00
Error err = rpcp ( 0 , method , & p_args [ 1 ] , p_argcount - 1 ) ;
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_OK ;
2022-07-12 21:12:42 +00:00
return err ;
2016-08-14 21:49:50 +00:00
}
2022-07-12 21:12:42 +00:00
Error 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-07-12 21:12:42 +00:00
return ERR_INVALID_PARAMETER ;
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-07-12 21:12:42 +00:00
return ERR_INVALID_PARAMETER ;
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-07-12 21:12:42 +00:00
return ERR_INVALID_PARAMETER ;
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
2022-07-12 21:12:42 +00:00
Error err = rpcp ( peer_id , method , & p_args [ 2 ] , p_argcount - 2 ) ;
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_OK ;
2022-07-12 21:12:42 +00:00
return err ;
2016-08-19 19:48:08 +00:00
}
2022-07-12 21:12:42 +00:00
Error Node : : rpcp ( int p_peer_id , const StringName & p_method , const Variant * * p_arg , int p_argcount ) {
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , ERR_UNCONFIGURED ) ;
return 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-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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2020-12-22 09:50:29 +00:00
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
2023-04-10 16:45:53 +00:00
if ( ! is_inside_tree ( ) ) {
data . process = p_process ;
return ;
}
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
}
2020-12-22 09:50:29 +00:00
data . process = p_process ;
2014-02-10 01:10:30 +00:00
2023-04-10 16:45:53 +00:00
if ( _is_any_processing ( ) ) {
_add_to_process_thread_group ( ) ;
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2020-12-22 09:50:29 +00:00
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
2023-04-10 16:45:53 +00:00
if ( ! is_inside_tree ( ) ) {
data . process_internal = p_process_internal ;
return ;
}
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
}
2020-12-22 09:50:29 +00:00
data . process_internal = p_process_internal ;
2017-01-10 21:02:19 +00:00
2023-04-10 16:45:53 +00:00
if ( _is_any_processing ( ) ) {
_add_to_process_thread_group ( ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2023-04-10 16:45:53 +00:00
void Node : : _add_process_group ( ) {
get_tree ( ) - > _add_process_group ( this ) ;
}
void Node : : _remove_process_group ( ) {
get_tree ( ) - > _remove_process_group ( this ) ;
}
void Node : : _remove_from_process_thread_group ( ) {
get_tree ( ) - > _remove_node_from_process_group ( this , data . process_thread_group_owner ) ;
}
void Node : : _add_to_process_thread_group ( ) {
get_tree ( ) - > _add_node_to_process_group ( this , data . process_thread_group_owner ) ;
}
void Node : : _remove_tree_from_process_thread_group ( ) {
if ( ! is_inside_tree ( ) ) {
return ; // May not be initialized yet.
}
for ( KeyValue < StringName , Node * > & K : data . children ) {
if ( K . value - > data . process_thread_group ! = PROCESS_THREAD_GROUP_INHERIT ) {
continue ;
}
K . value - > _remove_tree_from_process_thread_group ( ) ;
}
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
}
}
void Node : : _add_tree_to_process_thread_group ( Node * p_owner ) {
if ( _is_any_processing ( ) ) {
_add_to_process_thread_group ( ) ;
}
data . process_thread_group_owner = p_owner ;
if ( p_owner ! = nullptr ) {
data . process_group = p_owner - > data . process_group ;
} else {
data . process_group = & data . tree - > default_process_group ;
}
for ( KeyValue < StringName , Node * > & K : data . children ) {
if ( K . value - > data . process_thread_group ! = PROCESS_THREAD_GROUP_INHERIT ) {
continue ;
}
K . value - > _add_to_process_thread_group ( ) ;
}
}
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
}
2023-04-10 16:45:53 +00:00
void Node : : set_process_thread_group_order ( int p_order ) {
ERR_THREAD_GUARD
if ( data . process_thread_group_order = = p_order ) {
return ;
}
// Make sure we are in SceneTree and an actual process owner
if ( ! is_inside_tree ( ) | | data . process_thread_group_owner ! = this ) {
data . process_thread_group_order = p_order ;
return ;
}
get_tree ( ) - > process_groups_dirty = true ;
}
int Node : : get_process_thread_group_order ( ) const {
return data . process_thread_group_order ;
}
2018-07-02 05:30:40 +00:00
void Node : : set_process_priority ( int p_priority ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
if ( data . process_priority = = p_priority ) {
return ;
}
// Make sure we are in SceneTree and an actual process owner
if ( ! is_inside_tree ( ) ) {
data . process_priority = p_priority ;
return ;
}
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
data . process_priority = p_priority ;
_add_to_process_thread_group ( ) ;
}
}
2018-07-02 05:30:40 +00:00
2023-04-10 16:45:53 +00:00
int Node : : get_process_priority ( ) const {
return data . process_priority ;
}
void Node : : set_physics_process_priority ( int p_priority ) {
ERR_THREAD_GUARD
if ( data . physics_process_priority = = p_priority ) {
2019-11-21 16:26:28 +00:00
return ;
}
2023-04-10 16:45:53 +00:00
// Make sure we are in SceneTree and an actual physics_process owner
if ( ! is_inside_tree ( ) ) {
data . physics_process_priority = p_priority ;
return ;
}
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
data . physics_process_priority = p_priority ;
_add_to_process_thread_group ( ) ;
}
}
int Node : : get_physics_process_priority ( ) const {
return data . physics_process_priority ;
}
2019-06-22 12:52:51 +00:00
2023-04-10 16:45:53 +00:00
void Node : : set_process_thread_group ( ProcessThreadGroup p_mode ) {
ERR_FAIL_COND_MSG ( data . inside_tree & & ! Thread : : is_main_thread ( ) , " Changing the process thread group can only be done from the main thread. Use call_deferred( \" set_process_thread_group \" ,mode). " ) ;
if ( data . process_thread_group = = p_mode ) {
return ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
2023-04-10 16:45:53 +00:00
if ( ! is_inside_tree ( ) ) {
data . process_thread_group = p_mode ;
return ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
2023-04-10 16:45:53 +00:00
// Mode changed, must update everything.
_remove_tree_from_process_thread_group ( ) ;
if ( data . process_thread_group ! = PROCESS_THREAD_GROUP_INHERIT ) {
_remove_process_group ( ) ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
2023-04-10 16:45:53 +00:00
data . process_thread_group = p_mode ;
if ( p_mode = = PROCESS_THREAD_GROUP_INHERIT ) {
if ( data . parent ) {
data . process_thread_group_owner = data . parent - > data . process_thread_group_owner ;
} else {
data . process_thread_group_owner = nullptr ;
}
} else {
data . process_thread_group_owner = this ;
_add_process_group ( ) ;
2019-11-21 16:26:28 +00:00
}
2023-04-10 16:45:53 +00:00
_add_tree_to_process_thread_group ( data . process_thread_group_owner ) ;
notify_property_list_changed ( ) ;
2018-07-02 05:30:40 +00:00
}
2023-04-10 16:45:53 +00:00
Node : : ProcessThreadGroup Node : : get_process_thread_group ( ) const {
return data . process_thread_group ;
}
void Node : : set_process_thread_messages ( BitField < ProcessThreadMessages > p_flags ) {
ERR_THREAD_GUARD
if ( data . process_thread_group_order = = p_flags ) {
return ;
}
data . process_thread_messages = p_flags ;
}
BitField < Node : : ProcessThreadMessages > Node : : get_process_thread_messages ( ) const {
return data . process_thread_messages ;
2019-11-16 21:07:02 +00:00
}
2014-02-10 01:10:30 +00:00
void Node : : set_process_input ( bool p_enable ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2022-01-11 13:59:52 +00:00
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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 ) {
2023-04-10 16:45:53 +00:00
ERR_FAIL_COND_MSG ( data . inside_tree & & ! Thread : : is_main_thread ( ) , " Changing the name to nodes inside the SceneTree is only allowed from the main thread. Use call_deferred( \" set_name \" ,new_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 ( ) ;
}
2023-04-03 20:31:47 +00:00
String old_name = data . name ;
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 ) {
2023-04-03 20:31:47 +00:00
data . parent - > data . children . erase ( old_name ) ;
2021-11-15 01:05:44 +00:00
data . parent - > _validate_child_name ( this , true ) ;
2023-04-03 20:31:47 +00:00
data . parent - > data . children . insert ( data . name , this ) ;
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
}
}
2023-06-05 17:57:33 +00:00
// Returns a clear description of this node depending on what is available. Useful for error messages.
String Node : : get_description ( ) const {
String description ;
if ( is_inside_tree ( ) ) {
description = get_path ( ) ;
} else {
description = get_name ( ) ;
if ( description . is_empty ( ) ) {
description = get_class ( ) ;
}
}
return description ;
}
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
2022-08-18 11:47:05 +00:00
String Node : : adjust_name_casing ( const String & p_name ) {
2023-01-12 08:41:13 +00:00
switch ( GLOBAL_GET ( " editor/naming/node_name_casing " ) . operator int ( ) ) {
2022-08-18 11:47:05 +00:00
case NAME_CASING_PASCAL_CASE :
2022-08-30 09:36:24 +00:00
return p_name . to_pascal_case ( ) ;
case NAME_CASING_CAMEL_CASE :
return p_name . to_camel_case ( ) ;
2022-08-18 11:47:05 +00:00
case NAME_CASING_SNAKE_CASE :
2022-08-30 09:36:24 +00:00
return p_name . to_snake_case ( ) ;
2022-08-18 11:47:05 +00:00
}
return p_name ;
}
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 {
2023-04-03 20:31:47 +00:00
const Node * const * existing = data . children . getptr ( p_child - > data . name ) ;
unique = ! existing | | * existing = = p_child ;
2014-02-22 23:28:19 +00:00
}
if ( ! unique ) {
2019-08-07 10:54:30 +00:00
ERR_FAIL_COND ( ! node_hrcr_count . ref ( ) ) ;
2023-04-06 15:54:56 +00:00
// Optimized version of the code below:
// String name = "@" + String(p_child->get_name()) + "@" + itos(node_hrcr_count.get());
uint32_t c = node_hrcr_count . get ( ) ;
String cn = p_child - > get_class_name ( ) . operator String ( ) ;
const char32_t * cn_ptr = cn . ptr ( ) ;
uint32_t cn_length = cn . length ( ) ;
uint32_t c_chars = String : : num_characters ( c ) ;
uint32_t len = 2 + cn_length + c_chars ;
char32_t * str = ( char32_t * ) alloca ( sizeof ( char32_t ) * ( len + 1 ) ) ;
uint32_t idx = 0 ;
str [ idx + + ] = ' @ ' ;
for ( uint32_t i = 0 ; i < cn_length ; i + + ) {
str [ idx + + ] = cn_ptr [ i ] ;
}
str [ idx + + ] = ' @ ' ;
idx + = c_chars ;
ERR_FAIL_COND ( idx ! = len ) ;
str [ idx ] = 0 ;
while ( c ) {
str [ - - idx ] = ' 0 ' + ( c % 10 ) ;
c / = 10 ;
}
p_child - > data . name = String ( str ) ;
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 ( ) ) {
2022-10-10 20:30:34 +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 ( ) ;
2016-10-07 18:25:29 +00:00
}
2023-04-03 20:31:47 +00:00
const Node * const * existing = data . children . getptr ( name ) ;
if ( ! existing | | * existing = = p_child ) { // Unused, or is current node.
return ;
2019-01-10 21:52:47 +00:00
}
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 ;
2023-04-03 20:31:47 +00:00
existing = data . children . getptr ( attempt ) ;
bool exists = existing ! = nullptr & & * existing ! = p_child ;
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
}
}
}
2023-04-03 20:31:47 +00:00
void Node : : _add_child_nocheck ( Node * p_child , const StringName & p_name , InternalMode p_internal_mode ) {
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 ;
2023-04-03 20:31:47 +00:00
data . children . insert ( p_name , p_child ) ;
p_child - > data . internal_mode = p_internal_mode ;
switch ( p_internal_mode ) {
case INTERNAL_MODE_FRONT : {
p_child - > data . index = data . internal_children_front_count_cache + + ;
} break ;
case INTERNAL_MODE_BACK : {
p_child - > data . index = data . internal_children_back_count_cache + + ;
} break ;
case INTERNAL_MODE_DISABLED : {
p_child - > data . index = data . external_children_count_cache + + ;
} break ;
}
2017-03-05 15:44:50 +00:00
p_child - > data . parent = this ;
2021-08-25 13:49:30 +00:00
2023-04-03 20:31:47 +00:00
if ( ! data . children_cache_dirty & & p_internal_mode = = INTERNAL_MODE_DISABLED & & data . internal_children_back_count_cache = = 0 ) {
// Special case, also add to the cached children array since its cheap.
data . children_cache . push_back ( p_child ) ;
} else {
data . children_cache_dirty = true ;
2021-08-25 13:49:30 +00:00
}
2023-04-03 20:31:47 +00:00
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 ) ;
2023-04-05 16:53:32 +00:00
notification ( NOTIFICATION_CHILD_ORDER_CHANGED ) ;
emit_signal ( SNAME ( " child_order_changed " ) ) ;
2014-02-10 01:10:30 +00:00
}
2022-08-15 17:55:38 +00:00
void Node : : add_child ( Node * p_child , bool p_force_readable_name , InternalMode p_internal ) {
2023-04-10 16:45:53 +00:00
ERR_FAIL_COND_MSG ( data . inside_tree & & ! Thread : : is_main_thread ( ) , " Adding children to a node inside the SceneTree is only allowed from the main thread. Use call_deferred( \" add_child \" ,node). " ) ;
ERR_THREAD_GUARD
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
2022-11-12 16:16:45 +00:00
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, `add_child()` failed. Consider using `add_child.call_deferred(child)` instead. " ) ;
2016-03-08 23:00:52 +00:00
2022-08-15 17:55:38 +00:00
_validate_child_name ( p_child , p_force_readable_name ) ;
2023-04-03 20:31:47 +00:00
_add_child_nocheck ( p_child , p_child - > data . name , p_internal ) ;
2014-02-10 01:10:30 +00:00
}
2022-08-15 17:55:38 +00:00
void Node : : add_sibling ( Node * p_sibling , bool p_force_readable_name ) {
2023-04-10 16:45:53 +00:00
ERR_FAIL_COND_MSG ( data . inside_tree & & ! Thread : : is_main_thread ( ) , " Adding a sibling to a node inside the SceneTree is only allowed from the main thread. Use call_deferred( \" add_sibling \" ,node). " ) ;
2020-05-12 06:12:08 +00:00
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!
2022-11-12 16:16:45 +00:00
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, `add_sibling()` failed. Consider using `add_sibling.call_deferred(sibling)` instead. " ) ;
2016-05-13 16:09:49 +00:00
2023-04-03 20:31:47 +00:00
data . parent - > add_child ( p_sibling , p_force_readable_name , data . internal_mode ) ;
data . parent - > _update_children_cache ( ) ;
2021-08-25 13:49:30 +00:00
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 ) {
2023-04-10 16:45:53 +00:00
ERR_FAIL_COND_MSG ( data . inside_tree & & ! Thread : : is_main_thread ( ) , " Removing children from a node inside the SceneTree is only allowed from the main thread. Use call_deferred( \" remove_child \" ,node). " ) ;
2014-02-10 01:10:30 +00:00
ERR_FAIL_NULL ( p_child ) ;
2023-01-07 11:12:24 +00:00
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy adding/removing children, `remove_child()` can't be called at this time. Consider using `remove_child.call_deferred(child)` instead. " ) ;
2023-04-03 20:31:47 +00:00
ERR_FAIL_COND ( p_child - > data . parent ! = this ) ;
/**
* Do not change the data . internal_children * cache counters here .
* Because if nodes are re - added , the indices can remain
* greater - than - everything indices and children added remain
* properly ordered .
*
* All children indices and counters will be updated next time the
* cache is re - generated .
*/
2016-03-08 23:00:52 +00:00
2023-01-07 11:12:24 +00:00
data . blocked + + ;
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
2023-04-03 20:31:47 +00:00
data . blocked - - ;
2016-03-08 23:00:52 +00:00
2023-04-03 20:31:47 +00:00
data . children_cache_dirty = true ;
bool success = data . children . erase ( p_child - > data . name ) ;
ERR_FAIL_COND_MSG ( ! success , " Children name does not match parent name in hashtable, this is a bug. " ) ;
2023-04-06 18:47:57 +00:00
2020-04-01 23:20:12 +00:00
p_child - > data . parent = nullptr ;
2022-10-14 18:21:41 +00:00
p_child - > data . index = - 1 ;
2014-02-10 01:10:30 +00:00
2023-06-08 20:49:40 +00:00
notification ( NOTIFICATION_CHILD_ORDER_CHANGED ) ;
emit_signal ( SNAME ( " child_order_changed " ) ) ;
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
}
2023-04-03 20:31:47 +00:00
void Node : : _update_children_cache_impl ( ) const {
// Assign children
data . children_cache . resize ( data . children . size ( ) ) ;
int idx = 0 ;
for ( const KeyValue < StringName , Node * > & K : data . children ) {
data . children_cache [ idx ] = K . value ;
idx + + ;
}
// Sort them
data . children_cache . sort_custom < ComparatorByIndex > ( ) ;
// Update indices
data . external_children_count_cache = 0 ;
data . internal_children_back_count_cache = 0 ;
data . internal_children_front_count_cache = 0 ;
for ( uint32_t i = 0 ; i < data . children_cache . size ( ) ; i + + ) {
switch ( data . children_cache [ i ] - > data . internal_mode ) {
case INTERNAL_MODE_DISABLED : {
data . children_cache [ i ] - > data . index = data . external_children_count_cache + + ;
} break ;
case INTERNAL_MODE_FRONT : {
data . children_cache [ i ] - > data . index = data . internal_children_front_count_cache + + ;
} break ;
case INTERNAL_MODE_BACK : {
data . children_cache [ i ] - > data . index = data . internal_children_back_count_cache + + ;
} break ;
}
}
data . children_cache_dirty = false ;
}
2021-08-25 13:49:30 +00:00
int Node : : get_child_count ( bool p_include_internal ) const {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( 0 ) ;
2023-04-03 20:31:47 +00:00
_update_children_cache ( ) ;
2021-08-25 13:49:30 +00:00
if ( p_include_internal ) {
2023-04-03 20:31:47 +00:00
return data . children_cache . size ( ) ;
2021-08-25 13:49:30 +00:00
} else {
2023-04-03 20:31:47 +00:00
return data . children_cache . size ( ) - data . internal_children_front_count_cache - data . internal_children_back_count_cache ;
2021-08-25 13:49:30 +00:00
}
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2023-04-03 20:31:47 +00:00
_update_children_cache ( ) ;
2021-08-25 13:49:30 +00:00
if ( p_include_internal ) {
if ( p_index < 0 ) {
2023-04-03 20:31:47 +00:00
p_index + = data . children_cache . size ( ) ;
2021-08-25 13:49:30 +00:00
}
2023-04-03 20:31:47 +00:00
ERR_FAIL_INDEX_V ( p_index , ( int ) data . children_cache . size ( ) , nullptr ) ;
return data . children_cache [ p_index ] ;
2021-08-25 13:49:30 +00:00
} else {
if ( p_index < 0 ) {
2023-04-03 20:31:47 +00:00
p_index + = ( int ) data . children_cache . size ( ) - data . internal_children_front_count_cache - data . internal_children_back_count_cache ;
2021-08-25 13:49:30 +00:00
}
2023-04-03 20:31:47 +00:00
ERR_FAIL_INDEX_V ( p_index , ( int ) data . children_cache . size ( ) - data . internal_children_front_count_cache - data . internal_children_back_count_cache , nullptr ) ;
p_index + = data . internal_children_front_count_cache ;
return data . children_cache [ p_index ] ;
2020-08-25 12:46:33 +00:00
}
2014-02-10 01:10:30 +00:00
}
2022-11-08 02:27:50 +00:00
TypedArray < Node > Node : : get_children ( bool p_include_internal ) const {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( TypedArray < Node > ( ) ) ;
2022-11-08 02:27:50 +00:00
TypedArray < Node > arr ;
int cc = get_child_count ( p_include_internal ) ;
arr . resize ( cc ) ;
for ( int i = 0 ; i < cc ; i + + ) {
arr [ i ] = get_child ( i , p_include_internal ) ;
}
return arr ;
}
2017-03-05 15:44:50 +00:00
Node * Node : : _get_child_by_name ( const StringName & p_name ) const {
2023-04-03 20:31:47 +00:00
const Node * const * node = data . children . getptr ( p_name ) ;
if ( node ) {
return const_cast < Node * > ( * node ) ;
} else {
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( nullptr ) ;
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 ;
2023-04-03 20:31:47 +00:00
const Node * const * node = current - > data . children . getptr ( name ) ;
if ( node ) {
next = const_cast < Node * > ( * node ) ;
} else {
2020-04-01 23:20:12 +00:00
return nullptr ;
2023-04-03 20:31:47 +00:00
}
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 ) ) {
2023-06-05 17:57:33 +00:00
const String desc = get_description ( ) ;
2022-01-19 10:33:27 +00:00
if ( p_path . is_absolute ( ) ) {
ERR_FAIL_V_MSG ( nullptr ,
2022-10-16 02:42:09 +00:00
vformat ( R " (Node not found: " % s " (absolute path attempted from " % s " ).) " , p_path , desc ) ) ;
2022-01-19 10:33:27 +00:00
} else {
ERR_FAIL_V_MSG ( nullptr ,
2022-10-16 02:42:09 +00:00
vformat ( R " (Node not found: " % s " (relative to " % s " ).) " , p_path , desc ) ) ;
2022-01-19 10:33:27 +00:00
}
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2022-04-25 13:16:44 +00:00
ERR_FAIL_COND_V ( p_pattern . is_empty ( ) , nullptr ) ;
2023-04-03 20:31:47 +00:00
_update_children_cache ( ) ;
Node * const * cptr = data . children_cache . ptr ( ) ;
int ccount = data . children_cache . size ( ) ;
2022-04-25 13:16:44 +00:00
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( TypedArray < Node > ( ) ) ;
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 ) ;
2023-04-03 20:31:47 +00:00
_update_children_cache ( ) ;
Node * const * cptr = data . children_cache . ptr ( ) ;
int ccount = data . children_cache . 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 ( ) ) {
2022-09-29 09:53:28 +00:00
Ref < Script > scr = cptr [ i ] - > get_script_instance ( ) - > get_script ( ) ;
while ( scr . is_valid ( ) ) {
if ( ( ScriptServer : : is_global_class ( p_type ) & & ScriptServer : : get_global_class_path ( p_type ) = = scr - > get_path ( ) ) | | p_type = = scr - > get_path ( ) ) {
2021-12-17 18:04:35 +00:00
ret . append ( cptr [ i ] ) ;
break ;
}
2022-09-29 09:53:28 +00:00
scr = scr - > get_base_script ( ) ;
2021-12-17 18:04:35 +00:00
}
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
}
2020-02-17 17:29:14 +00:00
void Node : : reparent ( Node * p_parent , bool p_keep_global_transform ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2020-02-17 17:29:14 +00:00
ERR_FAIL_NULL ( p_parent ) ;
ERR_FAIL_NULL_MSG ( data . parent , " Node needs a parent to be reparented. " ) ;
if ( p_parent = = data . parent ) {
return ;
}
data . parent - > remove_child ( this ) ;
p_parent - > add_child ( this ) ;
}
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( nullptr ) ;
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
}
2023-01-10 07:40:44 +00:00
Window * Node : : get_window ( ) const {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2023-01-10 07:40:44 +00:00
Viewport * vp = get_viewport ( ) ;
if ( vp ) {
return vp - > get_base_window ( ) ;
}
return nullptr ;
}
2023-04-20 13:13:21 +00:00
Window * Node : : get_last_exclusive_window ( ) const {
Window * w = get_window ( ) ;
while ( w & & w - > get_exclusive_child ( ) ) {
w = w - > get_exclusive_child ( ) ;
}
return w ;
}
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 ) ;
2016-03-08 23:00:52 +00:00
2023-04-03 20:31:47 +00:00
_update_children_cache ( ) ;
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
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 ) ;
2023-04-03 20:31:47 +00:00
this_stack [ idx - - ] = n - > get_index ( ) ;
2017-03-05 15:44:50 +00:00
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2023-04-03 20:31:47 +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 ) ;
2023-04-03 20:31:47 +00:00
that_stack [ idx - - ] = n - > get_index ( ) ;
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
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > 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 ) {
2023-04-10 16:45:53 +00:00
ERR_MAIN_THREAD_GUARD
2022-04-16 10:23:32 +00:00
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 ) {
2023-04-10 16:45:53 +00:00
ERR_MAIN_THREAD_GUARD
2014-02-10 01:10:30 +00:00
if ( data . owner ) {
2023-02-27 08:16:51 +00:00
_clean_up_owner ( ) ;
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
}
2023-02-27 08:16:51 +00:00
void Node : : _clean_up_owner ( ) {
ERR_FAIL_NULL ( data . owner ) ; // Sanity check.
if ( data . unique_name_in_owner ) {
_release_unique_name_in_owner ( ) ;
}
data . owner - > data . owned . erase ( data . OW ) ;
data . owner = nullptr ;
data . OW = nullptr ;
}
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
}
2022-11-18 22:23:38 +00:00
NodePath Node : : get_path_to ( const Node * p_node , bool p_use_unique_path ) 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
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL_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 ;
2022-11-18 22:23:38 +00:00
StringName up = String ( " .. " ) ;
2016-03-08 23:00:52 +00:00
2022-11-18 22:23:38 +00:00
if ( p_use_unique_path ) {
n = p_node ;
2016-03-08 23:00:52 +00:00
2022-11-18 22:23:38 +00:00
bool is_detected = false ;
while ( n ! = common_parent ) {
if ( n - > is_unique_name_in_owner ( ) & & n - > get_owner ( ) = = get_owner ( ) ) {
path . push_back ( UNIQUE_NODE_PREFIX + String ( n - > get_name ( ) ) ) ;
is_detected = true ;
break ;
}
path . push_back ( n - > get_name ( ) ) ;
n = n - > data . parent ;
}
2016-03-08 23:00:52 +00:00
2022-11-18 22:23:38 +00:00
if ( ! is_detected ) {
n = this ;
2016-03-08 23:00:52 +00:00
2022-11-18 22:23:38 +00:00
String detected_name ;
int up_count = 0 ;
while ( n ! = common_parent ) {
if ( n - > is_unique_name_in_owner ( ) & & n - > get_owner ( ) = = get_owner ( ) ) {
detected_name = n - > get_name ( ) ;
up_count = 0 ;
}
up_count + + ;
n = n - > data . parent ;
}
for ( int i = 0 ; i < up_count ; i + + ) {
path . push_back ( up ) ;
}
if ( ! detected_name . is_empty ( ) ) {
path . push_back ( UNIQUE_NODE_PREFIX + detected_name ) ;
}
}
} else {
n = p_node ;
while ( n ! = common_parent ) {
path . push_back ( n - > get_name ( ) ) ;
n = n - > data . parent ;
}
n = this ;
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( false ) ;
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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
2022-11-12 15:01:17 +00:00
if ( ! E ) {
return ;
}
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
}
2022-08-05 18:35:08 +00:00
TypedArray < StringName > Node : : _get_groups ( ) const {
TypedArray < StringName > groups ;
2014-06-16 13:22:26 +00:00
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( 0 ) ;
2019-08-16 20:30:31 +00:00
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 ( ) ) ) ;
2023-04-03 20:31:47 +00:00
_update_children_cache ( ) ;
for ( uint32_t i = 0 ; i < data . children_cache . size ( ) ; i + + ) {
2018-02-28 09:12:06 +00:00
new_prefix = last ? String : : utf8 ( " " ) : String : : utf8 ( " ┃ " ) ;
2023-04-03 20:31:47 +00:00
data . children_cache [ i ] - > _print_tree_pretty ( prefix + new_prefix , i = = data . children_cache . size ( ) - 1 ) ;
2018-02-28 09:12:06 +00:00
}
}
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 ) ) ) ;
2023-04-03 20:31:47 +00:00
_update_children_cache ( ) ;
for ( uint32_t i = 0 ; i < data . children_cache . size ( ) ; i + + ) {
data . children_cache [ 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 + + ;
2023-04-03 20:31:47 +00:00
for ( HashMap < StringName , Node * > : : Iterator I = data . children . last ( ) ; I ; - - I ) {
I - > value - > _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
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > 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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2017-08-19 13:17:06 +00:00
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
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > propagate_call ( p_method , p_args , p_parent_first ) ;
2017-08-19 13:17:06 +00:00
}
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 + + ;
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _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
}
2020-09-05 01:05:30 +00:00
Ref < Tween > Node : : create_tween ( ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( Ref < Tween > ( ) ) ;
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL_V_MSG ( data . tree , nullptr , " Can't create Tween when not inside scene tree. " ) ;
2020-09-05 01:05:30 +00:00
Ref < Tween > tween = get_tree ( ) - > create_tween ( ) ;
tween - > bind_node ( this ) ;
return tween ;
}
2021-09-30 14:30:55 +00:00
void Node : : set_scene_file_path ( const String & p_scene_file_path ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2021-09-30 14:30:55 +00:00
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2022-09-22 16:29:11 +00:00
if ( data . editor_description = = p_editor_description ) {
return ;
}
2021-02-18 18:52:29 +00:00
data . editor_description = p_editor_description ;
2022-09-22 16:29:11 +00:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) & & is_inside_tree ( ) ) {
// Update tree so the tooltip in the Scene tree dock is also updated in the editor.
get_tree ( ) - > tree_changed ( ) ;
}
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2021-02-21 08:19:48 +00:00
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2021-10-26 19:12:25 +00:00
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 ;
}
2023-03-17 00:58:30 +00:00
bool Node : : is_part_of_edited_scene ( ) const {
return Engine : : get_singleton ( ) - > is_editor_hint ( ) & & is_inside_tree ( ) & & get_tree ( ) - > get_edited_scene_root ( ) & &
( get_tree ( ) - > get_edited_scene_root ( ) = = this | | get_tree ( ) - > get_edited_scene_root ( ) - > is_ancestor_of ( this ) ) ;
}
2021-10-26 19:12:25 +00:00
# endif
2022-05-19 15:00:06 +00:00
void Node : : get_storable_properties ( HashSet < StringName > & r_storable_properties ) const {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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 ( ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( String ( ) ) ;
2021-07-11 14:40:18 +00:00
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2017-03-05 15:44:50 +00:00
data . instance_state = p_state ;
2015-10-10 12:09:09 +00:00
}
2017-03-05 15:44:50 +00:00
Ref < SceneState > Node : : get_scene_instance_state ( ) const {
2015-10-10 12:09:09 +00:00
return data . instance_state ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_scene_inherited_state ( const Ref < SceneState > & p_state ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
2017-03-05 15:44:50 +00:00
data . inherited_state = p_state ;
2015-10-10 12:09:09 +00:00
}
2017-03-05 15:44:50 +00:00
Ref < SceneState > Node : : get_scene_inherited_state ( ) const {
2015-10-10 12:09:09 +00:00
return data . inherited_state ;
}
2015-10-16 22:11:23 +00:00
void Node : : set_scene_instance_load_placeholder ( bool p_enable ) {
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( nullptr ) ;
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
2022-11-15 23:13:39 +00:00
} else if ( ( p_flags & DUPLICATE_USE_INSTANTIATION ) & & ! 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 ) ;
2023-02-01 09:49:05 +00:00
PackedScene : : GenEditState edit_state = PackedScene : : GEN_EDIT_STATE_DISABLED ;
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 ) {
2023-02-01 09:49:05 +00:00
edit_state = PackedScene : : GEN_EDIT_STATE_INSTANCE ;
2020-05-14 14:41:43 +00:00
}
2017-11-19 13:32:10 +00:00
# endif
2023-02-01 09:49:05 +00:00
node = res - > instantiate ( edit_state ) ;
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL_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 ( ) ) ;
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL_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
}
2023-06-06 12:59:54 +00:00
ERR_FAIL_NULL_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 ;
2022-09-29 09:53:28 +00:00
Variant scr = N - > get ( ) - > get ( script_property_name , & is_valid ) ;
2017-10-13 22:03:33 +00:00
if ( is_valid ) {
2022-09-29 09:53:28 +00:00
current_node - > set ( script_property_name , scr ) ;
2017-10-13 22:03:33 +00:00
}
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
2023-01-10 06:04:35 +00:00
if ( E . usage & PROPERTY_USAGE_ALWAYS_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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2017-11-19 12:05:18 +00:00
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 {
2022-11-15 23:13:39 +00:00
Node * dupe = _duplicate ( DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR , & r_duplimap ) ;
2017-11-19 13:32:10 +00:00
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 ) ) {
2022-07-28 20:56:41 +00:00
copy - > connect ( E . signal . get_name ( ) , copy_callable , 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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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
}
2023-02-27 08:16:51 +00:00
_clean_up_owner ( ) ;
2014-02-10 01:10:30 +00:00
}
Node * parent = data . parent ;
2023-04-03 20:31:47 +00:00
int index_in_parent = get_index ( ) ;
2014-02-10 01:10:30 +00:00
if ( data . parent ) {
parent - > remove_child ( this ) ;
parent - > add_child ( p_node ) ;
2022-10-14 18:21:41 +00:00
parent - > move_child ( p_node , index_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 ( ) ) ) ;
2022-07-28 20:56:41 +00:00
c . signal . get_object ( ) - > connect ( c . signal . get_name ( ) , Callable ( p_new_target , c . callable . get_method ( ) ) , 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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( false ) ;
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 {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( nullptr ) ;
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
2023-03-09 15:47:38 +00:00
static HashMap < ObjectID , List < String > > _print_orphan_nodes_map ;
static void _print_orphan_nodes_routine ( 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
}
2023-03-09 15:47:38 +00:00
List < String > info_strings ;
info_strings . push_back ( path ) ;
info_strings . push_back ( n - > get_class ( ) ) ;
_print_orphan_nodes_map [ p_obj - > get_instance_id ( ) ] = info_strings ;
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 ( ) {
2014-02-10 01:10:30 +00:00
# ifdef DEBUG_ENABLED
2023-03-09 15:47:38 +00:00
// Make sure it's empty.
_print_orphan_nodes_map . clear ( ) ;
// Collect and print information about orphan nodes.
ObjectDB : : debug_objects ( _print_orphan_nodes_routine ) ;
for ( const KeyValue < ObjectID , List < String > > & E : _print_orphan_nodes_map ) {
print_line ( itos ( E . key ) + " - Stray Node: " + E . value [ 0 ] + " (Type: " + E . value [ 1 ] + " ) " ) ;
}
// Flush it after use.
_print_orphan_nodes_map . clear ( ) ;
2014-02-10 01:10:30 +00:00
# endif
}
2022-10-24 21:07:02 +00:00
void Node : : queue_free ( ) {
2022-10-25 01:31:56 +00:00
// There are users which instantiate multiple scene trees for their games.
// Use the node's own tree to handle its deletion when relevant.
2017-09-20 19:49:46 +00:00
if ( is_inside_tree ( ) ) {
get_tree ( ) - > queue_delete ( this ) ;
} else {
2022-10-25 01:31:56 +00:00
SceneTree * tree = SceneTree : : get_singleton ( ) ;
ERR_FAIL_NULL_MSG ( tree , " Can't queue free a node when no SceneTree is available. " ) ;
tree - > queue_delete ( this ) ;
2017-09-20 19:49:46 +00:00
}
2014-02-10 01:10:30 +00:00
}
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 ( ) ;
2023-04-03 20:31:47 +00:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > clear_internal_tree_resource_paths ( ) ;
2015-06-22 03:03:19 +00:00
}
}
2022-09-19 15:43:15 +00:00
PackedStringArray Node : : get_configuration_warnings ( ) const {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD_V ( PackedStringArray ( ) ) ;
2022-09-19 15:43:15 +00:00
PackedStringArray ret ;
2022-04-16 10:23:32 +00:00
2021-08-22 15:37:22 +00:00
Vector < String > warnings ;
if ( GDVIRTUAL_CALL ( _get_configuration_warnings , warnings ) ) {
2022-09-19 15:43:15 +00:00
ret . append_array ( warnings ) ;
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 {
2022-09-19 15:43:15 +00:00
PackedStringArray warnings = get_configuration_warnings ( ) ;
2022-11-14 17:21:06 +00:00
String all_warnings ;
2020-10-29 10:01:28 +00:00
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.
2022-09-19 15:43:15 +00:00
all_warnings + = String : : utf8 ( " • " ) + warnings [ i ] ;
2020-10-29 10:01:28 +00:00
}
return all_warnings ;
}
void Node : : update_configuration_warnings ( ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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 ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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 ;
}
2023-04-06 12:47:49 +00:00
bool Node : : is_ready ( ) const {
return ! data . ready_first ;
}
2017-01-10 21:02:19 +00:00
void Node : : request_ready ( ) {
2023-04-10 16:45:53 +00:00
ERR_THREAD_GUARD
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 ) {
2022-11-28 21:54:47 +00:00
if ( p_event - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL ) {
GDVIRTUAL_CALL ( _input , p_event ) ;
}
2021-08-22 15:37:22 +00:00
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 ) {
2022-11-28 21:54:47 +00:00
if ( p_event - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL ) {
GDVIRTUAL_CALL ( _shortcut_input , p_event ) ;
}
2022-01-11 13:59:52 +00:00
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 ) {
2022-11-28 21:54:47 +00:00
if ( p_event - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL ) {
GDVIRTUAL_CALL ( _unhandled_input , p_event ) ;
}
2021-08-22 15:37:22 +00:00
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 ) {
2022-11-28 21:54:47 +00:00
if ( p_event - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL ) {
GDVIRTUAL_CALL ( _unhandled_key_input , p_event ) ;
}
2021-08-22 15:37:22 +00:00
if ( ! is_inside_tree ( ) | | ! get_viewport ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
return ;
}
unhandled_key_input ( p_event ) ;
}
2023-04-10 16:45:53 +00:00
void Node : : _validate_property ( PropertyInfo & p_property ) const {
if ( ( p_property . name = = " process_thread_group_order " | | p_property . name = = " process_thread_messages " ) & & data . process_thread_group = = PROCESS_THREAD_GROUP_INHERIT ) {
p_property . usage = 0 ;
}
}
2021-08-22 15:37:22 +00:00
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 ) {
}
2023-04-10 16:45:53 +00:00
Variant Node : : _call_deferred_thread_group_bind ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
if ( p_argcount < 1 ) {
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 0 ;
return Variant ( ) ;
}
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING_NAME & & p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : STRING_NAME ;
return Variant ( ) ;
}
r_error . error = Callable : : CallError : : CALL_OK ;
StringName method = * p_args [ 0 ] ;
call_deferred_thread_groupp ( method , & p_args [ 1 ] , p_argcount - 1 , true ) ;
return Variant ( ) ;
}
Variant Node : : _call_thread_safe_bind ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
if ( p_argcount < 1 ) {
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
r_error . argument = 0 ;
return Variant ( ) ;
}
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING_NAME & & p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING ) {
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_error . argument = 0 ;
r_error . expected = Variant : : STRING_NAME ;
return Variant ( ) ;
}
r_error . error = Callable : : CallError : : CALL_OK ;
StringName method = * p_args [ 0 ] ;
call_thread_safep ( method , & p_args [ 1 ] , p_argcount - 1 , true ) ;
return Variant ( ) ;
}
void Node : : call_deferred_thread_groupp ( const StringName & p_method , const Variant * * p_args , int p_argcount , bool p_show_error ) {
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
SceneTree : : ProcessGroup * pg = ( SceneTree : : ProcessGroup * ) data . process_group ;
pg - > call_queue . push_callp ( this , p_method , p_args , p_argcount , p_show_error ) ;
}
void Node : : set_deferred_thread_group ( const StringName & p_property , const Variant & p_value ) {
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
SceneTree : : ProcessGroup * pg = ( SceneTree : : ProcessGroup * ) data . process_group ;
pg - > call_queue . push_set ( this , p_property , p_value ) ;
}
void Node : : notify_deferred_thread_group ( int p_notification ) {
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
SceneTree : : ProcessGroup * pg = ( SceneTree : : ProcessGroup * ) data . process_group ;
pg - > call_queue . push_notification ( this , p_notification ) ;
}
void Node : : call_thread_safep ( const StringName & p_method , const Variant * * p_args , int p_argcount , bool p_show_error ) {
if ( is_accessible_from_caller_thread ( ) ) {
Callable : : CallError ce ;
callp ( p_method , p_args , p_argcount , ce ) ;
if ( p_show_error & & ce . error ! = Callable : : CallError : : CALL_OK ) {
ERR_FAIL_MSG ( " Error calling method from 'call_threadp': " + Variant : : get_call_error_text ( this , p_method , p_args , p_argcount , ce ) + " . " ) ;
}
} else {
call_deferred_thread_groupp ( p_method , p_args , p_argcount , p_show_error ) ;
}
}
void Node : : set_thread_safe ( const StringName & p_property , const Variant & p_value ) {
if ( is_accessible_from_caller_thread ( ) ) {
set ( p_property , p_value ) ;
} else {
set_deferred_thread_group ( p_property , p_value ) ;
}
}
void Node : : notify_thread_safe ( int p_notification ) {
if ( is_accessible_from_caller_thread ( ) ) {
notification ( p_notification ) ;
} else {
notify_deferred_thread_group ( p_notification ) ;
}
}
2014-02-10 01:10:30 +00:00
void Node : : _bind_methods ( ) {
2023-01-12 08:41:13 +00:00
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " editor/naming/node_name_num_separator " , PROPERTY_HINT_ENUM , " None,Space,Underscore,Dash " ) , 0 ) ;
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " editor/naming/node_name_casing " , PROPERTY_HINT_ENUM , " PascalCase,camelCase,snake_case " ) , NAME_CASING_PASCAL_CASE ) ;
2016-10-07 18:25:29 +00:00
2022-11-12 15:54:06 +00:00
ClassDB : : bind_static_method ( " Node " , D_METHOD ( " print_orphan_nodes " ) , & Node : : print_orphan_nodes ) ;
2022-08-15 17:55:38 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_sibling " , " sibling " , " force_readable_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 ) ;
2022-08-15 17:55:38 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_child " , " node " , " force_readable_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 ) ;
2020-02-17 17:29:14 +00:00
ClassDB : : bind_method ( D_METHOD ( " reparent " , " new_parent " , " keep_global_transform " ) , & Node : : reparent , DEFVAL ( true ) ) ;
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.
2022-11-08 02:27:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_children " , " include_internal " ) , & Node : : get_children , DEFVAL ( false ) ) ;
2021-08-25 13:49:30 +00:00
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 ) ;
2022-11-18 22:23:38 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_path_to " , " node " , " use_unique_path " ) , & Node : : get_path_to , DEFVAL ( false ) ) ;
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 ) ;
2022-10-14 18:21:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " move_child " , " child_node " , " to_index " ) , & Node : : move_child ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_groups " ) , & Node : : _get_groups ) ;
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 ) ;
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 ) ;
2023-04-10 16:45:53 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_physics_process_priority " , " priority " ) , & Node : : set_physics_process_priority ) ;
ClassDB : : bind_method ( D_METHOD ( " get_physics_process_priority " ) , & Node : : get_physics_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 ) ;
2019-04-11 17:35:23 +00:00
2023-04-10 16:45:53 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_process_thread_group " , " mode " ) , & Node : : set_process_thread_group ) ;
ClassDB : : bind_method ( D_METHOD ( " get_process_thread_group " ) , & Node : : get_process_thread_group ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process_thread_messages " , " flags " ) , & Node : : set_process_thread_messages ) ;
ClassDB : : bind_method ( D_METHOD ( " get_process_thread_messages " ) , & Node : : get_process_thread_messages ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process_thread_group_order " , " order " ) , & Node : : set_process_thread_group_order ) ;
ClassDB : : bind_method ( D_METHOD ( " get_process_thread_group_order " ) , & Node : : get_process_thread_group_order ) ;
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
2023-01-10 07:40:44 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_window " ) , & Node : : get_window ) ;
2023-04-20 13:13:21 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_last_exclusive_window " ) , & Node : : get_last_exclusive_window ) ;
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
2022-11-15 23:13:39 +00:00
ClassDB : : bind_method ( D_METHOD ( " duplicate " , " flags " ) , & Node : : duplicate , DEFVAL ( DUPLICATE_USE_INSTANTIATION | 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
2022-10-24 21:07:02 +00:00
ClassDB : : bind_method ( D_METHOD ( " queue_free " ) , & Node : : queue_free ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " request_ready " ) , & Node : : request_ready ) ;
2023-04-06 12:47:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_node_ready " ) , & Node : : is_ready ) ;
2017-03-05 15:44:50 +00:00
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 ) ;
2022-07-12 21:12:42 +00:00
ClassDB : : bind_method ( D_METHOD ( " rpc_config " , " method " , " config " ) , & Node : : rpc_config ) ;
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
2023-04-10 16:45:53 +00:00
{
MethodInfo mi ;
mi . name = " call_deferred_thread_group " ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " method " ) ) ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " call_deferred_thread_group " , & Node : : _call_deferred_thread_group_bind , mi , varray ( ) , false ) ;
}
ClassDB : : bind_method ( D_METHOD ( " set_deferred_thread_group " , " property " , " value " ) , & Node : : set_deferred_thread_group ) ;
ClassDB : : bind_method ( D_METHOD ( " notify_deferred_thread_group " , " what " ) , & Node : : notify_deferred_thread_group ) ;
{
MethodInfo mi ;
mi . name = " call_thread_safe " ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " method " ) ) ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " call_thread_safe " , & Node : : _call_thread_safe_bind , mi , varray ( ) , false ) ;
}
ClassDB : : bind_method ( D_METHOD ( " set_thread_safe " , " property " , " value " ) , & Node : : set_thread_safe ) ;
ClassDB : : bind_method ( D_METHOD ( " notify_thread_safe " , " what " ) , & Node : : notify_thread_safe ) ;
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 ) ;
2022-08-14 22:50:31 +00:00
BIND_CONSTANT ( NOTIFICATION_SCENE_INSTANTIATED ) ;
2017-03-05 15:44:50 +00:00
BIND_CONSTANT ( NOTIFICATION_DRAG_BEGIN ) ;
BIND_CONSTANT ( NOTIFICATION_DRAG_END ) ;
2021-09-03 22:12:37 +00:00
BIND_CONSTANT ( NOTIFICATION_PATH_RENAMED ) ;
2023-04-05 16:53:32 +00:00
BIND_CONSTANT ( NOTIFICATION_CHILD_ORDER_CHANGED ) ;
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 ) ;
2022-01-30 21:31:32 +00:00
BIND_CONSTANT ( NOTIFICATION_NODE_RECACHE_REQUESTED ) ;
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
2023-04-10 16:45:53 +00:00
BIND_ENUM_CONSTANT ( PROCESS_THREAD_GROUP_INHERIT ) ;
BIND_ENUM_CONSTANT ( PROCESS_THREAD_GROUP_MAIN_THREAD ) ;
BIND_ENUM_CONSTANT ( PROCESS_THREAD_GROUP_SUB_THREAD ) ;
BIND_ENUM_CONSTANT ( FLAG_PROCESS_THREAD_MESSAGES ) ;
BIND_ENUM_CONSTANT ( FLAG_PROCESS_THREAD_MESSAGES_PHYSICS ) ;
BIND_ENUM_CONSTANT ( FLAG_PROCESS_THREAD_MESSAGES_ALL ) ;
2017-08-20 15:45:01 +00:00
BIND_ENUM_CONSTANT ( DUPLICATE_SIGNALS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_GROUPS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_SCRIPTS ) ;
2022-11-15 23:13:39 +00:00
BIND_ENUM_CONSTANT ( DUPLICATE_USE_INSTANTIATION ) ;
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 " ) ) ) ;
2023-04-05 16:53:32 +00:00
ADD_SIGNAL ( MethodInfo ( " child_order_changed " ) ) ;
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 " ) ;
2023-04-10 16:45:53 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " process_physics_priority " ) , " set_physics_process_priority " , " get_physics_process_priority " ) ;
ADD_SUBGROUP ( " Thread Group " , " process_thread " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " process_thread_group " , PROPERTY_HINT_ENUM , " Inherit,Main Thread,Sub Thread " ) , " set_process_thread_group " , " get_process_thread_group " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " process_thread_group_order " ) , " set_process_thread_group_order " , " get_process_thread_group_order " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " process_thread_messages " , PROPERTY_HINT_FLAGS , " Process,Physics Process " ) , " set_process_thread_messages " , " get_process_thread_messages " ) ;
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 ( ) {
2023-01-12 08:41:13 +00:00
switch ( GLOBAL_GET ( " editor/naming/node_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 ( ) ;
2023-04-03 20:31:47 +00:00
data . children_cache . clear ( ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( data . parent ) ;
2023-04-03 20:31:47 +00:00
ERR_FAIL_COND ( data . children_cache . 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
////////////////////////////////
2023-05-12 11:53:15 +00:00
// Multithreaded locked version of Object functions.
# ifdef DEBUG_ENABLED
void Node : : set_script ( const Variant & p_script ) {
ERR_THREAD_GUARD ;
Object : : set_script ( p_script ) ;
}
Variant Node : : get_script ( ) const {
ERR_THREAD_GUARD_V ( Variant ( ) ) ;
return Object : : get_script ( ) ;
}
bool Node : : has_meta ( const StringName & p_name ) const {
ERR_THREAD_GUARD_V ( false ) ;
return Object : : has_meta ( p_name ) ;
}
void Node : : set_meta ( const StringName & p_name , const Variant & p_value ) {
ERR_THREAD_GUARD ;
Object : : set_meta ( p_name , p_value ) ;
}
void Node : : remove_meta ( const StringName & p_name ) {
ERR_THREAD_GUARD ;
Object : : remove_meta ( p_name ) ;
}
Variant Node : : get_meta ( const StringName & p_name , const Variant & p_default ) const {
ERR_THREAD_GUARD_V ( Variant ( ) ) ;
return Object : : get_meta ( p_name , p_default ) ;
}
void Node : : get_meta_list ( List < StringName > * p_list ) const {
ERR_THREAD_GUARD ;
Object : : get_meta_list ( p_list ) ;
}
Error Node : : emit_signalp ( const StringName & p_name , const Variant * * p_args , int p_argcount ) {
ERR_THREAD_GUARD_V ( ERR_INVALID_PARAMETER ) ;
return Object : : emit_signalp ( p_name , p_args , p_argcount ) ;
}
bool Node : : has_signal ( const StringName & p_name ) const {
ERR_THREAD_GUARD_V ( false ) ;
return Object : : has_signal ( p_name ) ;
}
void Node : : get_signal_list ( List < MethodInfo > * p_signals ) const {
ERR_THREAD_GUARD ;
Object : : get_signal_list ( p_signals ) ;
}
void Node : : get_signal_connection_list ( const StringName & p_signal , List < Connection > * p_connections ) const {
ERR_THREAD_GUARD ;
Object : : get_signal_connection_list ( p_signal , p_connections ) ;
}
void Node : : get_all_signal_connections ( List < Connection > * p_connections ) const {
ERR_THREAD_GUARD ;
Object : : get_all_signal_connections ( p_connections ) ;
}
int Node : : get_persistent_signal_connection_count ( ) const {
ERR_THREAD_GUARD_V ( 0 ) ;
return Object : : get_persistent_signal_connection_count ( ) ;
}
void Node : : get_signals_connected_to_this ( List < Connection > * p_connections ) const {
ERR_THREAD_GUARD ;
Object : : get_signals_connected_to_this ( p_connections ) ;
}
Error Node : : connect ( const StringName & p_signal , const Callable & p_callable , uint32_t p_flags ) {
ERR_THREAD_GUARD_V ( ERR_INVALID_PARAMETER ) ;
return Object : : connect ( p_signal , p_callable , p_flags ) ;
}
void Node : : disconnect ( const StringName & p_signal , const Callable & p_callable ) {
ERR_THREAD_GUARD ;
Object : : disconnect ( p_signal , p_callable ) ;
}
bool Node : : is_connected ( const StringName & p_signal , const Callable & p_callable ) const {
ERR_THREAD_GUARD_V ( false ) ;
return Object : : is_connected ( p_signal , p_callable ) ;
}
# endif