2014-02-09 22:10:30 -03: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-05 00:50:27 +01:00
2014-02-09 22:10:30 -03:00
# include "node.h"
2023-04-28 15:59:00 -05:00
# include "node.compat.inc"
2017-08-27 21:07:15 +02:00
2022-02-12 02:46:22 +01:00
# include "core/config/project_settings.h"
2018-09-11 18:13:45 +02:00
# include "core/io/resource_loader.h"
2020-11-07 19:33:38 -03:00
# include "core/object/message_queue.h"
2023-09-06 21:02:52 +02:00
# include "core/object/script_language.h"
2020-11-07 19:33:38 -03:00
# include "core/string/print_string.h"
2014-02-09 22:10:30 -03:00
# include "instance_placeholder.h"
2020-09-05 03:05:30 +02:00
# include "scene/animation/tween.h"
2020-02-07 02:52:05 +01:00
# include "scene/debugger/scene_debugger.h"
2022-07-12 23:12:42 +02:00
# include "scene/main/multiplayer_api.h"
2023-01-10 09:40:44 +02:00
# include "scene/main/window.h"
2014-02-09 22:10:30 -03:00
# include "scene/resources/packed_scene.h"
2014-04-10 00:18:27 -03:00
# include "viewport.h"
2014-02-09 22:10:30 -03:00
2019-04-17 22:46:21 +02:00
int Node : : orphan_node_count = 0 ;
2023-04-10 18:45:53 +02:00
thread_local Node * Node : : current_process_thread_group = nullptr ;
2014-02-09 22:10:30 -03:00
void Node : : _notification ( int p_notification ) {
switch ( p_notification ) {
2025-03-21 16:42:23 +02:00
case NOTIFICATION_ACCESSIBILITY_INVALIDATE : {
if ( data . accessibility_element . is_valid ( ) ) {
DisplayServer : : get_singleton ( ) - > accessibility_free_element ( data . accessibility_element ) ;
data . accessibility_element = RID ( ) ;
}
} break ;
case NOTIFICATION_ACCESSIBILITY_UPDATE : {
RID ae = get_accessibility_element ( ) ;
ERR_FAIL_COND ( ae . is_null ( ) ) ;
2025-05-21 09:34:12 +03:00
DisplayServer : : get_singleton ( ) - > accessibility_update_set_name ( ae , get_name ( ) ) ;
2025-03-21 16:42:23 +02:00
// Node children.
if ( ! accessibility_override_tree_hierarchy ( ) ) {
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
Node * child_node = get_child ( i ) ;
Window * child_wnd = Object : : cast_to < Window > ( child_node ) ;
if ( child_wnd & & ! child_wnd - > is_embedded ( ) ) {
continue ;
}
if ( child_node - > is_part_of_edited_scene ( ) ) {
continue ;
}
DisplayServer : : get_singleton ( ) - > accessibility_update_add_child ( ae , child_node - > get_accessibility_element ( ) ) ;
}
}
} break ;
2014-02-09 22:10:30 -03:00
case NOTIFICATION_PROCESS : {
2021-08-21 22:52:44 -03:00
GDVIRTUAL_CALL ( _process , get_process_delta_time ( ) ) ;
2014-02-09 22:10:30 -03:00
} break ;
2022-02-15 18:06:48 +01:00
2017-09-30 16:19:07 +02:00
case NOTIFICATION_PHYSICS_PROCESS : {
2021-08-26 10:49:12 -07:00
GDVIRTUAL_CALL ( _physics_process , get_physics_process_delta_time ( ) ) ;
2014-02-09 22:10:30 -03:00
} break ;
2022-02-15 18:06:48 +01:00
2014-11-05 21:20:42 -03:00
case NOTIFICATION_ENTER_TREE : {
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL ( get_viewport ( ) ) ;
2025-05-28 15:24:49 +02:00
ERR_FAIL_NULL ( data . tree ) ;
2014-02-09 22:10:30 -03:00
2025-05-28 15:24:49 +02:00
if ( data . tree - > is_accessibility_supported ( ) & & ! is_part_of_edited_scene ( ) ) {
data . tree - > _accessibility_force_update ( ) ;
data . tree - > _accessibility_notify_change ( this ) ;
2025-03-21 16:42:23 +02:00
if ( data . parent ) {
2025-05-28 15:24:49 +02:00
data . tree - > _accessibility_notify_change ( data . parent ) ;
2025-03-21 16:42:23 +02:00
} else {
2025-05-28 15:24:49 +02:00
data . tree - > _accessibility_notify_change ( get_window ( ) ) ; // Root node.
2025-03-21 16:42:23 +02:00
}
}
2023-04-10 18:45:53 +02:00
// Update process mode.
2021-02-18 15:52:29 -03:00
if ( data . process_mode = = PROCESS_MODE_INHERIT ) {
2020-05-14 16:41:43 +02:00
if ( data . parent ) {
2021-02-18 15:52:29 -03:00
data . process_owner = data . parent - > data . process_owner ;
2020-05-14 16:41:43 +02:00
} else {
2021-06-21 17:49:34 -07: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 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
} else {
2021-02-18 15:52:29 -03:00
data . process_owner = this ;
2014-02-09 22:10:30 -03:00
}
2023-04-10 18:45:53 +02: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 ( ) ;
}
}
2024-02-17 00:57:32 +01:00
if ( data . physics_interpolation_mode = = PHYSICS_INTERPOLATION_MODE_INHERIT ) {
bool interpolate = true ; // Root node default is for interpolation to be on.
if ( data . parent ) {
interpolate = data . parent - > is_physics_interpolated ( ) ;
}
_propagate_physics_interpolated ( interpolate ) ;
}
2024-01-23 18:29:45 -03:00
// Update auto translate mode.
if ( data . auto_translate_mode = = AUTO_TRANSLATE_MODE_INHERIT & & ! data . parent ) {
ERR_PRINT ( " The root node can't be set to Inherit auto translate mode, reverting to Always instead. " ) ;
data . auto_translate_mode = AUTO_TRANSLATE_MODE_ALWAYS ;
}
data . is_auto_translate_dirty = true ;
2024-08-16 17:25:24 +08:00
data . is_translation_domain_dirty = true ;
2024-01-23 18:29:45 -03:00
2020-05-14 16:41:43 +02:00
if ( data . input ) {
2017-08-07 17:17:31 +07:00
add_to_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
}
2022-01-11 15:59:52 +02:00
if ( data . shortcut_input ) {
add_to_group ( " _vp_shortcut_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
}
2020-05-14 16:41:43 +02:00
if ( data . unhandled_input ) {
2017-08-07 17:17:31 +07:00
add_to_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
}
if ( data . unhandled_key_input ) {
2017-08-07 17:17:31 +07:00
add_to_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-04-10 00:18:27 -03:00
2025-05-28 15:24:49 +02:00
data . tree - > nodes_in_tree_count + + ;
2019-04-17 22:46:21 +02:00
orphan_node_count - - ;
2024-05-26 19:39:28 +02:00
2014-02-09 22:10:30 -03:00
} break ;
2022-02-15 18:06:48 +01:00
2024-11-22 17:42:58 +01:00
case NOTIFICATION_POST_ENTER_TREE : {
if ( data . auto_translate_mode ! = AUTO_TRANSLATE_MODE_DISABLED ) {
notification ( NOTIFICATION_TRANSLATION_CHANGED ) ;
}
} break ;
2014-11-05 21:20:42 -03:00
case NOTIFICATION_EXIT_TREE : {
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL ( get_viewport ( ) ) ;
2025-05-28 15:24:49 +02:00
ERR_FAIL_NULL ( data . tree ) ;
2014-02-09 22:10:30 -03:00
2025-05-28 15:24:49 +02:00
if ( data . tree - > is_accessibility_supported ( ) & & ! is_part_of_edited_scene ( ) ) {
2025-03-21 16:42:23 +02:00
if ( data . accessibility_element . is_valid ( ) ) {
DisplayServer : : get_singleton ( ) - > accessibility_free_element ( data . accessibility_element ) ;
data . accessibility_element = RID ( ) ;
}
2025-05-28 15:24:49 +02:00
data . tree - > _accessibility_notify_change ( this , true ) ;
2025-03-21 16:42:23 +02:00
if ( data . parent ) {
2025-05-28 15:24:49 +02:00
data . tree - > _accessibility_notify_change ( data . parent ) ;
2025-03-21 16:42:23 +02:00
} else {
2025-05-28 15:24:49 +02:00
data . tree - > _accessibility_notify_change ( get_window ( ) ) ; // Root node.
2025-03-21 16:42:23 +02:00
}
}
2025-05-28 15:24:49 +02:00
data . tree - > nodes_in_tree_count - - ;
2019-04-17 22:46:21 +02:00
orphan_node_count + + ;
2020-05-14 16:41:43 +02:00
if ( data . input ) {
2017-08-07 17:17:31 +07:00
remove_from_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
}
2022-01-11 15:59:52 +02:00
if ( data . shortcut_input ) {
remove_from_group ( " _vp_shortcut_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
}
2020-05-14 16:41:43 +02:00
if ( data . unhandled_input ) {
2017-08-07 17:17:31 +07:00
remove_from_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
}
if ( data . unhandled_key_input ) {
2017-08-07 17:17:31 +07:00
remove_from_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
}
2016-08-14 18:49:50 -03:00
2024-01-23 18:29:45 -03:00
// Remove from processing first.
2023-04-10 18:45:53 +02:00
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
}
2024-01-23 18:29:45 -03:00
// Remove the process group.
2023-04-10 18:45:53 +02:00
if ( data . process_thread_group_owner = = this ) {
_remove_process_group ( ) ;
}
data . process_thread_group_owner = nullptr ;
2021-02-18 15:52:29 -03:00
data . process_owner = nullptr ;
2023-04-10 18:45:53 +02:00
2016-08-14 18:49:50 -03:00
if ( data . path_cache ) {
memdelete ( data . path_cache ) ;
2020-04-02 01:20:12 +02:00
data . path_cache = nullptr ;
2016-08-14 18:49:50 -03:00
}
} break ;
2022-02-15 18:06:48 +01:00
2024-09-18 18:07:18 -03:00
case NOTIFICATION_SUSPENDED :
2024-07-07 16:48:17 +02:00
case NOTIFICATION_PAUSED : {
if ( is_physics_interpolated_and_enabled ( ) & & is_inside_tree ( ) ) {
reset_physics_interpolation ( ) ;
}
} break ;
2021-09-04 00:12:37 +02:00
case NOTIFICATION_PATH_RENAMED : {
2016-08-14 18:49:50 -03:00
if ( data . path_cache ) {
memdelete ( data . path_cache ) ;
2020-04-02 01:20:12 +02:00
data . path_cache = nullptr ;
2016-08-14 18:49:50 -03:00
}
2014-02-09 22:10:30 -03:00
} break ;
2022-02-15 18:06:48 +01:00
2014-02-09 22:10:30 -03:00
case NOTIFICATION_READY : {
2021-09-04 12:14:51 +03:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _input ) ) {
set_process_input ( true ) ;
}
2017-01-10 18:02:19 -03:00
2022-01-11 15:59:52 +02:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _shortcut_input ) ) {
set_process_shortcut_input ( true ) ;
}
2021-09-04 12:14:51 +03:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _unhandled_input ) ) {
set_process_unhandled_input ( true ) ;
}
2017-01-10 18:02:19 -03:00
2021-09-04 12:14:51 +03:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _unhandled_key_input ) ) {
set_process_unhandled_key_input ( true ) ;
}
2017-01-10 18:02:19 -03:00
2021-09-04 12:14:51 +03:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _process ) ) {
set_process ( true ) ;
2014-02-09 22:10:30 -03:00
}
2021-09-04 12:14:51 +03:00
if ( GDVIRTUAL_IS_OVERRIDDEN ( _physics_process ) ) {
set_physics_process ( true ) ;
}
GDVIRTUAL_CALL ( _ready ) ;
2014-02-09 22:10:30 -03:00
} break ;
2022-02-15 18:06:48 +01:00
2014-02-09 22:10:30 -03:00
case NOTIFICATION_PREDELETE : {
2025-05-28 15:24:49 +02:00
if ( data . tree & & ! Thread : : is_main_thread ( ) ) {
2023-04-10 18:45:53 +02:00
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 16:16:51 +08:00
if ( data . owner ) {
_clean_up_owner ( ) ;
}
2023-07-03 21:18:12 +02:00
while ( ! data . owned . is_empty ( ) ) {
Node * n = data . owned . back ( ) - > get ( ) ;
n - > _clean_up_owner ( ) ; // This will change data.owned. So it's impossible to loop over the list in the usual manner.
}
2014-02-09 22:10:30 -03:00
if ( data . parent ) {
data . parent - > remove_child ( this ) ;
}
// kill children as cleanly as possible
while ( data . children . size ( ) ) {
2023-04-03 22:31:47 +02:00
Node * child = data . children . last ( ) - > value ; // begin from the end because its faster and more consistent with creation
2014-02-09 22:10:30 -03:00
memdelete ( child ) ;
}
} break ;
2024-01-23 18:29:45 -03:00
case NOTIFICATION_TRANSLATION_CHANGED : {
2025-05-28 15:24:49 +02:00
if ( data . tree ) {
2024-01-23 18:29:45 -03:00
data . is_auto_translate_dirty = true ;
}
} break ;
2014-02-09 22:10:30 -03:00
}
}
void Node : : _propagate_ready ( ) {
2016-11-30 00:07:29 +01:00
data . ready_notified = true ;
2014-02-09 22:10:30 -03:00
data . blocked + + ;
2023-04-03 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _propagate_ready ( ) ;
2014-02-09 22:10:30 -03:00
}
2023-04-03 22:31:47 +02:00
2014-02-09 22:10:30 -03:00
data . blocked - - ;
2018-05-15 17:12:35 -03:00
notification ( NOTIFICATION_POST_ENTER_TREE ) ;
2017-01-10 18:02:19 -03:00
if ( data . ready_first ) {
data . ready_first = false ;
2017-12-14 08:59:46 -03:00
notification ( NOTIFICATION_READY ) ;
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( ready ) ) ;
2017-01-10 18:02:19 -03:00
}
2014-02-09 22:10:30 -03:00
}
2014-11-05 21:20:42 -03:00
void Node : : _propagate_enter_tree ( ) {
2018-01-18 21:37:17 +01:00
// this needs to happen to all children before any enter_tree
2014-02-09 22:10:30 -03:00
if ( data . parent ) {
2014-11-05 21:20:42 -03:00
data . tree = data . parent - > data . tree ;
2014-02-09 22:10:30 -03:00
data . depth = data . parent - > data . depth + 1 ;
} else {
data . depth = 1 ;
}
2016-03-09 00:00:52 +01:00
2017-08-24 22:58:51 +02:00
data . viewport = Object : : cast_to < Viewport > ( this ) ;
2020-05-14 16:41:43 +02:00
if ( ! data . viewport & & data . parent ) {
2014-04-10 00:18:27 -03:00
data . viewport = data . parent - > data . viewport ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2021-08-09 14:13:42 -06:00
for ( KeyValue < StringName , GroupData > & E : data . grouped ) {
E . value . group = data . tree - > add_to_group ( E . key , this ) ;
2014-02-09 22:10:30 -03:00
}
2014-11-05 21:20:42 -03:00
notification ( NOTIFICATION_ENTER_TREE ) ;
2014-02-09 22:10:30 -03:00
2021-08-21 22:52:44 -03:00
GDVIRTUAL_CALL ( _enter_tree ) ;
2014-02-09 22:10:30 -03:00
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( tree_entered ) ) ;
2014-02-09 22:10:30 -03:00
2017-10-18 19:30:27 -05:00
data . tree - > node_added ( this ) ;
2022-02-02 11:22:11 +01:00
if ( data . parent ) {
Variant c = this ;
const Variant * cptr = & c ;
2022-03-09 14:58:40 +01:00
data . parent - > emit_signalp ( SNAME ( " child_entered_tree " ) , & cptr , 1 ) ;
2022-02-02 11:22:11 +01:00
}
2014-02-09 22:10:30 -03:00
data . blocked + + ;
//block while adding children
2023-04-03 22:31:47 +02: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 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
}
2014-02-09 22:10:30 -03:00
data . blocked - - ;
2015-08-02 12:29:37 -03:00
# ifdef DEBUG_ENABLED
2021-09-30 16:30:55 +02:00
SceneDebugger : : add_to_cache ( data . scene_file_path , this ) ;
2015-08-02 12:29:37 -03:00
# endif
2014-02-09 22:10:30 -03:00
// enter groups
}
2018-09-07 15:31:19 -03:00
void Node : : _propagate_after_exit_tree ( ) {
2022-01-05 14:00:04 +01:00
// Clear owner if it was not part of the pruned branch
2021-12-01 14:28:59 +01:00
if ( data . owner ) {
2025-04-13 13:43:57 +08:00
if ( ! data . owner - > is_ancestor_of ( this ) ) {
2023-02-27 16:16:51 +08:00
_clean_up_owner ( ) ;
2022-01-05 14:00:04 +01:00
}
2021-12-01 14:28:59 +01:00
}
2022-01-05 14:00:04 +01:00
2018-09-07 15:31:19 -03:00
data . blocked + + ;
2023-04-03 22:31:47 +02:00
for ( HashMap < StringName , Node * > : : Iterator I = data . children . last ( ) ; I ; - - I ) {
I - > value - > _propagate_after_exit_tree ( ) ;
2018-09-07 15:31:19 -03:00
}
2023-04-03 22:31:47 +02:00
2018-09-07 15:31:19 -03:00
data . blocked - - ;
2022-01-05 14:00:04 +01:00
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( tree_exited ) ) ;
2018-09-07 15:31:19 -03:00
}
2014-11-05 21:20:42 -03:00
void Node : : _propagate_exit_tree ( ) {
2018-08-21 21:28:06 +02:00
//block while removing children
2014-02-09 22:10:30 -03:00
2015-08-02 12:29:37 -03:00
# ifdef DEBUG_ENABLED
2023-01-07 12:12:24 +01: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 12:29:37 -03:00
# endif
2014-02-09 22:10:30 -03:00
data . blocked + + ;
2023-04-03 22:31:47 +02:00
for ( HashMap < StringName , Node * > : : Iterator I = data . children . last ( ) ; I ; - - I ) {
I - > value - > _propagate_exit_tree ( ) ;
2014-02-09 22:10:30 -03:00
}
data . blocked - - ;
2021-08-21 22:52:44 -03:00
GDVIRTUAL_CALL ( _exit_tree ) ;
2023-09-04 17:01:33 +02:00
emit_signal ( SceneStringName ( tree_exiting ) ) ;
2014-02-09 22:10:30 -03:00
2014-11-05 21:20:42 -03:00
notification ( NOTIFICATION_EXIT_TREE , true ) ;
2020-05-14 16:41:43 +02:00
if ( data . tree ) {
2014-11-05 21:20:42 -03:00
data . tree - > node_removed ( this ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2022-02-02 11:22:11 +01:00
if ( data . parent ) {
Variant c = this ;
const Variant * cptr = & c ;
2022-06-20 09:53:44 +02:00
data . parent - > emit_signalp ( SNAME ( " child_exiting_tree " ) , & cptr , 1 ) ;
2022-02-02 11:22:11 +01:00
}
2014-02-09 22:10:30 -03:00
// exit groups
2021-08-09 14:13:42 -06:00
for ( KeyValue < StringName , GroupData > & E : data . grouped ) {
data . tree - > remove_from_group ( E . key , this ) ;
E . value . group = nullptr ;
2014-02-09 22:10:30 -03:00
}
2020-04-02 01:20:12 +02:00
data . viewport = nullptr ;
2014-04-10 00:18:27 -03:00
2020-05-14 16:41:43 +02:00
if ( data . tree ) {
2014-11-05 21:20:42 -03:00
data . tree - > tree_changed ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2017-01-10 18:02:19 -03:00
data . ready_notified = false ;
2020-04-02 01:20:12 +02:00
data . tree = nullptr ;
2014-02-09 22:10:30 -03:00
data . depth = - 1 ;
}
2024-02-17 00:57:32 +01:00
void Node : : _propagate_physics_interpolated ( bool p_interpolated ) {
switch ( data . physics_interpolation_mode ) {
case PHYSICS_INTERPOLATION_MODE_INHERIT :
// Keep the parent p_interpolated.
break ;
case PHYSICS_INTERPOLATION_MODE_OFF : {
p_interpolated = false ;
} break ;
case PHYSICS_INTERPOLATION_MODE_ON : {
p_interpolated = true ;
} break ;
}
// No change? No need to propagate further.
if ( data . physics_interpolated = = p_interpolated ) {
return ;
}
data . physics_interpolated = p_interpolated ;
// Allow a call to the RenderingServer etc. in derived classes.
_physics_interpolated_changed ( ) ;
2025-03-03 11:01:49 +00:00
update_configuration_warnings ( ) ;
2024-02-17 00:57:32 +01:00
data . blocked + + ;
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _propagate_physics_interpolated ( p_interpolated ) ;
}
data . blocked - - ;
}
2024-05-26 19:39:28 +02:00
void Node : : _propagate_physics_interpolation_reset_requested ( bool p_requested ) {
if ( is_physics_interpolated ( ) ) {
data . physics_interpolation_reset_requested = p_requested ;
}
data . blocked + + ;
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _propagate_physics_interpolation_reset_requested ( p_requested ) ;
}
data . blocked - - ;
}
2022-10-14 19:21:41 +01:00
void Node : : move_child ( Node * p_child , int p_index ) {
2025-05-28 15:24:49 +02:00
ERR_FAIL_COND_MSG ( data . 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-09 22:10:30 -03:00
ERR_FAIL_NULL ( p_child ) ;
2019-08-08 22:11:48 +02:00
ERR_FAIL_COND_MSG ( p_child - > data . parent ! = this , " Child is not a child of this node. " ) ;
2021-08-25 15:49:30 +02:00
2023-04-03 22:31:47 +02:00
_update_children_cache ( ) ;
2021-08-25 15:49:30 +02:00
// We need to check whether node is internal and move it only in the relevant node range.
2023-04-03 22:31:47 +02:00
if ( p_child - > data . internal_mode = = INTERNAL_MODE_FRONT ) {
2022-10-14 19:21:41 +01:00
if ( p_index < 0 ) {
2023-04-03 22:31:47 +02:00
p_index + = data . internal_children_front_count_cache ;
2022-09-10 03:54:04 +02:00
}
2023-04-03 22:31:47 +02: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 19:21:41 +01:00
_move_child ( p_child , p_index ) ;
2023-04-03 22:31:47 +02:00
} else if ( p_child - > data . internal_mode = = INTERNAL_MODE_BACK ) {
2022-10-14 19:21:41 +01:00
if ( p_index < 0 ) {
2023-04-03 22:31:47 +02:00
p_index + = data . internal_children_back_count_cache ;
2022-09-10 03:54:04 +02:00
}
2023-04-03 22:31:47 +02: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 15:49:30 +02:00
} else {
2022-10-14 19:21:41 +01:00
if ( p_index < 0 ) {
p_index + = get_child_count ( false ) ;
2022-09-10 03:54:04 +02:00
}
2023-04-03 22:31:47 +02: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 15:49:30 +02:00
}
}
2022-10-14 19:21:41 +01:00
void Node : : _move_child ( Node * p_child , int p_index , bool p_ignore_end ) {
2022-11-12 17:16:45 +01: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-13 22:46:18 -03:00
2017-07-25 05:11:00 +02:00
// Specifying one place beyond the end
2022-10-14 19:21:41 +01:00
// means the same as moving to the last index
2021-08-25 15:49:30 +02:00
if ( ! p_ignore_end ) { // p_ignore_end is a little hack to make back internal children work properly.
2023-04-03 22:31:47 +02:00
if ( p_child - > data . internal_mode = = INTERNAL_MODE_FRONT ) {
if ( p_index = = data . internal_children_front_count_cache ) {
2022-10-14 19:21:41 +01:00
p_index - - ;
2021-08-25 15:49:30 +02:00
}
2023-04-03 22:31:47 +02:00
} else if ( p_child - > data . internal_mode = = INTERNAL_MODE_BACK ) {
if ( p_index = = ( int ) data . children_cache . size ( ) ) {
2022-10-14 19:21:41 +01:00
p_index - - ;
2021-08-25 15:49:30 +02:00
}
} else {
2023-04-03 22:31:47 +02:00
if ( p_index = = ( int ) data . children_cache . size ( ) - data . internal_children_back_count_cache ) {
2022-10-14 19:21:41 +01:00
p_index - - ;
2021-08-25 15:49:30 +02:00
}
}
2020-05-14 16:41:43 +02:00
}
2017-07-25 05:11:00 +02:00
2023-04-03 22:31:47 +02:00
int child_index = p_child - > get_index ( ) ;
if ( child_index = = p_index ) {
2016-10-03 16:33:42 -03:00
return ; //do nothing
2020-05-14 16:41:43 +02:00
}
2016-10-03 16:33:42 -03:00
2023-04-03 22:31:47 +02:00
int motion_from = MIN ( p_index , child_index ) ;
int motion_to = MAX ( p_index , child_index ) ;
2016-10-03 16:33:42 -03:00
2023-04-03 22:31:47 +02:00
data . children_cache . remove_at ( child_index ) ;
data . children_cache . insert ( p_index , p_child ) ;
2014-02-09 22:10:30 -03:00
2014-11-05 21:20:42 -03:00
if ( data . tree ) {
data . tree - > tree_changed ( ) ;
2014-02-09 22:10:30 -03:00
}
data . blocked + + ;
//new pos first
2016-10-03 16:33:42 -03:00
for ( int i = motion_from ; i < = motion_to ; i + + ) {
2023-04-03 22:31:47 +02: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-09 22:10:30 -03:00
}
// notification second
2014-12-03 13:29:28 +08:00
move_child_notify ( p_child ) ;
2023-04-05 18:53:32 +02:00
notification ( NOTIFICATION_CHILD_ORDER_CHANGED ) ;
emit_signal ( SNAME ( " child_order_changed " ) ) ;
2022-05-31 21:28:04 +03:00
p_child - > _propagate_groups_dirty ( ) ;
2014-02-09 22:10:30 -03:00
data . blocked - - ;
}
2022-05-31 21:28:04 +03: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 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _propagate_groups_dirty ( ) ;
2022-05-31 21:28:04 +03:00
}
}
2014-02-09 22:10:30 -03:00
void Node : : add_child_notify ( Node * p_child ) {
2016-03-09 00:00:52 +01:00
// to be used when not wanted
2014-02-09 22:10:30 -03:00
}
void Node : : remove_child_notify ( Node * p_child ) {
2016-03-09 00:00:52 +01:00
// to be used when not wanted
2014-02-09 22:10:30 -03:00
}
2014-12-03 12:17:23 +08:00
void Node : : move_child_notify ( Node * p_child ) {
2016-03-09 00:00:52 +01:00
// to be used when not wanted
2014-12-03 12:17:23 +08:00
}
2022-06-23 08:19:18 +02:00
void Node : : owner_changed_notify ( ) {
}
2024-02-17 00:57:32 +01:00
void Node : : _physics_interpolated_changed ( ) { }
2017-09-30 16:19:07 +02:00
void Node : : set_physics_process ( bool p_process ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2020-05-14 16:41:43 +02:00
if ( data . physics_process = = p_process ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2023-04-10 18:45:53 +02:00
if ( ! is_inside_tree ( ) ) {
data . physics_process = p_process ;
return ;
}
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
}
2017-09-30 16:19:07 +02:00
data . physics_process = p_process ;
2016-03-09 00:00:52 +01:00
2023-04-10 18:45:53 +02:00
if ( _is_any_processing ( ) ) {
_add_to_process_thread_group ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
2017-09-30 16:19:07 +02:00
bool Node : : is_physics_processing ( ) const {
return data . physics_process ;
2017-01-10 18:02:19 -03:00
}
2017-09-30 16:19:07 +02:00
void Node : : set_physics_process_internal ( bool p_process_internal ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2020-05-14 16:41:43 +02:00
if ( data . physics_process_internal = = p_process_internal ) {
2017-01-10 18:02:19 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-01-10 18:02:19 -03:00
2023-04-10 18:45:53 +02: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 16:19:07 +02:00
data . physics_process_internal = p_process_internal ;
2017-01-10 18:02:19 -03:00
2023-04-10 18:45:53 +02:00
if ( _is_any_processing ( ) ) {
_add_to_process_thread_group ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-01-10 18:02:19 -03:00
}
2017-09-30 16:19:07 +02:00
bool Node : : is_physics_processing_internal ( ) const {
return data . physics_process_internal ;
2017-01-10 18:02:19 -03:00
}
2021-02-18 15:52:29 -03:00
void Node : : set_process_mode ( ProcessMode p_mode ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2021-02-18 15:52:29 -03:00
if ( data . process_mode = = p_mode ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2020-05-14 16:41:43 +02:00
if ( ! is_inside_tree ( ) ) {
2021-02-18 15:52:29 -03:00
data . process_mode = p_mode ;
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2021-02-18 15:52:29 -03:00
bool prev_can_process = can_process ( ) ;
2021-06-17 18:09:40 -07:00
bool prev_enabled = _is_enabled ( ) ;
2021-02-18 15:52:29 -03:00
2021-06-21 17:49:34 -07:00
if ( p_mode = = PROCESS_MODE_INHERIT ) {
2020-05-14 16:41:43 +02:00
if ( data . parent ) {
2021-06-21 17:49:34 -07:00
data . process_owner = data . parent - > data . process_owner ;
2021-02-18 15:52:29 -03:00
} else {
2021-06-21 17:49:34 -07:00
ERR_FAIL_MSG ( " The root node can't be set to Inherit process mode. " ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
} else {
2021-02-18 15:52:29 -03:00
data . process_owner = this ;
}
2021-06-21 17:49:34 -07:00
data . process_mode = p_mode ;
2021-02-18 15:52:29 -03:00
bool next_can_process = can_process ( ) ;
2021-06-17 18:09:40 -07:00
bool next_enabled = _is_enabled ( ) ;
2021-02-18 15:52:29 -03: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-17 18:09:40 -07: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 15:52:29 -03:00
# ifdef TOOLS_ENABLED
// This is required for the editor to update the visibility of disabled nodes
2021-03-12 19:05:16 +05:30
// It's very expensive during runtime to change, so editor-only
2021-02-18 15:52:29 -03:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2025-05-28 15:24:49 +02:00
data . tree - > emit_signal ( SNAME ( " tree_process_mode_changed " ) ) ;
2014-02-09 22:10:30 -03:00
}
2024-11-26 00:04:25 +01:00
_emit_editor_state_changed ( ) ;
2021-02-18 15:52:29 -03: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-09 22:10:30 -03:00
2021-02-18 15:52:29 -03:00
if ( prev_can_process & & ! next_can_process ) {
notification ( NOTIFICATION_PAUSED ) ;
} else if ( ! prev_can_process & & next_can_process ) {
notification ( NOTIFICATION_UNPAUSED ) ;
}
2023-06-24 22:15:50 +02:00
data . blocked + + ;
2023-04-03 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _propagate_pause_notification ( p_enable ) ;
2021-02-18 15:52:29 -03:00
}
2023-06-24 22:15:50 +02:00
data . blocked - - ;
2014-02-09 22:10:30 -03:00
}
2024-09-18 18:07:18 -03:00
void Node : : _propagate_suspend_notification ( bool p_enable ) {
notification ( p_enable ? NOTIFICATION_SUSPENDED : NOTIFICATION_UNSUSPENDED ) ;
data . blocked + + ;
for ( KeyValue < StringName , Node * > & KV : data . children ) {
KV . value - > _propagate_suspend_notification ( p_enable ) ;
}
data . blocked - - ;
}
2021-02-18 15:52:29 -03:00
Node : : ProcessMode Node : : get_process_mode ( ) const {
return data . process_mode ;
2014-02-09 22:10:30 -03:00
}
2021-06-17 18:09:40 -07:00
void Node : : _propagate_process_owner ( Node * p_owner , int p_pause_notification , int p_enabled_notification ) {
2021-02-18 15:52:29 -03:00
data . process_owner = p_owner ;
2021-06-17 18:09:40 -07:00
if ( p_pause_notification ! = 0 ) {
notification ( p_pause_notification ) ;
}
if ( p_enabled_notification ! = 0 ) {
notification ( p_enabled_notification ) ;
2020-05-14 16:41:43 +02:00
}
2021-02-18 15:52:29 -03:00
2023-06-24 22:15:50 +02:00
data . blocked + + ;
2023-04-03 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
Node * c = K . value ;
2021-02-18 15:52:29 -03:00
if ( c - > data . process_mode = = PROCESS_MODE_INHERIT ) {
2021-06-17 18:09:40 -07:00
c - > _propagate_process_owner ( p_owner , p_pause_notification , p_enabled_notification ) ;
2021-02-18 15:52:29 -03:00
}
2014-02-09 22:10:30 -03:00
}
2023-06-24 22:15:50 +02:00
data . blocked - - ;
2014-02-09 22:10:30 -03:00
}
2021-09-07 23:35:19 +02:00
void Node : : set_multiplayer_authority ( int p_peer_id , bool p_recursive ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2021-09-07 23:35:19 +02:00
data . multiplayer_authority = p_peer_id ;
2016-08-14 18:49:50 -03:00
2017-07-03 10:44:45 -03:00
if ( p_recursive ) {
2023-04-03 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > set_multiplayer_authority ( p_peer_id , true ) ;
2017-07-03 10:44:45 -03:00
}
2016-08-14 18:49:50 -03:00
}
}
2021-09-07 23:35:19 +02:00
int Node : : get_multiplayer_authority ( ) const {
return data . multiplayer_authority ;
2016-08-14 18:49:50 -03:00
}
2021-09-07 23:35:19 +02:00
bool Node : : is_multiplayer_authority ( ) const {
2016-08-14 18:49:50 -03:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , false ) ;
2023-07-11 12:40:53 +02:00
Ref < MultiplayerAPI > api = get_multiplayer ( ) ;
return api . is_valid ( ) & & ( api - > get_unique_id ( ) = = data . multiplayer_authority ) ;
2016-08-14 18:49:50 -03:00
}
2016-08-19 16:48:08 -03:00
/***** RPC CONFIG ********/
2016-08-14 18:49:50 -03:00
2022-07-12 23:12:42 +02:00
void Node : : rpc_config ( const StringName & p_method , const Variant & p_config ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2022-07-12 23:12:42 +02: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 11:51:50 +01:00
}
2022-07-12 23:12:42 +02:00
}
2025-05-26 15:57:38 +02:00
const Variant Node : : get_node_rpc_config ( ) const {
2022-07-12 23:12:42 +02:00
return data . rpc_config ;
2016-08-14 18:49:50 -03:00
}
2016-08-19 16:48:08 -03:00
/***** RPC FUNCTIONS ********/
2016-08-14 18:49:50 -03:00
2022-07-12 23:12:42 +02:00
Error Node : : _rpc_bind ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2016-08-19 16:48:08 -03:00
if ( p_argcount < 1 ) {
2020-02-19 16:27:19 -03:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2023-09-29 19:19:46 +03:00
r_error . expected = 1 ;
2022-07-12 23:12:42 +02:00
return ERR_INVALID_PARAMETER ;
2016-08-19 16:48:08 -03:00
}
2016-08-14 18:49:50 -03:00
2023-12-28 14:44:23 -08:00
if ( ! p_args [ 0 ] - > is_string ( ) ) {
2020-02-19 16:27:19 -03:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2016-08-19 16:48:08 -03:00
r_error . argument = 0 ;
2021-05-03 15:45:36 +02:00
r_error . expected = Variant : : STRING_NAME ;
2022-07-12 23:12:42 +02:00
return ERR_INVALID_PARAMETER ;
2016-08-19 16:48:08 -03:00
}
2016-08-14 18:49:50 -03:00
2022-02-09 14:27:16 +01:00
StringName method = ( * p_args [ 0 ] ) . operator StringName ( ) ;
2016-08-14 18:49:50 -03:00
2022-07-12 23:12:42 +02:00
Error err = rpcp ( 0 , method , & p_args [ 1 ] , p_argcount - 1 ) ;
2020-02-19 16:27:19 -03:00
r_error . error = Callable : : CallError : : CALL_OK ;
2022-07-12 23:12:42 +02:00
return err ;
2016-08-14 18:49:50 -03:00
}
2022-07-12 23:12:42 +02:00
Error Node : : _rpc_id_bind ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2016-08-19 16:48:08 -03:00
if ( p_argcount < 2 ) {
2020-02-19 16:27:19 -03:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2023-09-29 19:19:46 +03:00
r_error . expected = 2 ;
2022-07-12 23:12:42 +02:00
return ERR_INVALID_PARAMETER ;
2016-08-19 16:48:08 -03:00
}
2016-08-14 18:49:50 -03:00
2016-08-19 16:48:08 -03:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : INT ) {
2020-02-19 16:27:19 -03:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2016-08-19 16:48:08 -03:00
r_error . argument = 0 ;
r_error . expected = Variant : : INT ;
2022-07-12 23:12:42 +02:00
return ERR_INVALID_PARAMETER ;
2016-08-19 16:48:08 -03:00
}
2023-12-28 14:44:23 -08:00
if ( ! p_args [ 1 ] - > is_string ( ) ) {
2020-02-19 16:27:19 -03:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2016-08-19 16:48:08 -03:00
r_error . argument = 1 ;
2021-05-03 15:45:36 +02:00
r_error . expected = Variant : : STRING_NAME ;
2022-07-12 23:12:42 +02:00
return ERR_INVALID_PARAMETER ;
2016-08-19 16:48:08 -03:00
}
int peer_id = * p_args [ 0 ] ;
2022-02-09 14:27:16 +01:00
StringName method = ( * p_args [ 1 ] ) . operator StringName ( ) ;
2016-08-19 16:48:08 -03:00
2022-07-12 23:12:42 +02:00
Error err = rpcp ( peer_id , method , & p_args [ 2 ] , p_argcount - 2 ) ;
2020-02-19 16:27:19 -03:00
r_error . error = Callable : : CallError : : CALL_OK ;
2022-07-12 23:12:42 +02:00
return err ;
2016-08-19 16:48:08 -03:00
}
2022-07-12 23:12:42 +02: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 ) ;
2023-07-11 12:40:53 +02:00
Ref < MultiplayerAPI > api = get_multiplayer ( ) ;
if ( api . is_null ( ) ) {
return ERR_UNCONFIGURED ;
}
return api - > rpcp ( this , p_peer_id , p_method , p_arg , p_argcount ) ;
2016-08-19 16:48:08 -03:00
}
2018-05-08 10:51:04 +02:00
Ref < MultiplayerAPI > Node : : get_multiplayer ( ) const {
2020-05-14 16:41:43 +02:00
if ( ! is_inside_tree ( ) ) {
2018-03-03 18:30:11 +01:00
return Ref < MultiplayerAPI > ( ) ;
2020-05-14 16:41:43 +02:00
}
2025-05-28 15:24:49 +02:00
return data . tree - > get_multiplayer ( get_path ( ) ) ;
2018-03-03 18:30:11 +01:00
}
2021-05-26 14:07:57 +02:00
//////////// end of rpc
2016-08-19 16:48:08 -03:00
2018-07-29 21:20:41 -03:00
bool Node : : can_process_notification ( int p_what ) const {
switch ( p_what ) {
2020-05-10 13:00:47 +02: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 13:00:47 +02:00
case NOTIFICATION_INTERNAL_PROCESS :
2020-12-22 09:50:29 +00:00
return data . process_internal ;
2020-05-10 13:00:47 +02:00
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS :
return data . physics_process_internal ;
2018-07-29 21:20:41 -03:00
}
return true ;
}
2014-02-09 22:10:30 -03:00
bool Node : : can_process ( ) const {
2014-11-05 21:20:42 -03:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , false ) ;
2025-05-28 15:24:49 +02:00
return ! data . tree - > is_suspended ( ) & & _can_process ( data . tree - > is_paused ( ) ) ;
2021-02-18 15:52:29 -03:00
}
2014-02-09 22:10:30 -03:00
2021-02-18 15:52:29 -03:00
bool Node : : _can_process ( bool p_paused ) const {
ProcessMode process_mode ;
2014-02-09 22:10:30 -03:00
2021-02-18 15:52:29 -03: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-09 22:10:30 -03:00
}
2021-02-18 15:52:29 -03:00
} else {
process_mode = data . process_mode ;
2014-02-09 22:10:30 -03:00
}
2021-06-21 17:49:34 -07: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 15:52:29 -03: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-09 22:10:30 -03:00
}
2024-02-17 00:57:32 +01:00
void Node : : set_physics_interpolation_mode ( PhysicsInterpolationMode p_mode ) {
ERR_THREAD_GUARD
if ( data . physics_interpolation_mode = = p_mode ) {
return ;
}
data . physics_interpolation_mode = p_mode ;
bool interpolate = true ; // Default for root node.
switch ( p_mode ) {
case PHYSICS_INTERPOLATION_MODE_INHERIT : {
if ( is_inside_tree ( ) & & data . parent ) {
interpolate = data . parent - > is_physics_interpolated ( ) ;
}
} break ;
case PHYSICS_INTERPOLATION_MODE_OFF : {
interpolate = false ;
} break ;
case PHYSICS_INTERPOLATION_MODE_ON : {
interpolate = true ;
} break ;
}
2025-02-10 10:14:50 +00:00
_propagate_physics_interpolated ( interpolate ) ;
// Auto-reset on changing interpolation mode.
if ( is_physics_interpolated ( ) & & is_inside_tree ( ) ) {
2024-05-26 19:39:28 +02:00
propagate_notification ( NOTIFICATION_RESET_PHYSICS_INTERPOLATION ) ;
2024-02-17 00:57:32 +01:00
}
}
void Node : : reset_physics_interpolation ( ) {
2025-06-29 16:55:15 +01:00
if ( SceneTree : : is_fti_enabled ( ) & & is_inside_tree ( ) ) {
2024-05-26 19:39:28 +02:00
propagate_notification ( NOTIFICATION_RESET_PHYSICS_INTERPOLATION ) ;
// If `reset_physics_interpolation()` is called explicitly by the user
// (e.g. from scripts) then we prevent deferred auto-resets taking place.
// The user is trusted to call reset in the right order, and auto-reset
// will interfere with their control of prev / curr, so should be turned off.
_propagate_physics_interpolation_reset_requested ( false ) ;
}
2024-02-17 00:57:32 +01:00
}
2021-06-17 18:09:40 -07: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-01 21:16:37 -05:00
double Node : : get_physics_process_delta_time ( ) const {
2020-05-14 16:41:43 +02:00
if ( data . tree ) {
2017-09-30 16:19:07 +02:00
return data . tree - > get_physics_process_time ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-09 22:10:30 -03:00
return 0 ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
2021-02-01 21:16:37 -05:00
double Node : : get_process_delta_time ( ) const {
2020-05-14 16:41:43 +02:00
if ( data . tree ) {
2020-12-22 09:50:29 +00:00
return data . tree - > get_process_time ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2017-01-10 18:02:19 -03:00
return 0 ;
2020-05-14 16:41:43 +02:00
}
2017-01-10 18:02:19 -03:00
}
2020-12-22 09:50:29 +00:00
void Node : : set_process ( bool p_process ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2020-12-22 09:50:29 +00:00
if ( data . process = = p_process ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2023-04-10 18:45:53 +02: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-09 22:10:30 -03:00
2023-04-10 18:45:53 +02:00
if ( _is_any_processing ( ) ) {
_add_to_process_thread_group ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
2017-01-10 18:02:19 -03:00
bool Node : : is_processing ( ) const {
2020-12-22 09:50:29 +00:00
return data . process ;
2014-02-09 22:10:30 -03:00
}
2020-12-22 09:50:29 +00:00
void Node : : set_process_internal ( bool p_process_internal ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2020-12-22 09:50:29 +00:00
if ( data . process_internal = = p_process_internal ) {
2017-01-10 18:02:19 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-01-10 18:02:19 -03:00
2023-04-10 18:45:53 +02: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 18:02:19 -03:00
2023-04-10 18:45:53 +02:00
if ( _is_any_processing ( ) ) {
_add_to_process_thread_group ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
2023-04-10 18:45:53 +02:00
void Node : : _add_process_group ( ) {
2025-05-28 15:24:49 +02:00
data . tree - > _add_process_group ( this ) ;
2023-04-10 18:45:53 +02:00
}
void Node : : _remove_process_group ( ) {
2025-05-28 15:24:49 +02:00
data . tree - > _remove_process_group ( this ) ;
2023-04-10 18:45:53 +02:00
}
void Node : : _remove_from_process_thread_group ( ) {
2025-05-28 15:24:49 +02:00
data . tree - > _remove_node_from_process_group ( this , data . process_thread_group_owner ) ;
2023-04-10 18:45:53 +02:00
}
void Node : : _add_to_process_thread_group ( ) {
2025-05-28 15:24:49 +02:00
data . tree - > _add_node_to_process_group ( this , data . process_thread_group_owner ) ;
2023-04-10 18:45:53 +02:00
}
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 18:02:19 -03:00
bool Node : : is_processing_internal ( ) const {
2020-12-22 09:50:29 +00:00
return data . process_internal ;
2014-02-09 22:10:30 -03:00
}
2023-04-10 18:45:53 +02:00
void Node : : set_process_thread_group_order ( int p_order ) {
ERR_THREAD_GUARD
if ( data . process_thread_group_order = = p_order ) {
return ;
}
2023-06-27 12:48:14 +02:00
data . process_thread_group_order = p_order ;
// Not yet in the tree (or not a group owner, in whose case this is pointless but harmless); trivial update.
2023-04-10 18:45:53 +02:00
if ( ! is_inside_tree ( ) | | data . process_thread_group_owner ! = this ) {
return ;
}
2025-05-28 15:24:49 +02:00
data . tree - > process_groups_dirty = true ;
2023-04-10 18:45:53 +02:00
}
int Node : : get_process_thread_group_order ( ) const {
return data . process_thread_group_order ;
}
2018-07-02 07:30:40 +02:00
void Node : : set_process_priority ( int p_priority ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
if ( data . process_priority = = p_priority ) {
return ;
}
if ( ! is_inside_tree ( ) ) {
2023-06-27 12:48:14 +02:00
// Not yet in the tree; trivial update.
2023-04-10 18:45:53 +02:00
data . process_priority = p_priority ;
return ;
}
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
2023-09-26 17:57:45 +08:00
}
data . process_priority = p_priority ;
if ( _is_any_processing ( ) ) {
2023-04-10 18:45:53 +02:00
_add_to_process_thread_group ( ) ;
}
}
2018-07-02 07:30:40 +02:00
2023-04-10 18:45:53 +02: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 17:26:28 +01:00
return ;
}
2023-04-10 18:45:53 +02:00
if ( ! is_inside_tree ( ) ) {
2023-06-27 12:48:14 +02:00
// Not yet in the tree; trivial update.
2023-04-10 18:45:53 +02:00
data . physics_process_priority = p_priority ;
return ;
}
if ( _is_any_processing ( ) ) {
_remove_from_process_thread_group ( ) ;
2023-09-26 17:57:45 +08:00
}
data . physics_process_priority = p_priority ;
if ( _is_any_processing ( ) ) {
2023-04-10 18:45:53 +02:00
_add_to_process_thread_group ( ) ;
}
}
int Node : : get_physics_process_priority ( ) const {
return data . physics_process_priority ;
}
2019-06-22 15:52:51 +03:00
2023-04-10 18:45:53 +02:00
void Node : : set_process_thread_group ( ProcessThreadGroup p_mode ) {
2025-05-28 15:24:49 +02:00
ERR_FAIL_COND_MSG ( data . 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). " ) ;
2023-04-10 18:45:53 +02:00
if ( data . process_thread_group = = p_mode ) {
return ;
2019-11-21 17:26:28 +01:00
}
2018-07-02 07:30:40 +02:00
2023-04-10 18:45:53 +02:00
if ( ! is_inside_tree ( ) ) {
2023-06-27 12:48:14 +02:00
// Not yet in the tree; trivial update.
2023-04-10 18:45:53 +02:00
data . process_thread_group = p_mode ;
return ;
2019-11-21 17:26:28 +01:00
}
2018-07-02 07:30:40 +02:00
2023-04-10 18:45:53 +02:00
_remove_tree_from_process_thread_group ( ) ;
if ( data . process_thread_group ! = PROCESS_THREAD_GROUP_INHERIT ) {
_remove_process_group ( ) ;
2019-11-21 17:26:28 +01:00
}
2018-07-02 07:30:40 +02:00
2023-04-10 18:45:53 +02: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 17:26:28 +01:00
}
2023-04-10 18:45:53 +02:00
_add_tree_to_process_thread_group ( data . process_thread_group_owner ) ;
notify_property_list_changed ( ) ;
2018-07-02 07:30:40 +02:00
}
2023-04-10 18:45:53 +02: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
2023-06-27 12:48:14 +02:00
if ( data . process_thread_messages = = p_flags ) {
2023-04-10 18:45:53 +02:00
return ;
}
data . process_thread_messages = p_flags ;
}
BitField < Node : : ProcessThreadMessages > Node : : get_process_thread_messages ( ) const {
return data . process_thread_messages ;
2019-11-16 22:07:02 +01:00
}
2014-02-09 22:10:30 -03:00
void Node : : set_process_input ( bool p_enable ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2020-05-14 16:41:43 +02:00
if ( p_enable = = data . input ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-04-10 00:18:27 -03:00
2014-02-09 22:10:30 -03:00
data . input = p_enable ;
2020-05-14 16:41:43 +02:00
if ( ! is_inside_tree ( ) ) {
2014-04-10 00:18:27 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-04-10 00:18:27 -03:00
2020-05-14 16:41:43 +02:00
if ( p_enable ) {
2017-08-07 17:17:31 +07:00
add_to_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
} else {
2017-08-07 17:17:31 +07:00
remove_from_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
bool Node : : is_processing_input ( ) const {
return data . input ;
}
2022-01-11 15:59:52 +02:00
void Node : : set_process_shortcut_input ( bool p_enable ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2022-01-11 15:59:52 +02: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-09 22:10:30 -03:00
void Node : : set_process_unhandled_input ( bool p_enable ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2020-05-14 16:41:43 +02:00
if ( p_enable = = data . unhandled_input ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
data . unhandled_input = p_enable ;
2020-05-14 16:41:43 +02:00
if ( ! is_inside_tree ( ) ) {
2014-04-10 00:18:27 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2020-05-14 16:41:43 +02:00
if ( p_enable ) {
2017-08-07 17:17:31 +07:00
add_to_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
} else {
2017-08-07 17:17:31 +07:00
remove_from_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
bool Node : : is_processing_unhandled_input ( ) const {
return data . unhandled_input ;
}
2014-04-10 00:18:27 -03:00
void Node : : set_process_unhandled_key_input ( bool p_enable ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2020-05-14 16:41:43 +02:00
if ( p_enable = = data . unhandled_key_input ) {
2014-04-10 00:18:27 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-04-10 00:18:27 -03:00
data . unhandled_key_input = p_enable ;
2020-05-14 16:41:43 +02:00
if ( ! is_inside_tree ( ) ) {
2014-04-10 00:18:27 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-04-10 00:18:27 -03:00
2020-05-14 16:41:43 +02:00
if ( p_enable ) {
2017-08-07 17:17:31 +07:00
add_to_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
} else {
2017-08-07 17:17:31 +07:00
remove_from_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-04-10 00:18:27 -03:00
}
bool Node : : is_processing_unhandled_key_input ( ) const {
return data . unhandled_key_input ;
}
2024-01-23 18:29:45 -03:00
void Node : : set_auto_translate_mode ( AutoTranslateMode p_mode ) {
ERR_THREAD_GUARD
if ( data . auto_translate_mode = = p_mode ) {
return ;
}
2025-05-28 15:24:49 +02:00
if ( p_mode = = AUTO_TRANSLATE_MODE_INHERIT & & data . tree & & ! data . parent ) {
2024-01-23 18:29:45 -03:00
ERR_FAIL_MSG ( " The root node can't be set to Inherit auto translate mode. " ) ;
}
data . auto_translate_mode = p_mode ;
data . is_auto_translating = p_mode ! = AUTO_TRANSLATE_MODE_DISABLED ;
data . is_auto_translate_dirty = true ;
propagate_notification ( NOTIFICATION_TRANSLATION_CHANGED ) ;
}
Node : : AutoTranslateMode Node : : get_auto_translate_mode ( ) const {
return data . auto_translate_mode ;
}
bool Node : : can_auto_translate ( ) const {
ERR_READ_THREAD_GUARD_V ( false ) ;
if ( ! data . is_auto_translate_dirty | | data . auto_translate_mode ! = AUTO_TRANSLATE_MODE_INHERIT ) {
return data . is_auto_translating ;
}
data . is_auto_translate_dirty = false ;
Node * parent = data . parent ;
while ( parent ) {
if ( parent - > data . auto_translate_mode = = AUTO_TRANSLATE_MODE_INHERIT ) {
parent = parent - > data . parent ;
continue ;
}
data . is_auto_translating = parent - > data . auto_translate_mode = = AUTO_TRANSLATE_MODE_ALWAYS ;
break ;
}
return data . is_auto_translating ;
}
2024-08-16 17:25:24 +08:00
StringName Node : : get_translation_domain ( ) const {
ERR_READ_THREAD_GUARD_V ( StringName ( ) ) ;
if ( data . is_translation_domain_inherited & & data . is_translation_domain_dirty ) {
const_cast < Node * > ( this ) - > _translation_domain = data . parent ? data . parent - > get_translation_domain ( ) : StringName ( ) ;
data . is_translation_domain_dirty = false ;
}
return _translation_domain ;
}
void Node : : set_translation_domain ( const StringName & p_domain ) {
ERR_THREAD_GUARD
if ( ! data . is_translation_domain_inherited & & _translation_domain = = p_domain ) {
return ;
}
_translation_domain = p_domain ;
data . is_translation_domain_inherited = false ;
data . is_translation_domain_dirty = false ;
_propagate_translation_domain_dirty ( ) ;
}
void Node : : set_translation_domain_inherited ( ) {
ERR_THREAD_GUARD
if ( data . is_translation_domain_inherited ) {
return ;
}
data . is_translation_domain_inherited = true ;
data . is_translation_domain_dirty = true ;
_propagate_translation_domain_dirty ( ) ;
}
void Node : : _propagate_translation_domain_dirty ( ) {
for ( KeyValue < StringName , Node * > & K : data . children ) {
Node * child = K . value ;
if ( child - > data . is_translation_domain_inherited ) {
child - > data . is_translation_domain_dirty = true ;
child - > _propagate_translation_domain_dirty ( ) ;
}
}
2025-02-08 16:14:05 +01:00
if ( is_inside_tree ( ) & & data . auto_translate_mode ! = AUTO_TRANSLATE_MODE_DISABLED ) {
notification ( NOTIFICATION_TRANSLATION_CHANGED ) ;
}
2024-08-16 17:25:24 +08:00
}
2014-02-09 22:10:30 -03:00
StringName Node : : get_name ( ) const {
return data . name ;
}
void Node : : _set_name_nocheck ( const StringName & p_name ) {
2016-10-07 20:25:29 +02:00
data . name = p_name ;
2014-02-09 22:10:30 -03:00
}
2023-04-28 15:59:00 -05:00
void Node : : set_name ( const StringName & p_name ) {
2025-05-28 15:24:49 +02:00
ERR_FAIL_COND_MSG ( data . tree & & ! Thread : : is_main_thread ( ) , " Changing the name to nodes inside the SceneTree is only allowed from the main thread. Use `set_name.call_deferred(new_name)`. " ) ;
2023-04-28 15:59:00 -05:00
const StringName old_name = data . name ;
{
const String input_name_str = String ( p_name ) ;
ERR_FAIL_COND ( input_name_str . is_empty ( ) ) ;
const String validated_node_name_string = input_name_str . validate_node_name ( ) ;
if ( input_name_str = = validated_node_name_string ) {
data . name = p_name ;
} else {
data . name = StringName ( validated_node_name_string ) ;
}
}
2022-04-16 12:23:32 +02:00
if ( data . unique_name_in_owner & & data . owner ) {
_release_unique_name_in_owner ( ) ;
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
if ( data . parent ) {
2021-11-15 02:05:44 +01:00
data . parent - > _validate_child_name ( this , true ) ;
2023-06-26 10:10:25 +02:00
bool success = data . parent - > data . children . replace_key ( old_name , data . name ) ;
ERR_FAIL_COND_MSG ( ! success , " Renaming child in hashtable failed, this is a bug. " ) ;
2014-02-09 22:10:30 -03:00
}
2022-04-16 12:23:32 +02:00
if ( data . unique_name_in_owner & & data . owner ) {
_acquire_unique_name_in_owner ( ) ;
}
2021-09-04 00:12:37 +02:00
propagate_notification ( NOTIFICATION_PATH_RENAMED ) ;
2016-08-14 18:49:50 -03:00
2014-11-05 21:20:42 -03:00
if ( is_inside_tree ( ) ) {
2021-07-17 18:22:52 -03:00
emit_signal ( SNAME ( " renamed " ) ) ;
2025-05-28 15:24:49 +02:00
data . tree - > node_renamed ( this ) ;
data . tree - > tree_changed ( ) ;
2014-02-09 22:10:30 -03:00
}
}
2023-06-05 19:57:33 +02: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 ( ) ) {
2025-06-11 16:19:23 +02:00
description = String ( get_path ( ) ) ;
2023-06-05 19:57:33 +02:00
} else {
description = get_name ( ) ;
if ( description . is_empty ( ) ) {
description = get_class ( ) ;
}
}
return description ;
}
2014-02-22 20:28:19 -03:00
static SafeRefCount node_hrcr_count ;
void Node : : init_node_hrcr ( ) {
node_hrcr_count . init ( 1 ) ;
}
2016-10-07 20:25:29 +02:00
# ifdef TOOLS_ENABLED
String Node : : validate_child_name ( Node * p_child ) {
2019-01-10 18:52:47 -03:00
StringName name = p_child - > data . name ;
_generate_serial_child_name ( p_child , name ) ;
return name ;
2015-08-02 12:29:37 -03:00
}
2024-01-16 15:16:58 +01:00
String Node : : prevalidate_child_name ( Node * p_child , StringName p_name ) {
_generate_serial_child_name ( p_child , p_name ) ;
return p_name ;
}
2016-10-07 20:25:29 +02:00
# endif
2015-08-02 12:29:37 -03:00
2022-08-18 13:47:05 +02:00
String Node : : adjust_name_casing ( const String & p_name ) {
2023-01-12 11:41:13 +03:00
switch ( GLOBAL_GET ( " editor/naming/node_name_casing " ) . operator int ( ) ) {
2022-08-18 13:47:05 +02:00
case NAME_CASING_PASCAL_CASE :
2022-08-30 12:36:24 +03:00
return p_name . to_pascal_case ( ) ;
case NAME_CASING_CAMEL_CASE :
return p_name . to_camel_case ( ) ;
2022-08-18 13:47:05 +02:00
case NAME_CASING_SNAKE_CASE :
2022-08-30 12:36:24 +03:00
return p_name . to_snake_case ( ) ;
2024-07-28 21:32:28 +02:00
case NAME_CASING_KEBAB_CASE :
return p_name . to_kebab_case ( ) ;
2022-08-18 13:47:05 +02:00
}
return p_name ;
}
2015-12-08 11:21:12 -03:00
void Node : : _validate_child_name ( Node * p_child , bool p_force_human_readable ) {
2014-02-09 22:10:30 -03:00
/* Make sure the name is unique */
2021-10-21 16:46:07 +02:00
if ( p_force_human_readable ) {
2014-02-22 20:28:19 -03:00
//this approach to autoset node names is human readable but very slow
2019-01-10 18:52:47 -03:00
StringName name = p_child - > data . name ;
_generate_serial_child_name ( p_child , name ) ;
p_child - > data . name = name ;
2014-02-22 20:28:19 -03:00
} else {
//this approach to autoset node names is fast but not as readable
//it's the default and reserves the '@' character for unique names.
bool unique = true ;
2020-07-26 15:29:50 +02:00
if ( p_child - > data . name = = StringName ( ) ) {
2014-02-22 20:28:19 -03:00
//new unique name must be assigned
unique = false ;
} else {
2023-04-03 22:31:47 +02:00
const Node * const * existing = data . children . getptr ( p_child - > data . name ) ;
unique = ! existing | | * existing = = p_child ;
2014-02-22 20:28:19 -03:00
}
if ( ! unique ) {
2019-08-07 12:54:30 +02:00
ERR_FAIL_COND ( ! node_hrcr_count . ref ( ) ) ;
2023-04-06 17:54:56 +02: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-09 22:10:30 -03:00
}
}
}
2019-01-10 18:52:47 -03: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 20:25:29 +02:00
2019-01-10 18:52:47 -03:00
for ( int i = res . length ( ) - 1 ; i > = 0 ; i - - ) {
if ( ! carry ) {
break ;
}
2020-07-27 13:43:20 +03:00
char32_t n = s [ i ] ;
2019-01-10 18:52:47 -03: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 22:30:34 +02:00
// No name and a new name is needed, create one.
2016-10-07 20:25:29 +02:00
2017-01-02 23:03:46 -03:00
name = p_child - > get_class ( ) ;
2016-10-07 20:25:29 +02:00
}
2023-04-03 22:31:47 +02:00
const Node * const * existing = data . children . getptr ( name ) ;
if ( ! existing | | * existing = = p_child ) { // Unused, or is current node.
return ;
2019-01-10 18:52:47 -03:00
}
2016-10-10 13:06:13 +02:00
// Extract trailing number
2019-01-10 18:52:47 -03:00
String name_string = name ;
2016-10-07 20:25:29 +02:00
String nums ;
2019-01-10 18:52:47 -03:00
for ( int i = name_string . length ( ) - 1 ; i > = 0 ; i - - ) {
2020-07-27 13:43:20 +03:00
char32_t n = name_string [ i ] ;
2022-02-04 10:32:20 +02:00
if ( is_digit ( n ) ) {
2019-01-10 18:52:47 -03:00
nums = String : : chr ( name_string [ i ] ) + nums ;
2016-10-07 20:25:29 +02:00
} else {
break ;
}
}
String nnsep = _get_name_num_separator ( ) ;
2019-01-10 18:52:47 -03: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 23:02:07 +01:00
name_string = name_string . substr ( 0 , name_last_index + nnsep . length ( ) ) ;
2019-01-10 18:52:47 -03:00
} else {
nums = " " ;
2016-10-07 20:25:29 +02:00
}
for ( ; ; ) {
2019-01-10 18:52:47 -03:00
StringName attempt = name_string + nums ;
2023-04-03 22:31:47 +02:00
existing = data . children . getptr ( attempt ) ;
bool exists = existing ! = nullptr & & * existing ! = p_child ;
2019-01-10 18:52:47 -03:00
if ( ! exists ) {
name = attempt ;
return ;
2016-10-07 20:25:29 +02:00
} else {
2019-01-10 18:52:47 -03: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 13:06:13 +02:00
} else {
2019-01-10 18:52:47 -03:00
nums = increase_numeric_string ( nums ) ;
2016-10-10 13:06:13 +02:00
}
2016-10-07 20:25:29 +02:00
}
}
}
2023-06-29 00:46:11 +02:00
Node : : InternalMode Node : : get_internal_mode ( ) const {
return data . internal_mode ;
}
2023-04-03 22:31:47 +02:00
void Node : : _add_child_nocheck ( Node * p_child , const StringName & p_name , InternalMode p_internal_mode ) {
2014-02-09 22:10:30 -03:00
//add a child node quickly, without name validation
p_child - > data . name = p_name ;
2023-04-03 22:31:47 +02: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 ;
}
2014-02-09 22:10:30 -03:00
p_child - > data . parent = this ;
2021-08-25 15:49:30 +02:00
2023-04-03 22:31:47 +02: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 15:49:30 +02:00
}
2023-04-03 22:31:47 +02:00
2015-06-14 02:13:47 -03:00
p_child - > notification ( NOTIFICATION_PARENTED ) ;
2014-02-09 22:10:30 -03:00
2014-11-05 21:20:42 -03:00
if ( data . tree ) {
p_child - > _set_tree ( data . tree ) ;
2014-02-09 22:10:30 -03:00
}
/* Notify */
add_child_notify ( p_child ) ;
2023-04-05 18:53:32 +02:00
notification ( NOTIFICATION_CHILD_ORDER_CHANGED ) ;
emit_signal ( SNAME ( " child_order_changed " ) ) ;
2014-02-09 22:10:30 -03:00
}
2022-08-15 19:55:38 +02:00
void Node : : add_child ( Node * p_child , bool p_force_readable_name , InternalMode p_internal ) {
2025-05-28 15:24:49 +02:00
ERR_FAIL_COND_MSG ( data . 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). " ) ;
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2014-02-09 22:10:30 -03:00
ERR_FAIL_NULL ( p_child ) ;
2021-05-23 16:42:47 +02: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 16:02:50 -06: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 16:42:47 +02:00
# endif
2022-11-12 17:16:45 +01: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-09 00:00:52 +01:00
2022-08-15 19:55:38 +02:00
_validate_child_name ( p_child , p_force_readable_name ) ;
2023-07-03 21:18:12 +02:00
# ifdef DEBUG_ENABLED
if ( p_child - > data . owner & & ! p_child - > data . owner - > is_ancestor_of ( p_child ) ) {
// Owner of p_child should be ancestor of p_child.
WARN_PRINT ( vformat ( " Adding '%s' as child to '%s' will make owner '%s' inconsistent. Consider unsetting the owner beforehand. " , p_child - > get_name ( ) , get_name ( ) , p_child - > data . owner - > get_name ( ) ) ) ;
}
# endif // DEBUG_ENABLED
2023-04-03 22:31:47 +02:00
_add_child_nocheck ( p_child , p_child - > data . name , p_internal ) ;
2014-02-09 22:10:30 -03:00
}
2022-08-15 19:55:38 +02:00
void Node : : add_sibling ( Node * p_sibling , bool p_force_readable_name ) {
2025-05-28 15:24:49 +02:00
ERR_FAIL_COND_MSG ( data . 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 08:12:08 +02:00
ERR_FAIL_NULL ( p_sibling ) ;
2021-05-23 16:42:47 +02:00
ERR_FAIL_COND_MSG ( p_sibling = = this , vformat ( " Can't add sibling '%s' to itself. " , p_sibling - > get_name ( ) ) ) ; // adding to itself!
2023-06-29 20:21:37 +02:00
ERR_FAIL_NULL ( data . parent ) ;
ERR_FAIL_COND_MSG ( data . parent - > data . blocked > 0 , " Parent node is busy setting up children, `add_sibling()` failed. Consider using `add_sibling.call_deferred(sibling)` instead. " ) ;
2016-05-13 17:09:49 +01:00
2023-04-03 22:31:47 +02:00
data . parent - > add_child ( p_sibling , p_force_readable_name , data . internal_mode ) ;
data . parent - > _update_children_cache ( ) ;
2021-08-25 15:49:30 +02:00
data . parent - > _move_child ( p_sibling , get_index ( ) + 1 ) ;
2016-05-13 17:09:49 +01:00
}
2014-02-09 22:10:30 -03:00
void Node : : remove_child ( Node * p_child ) {
2025-05-28 15:24:49 +02:00
ERR_FAIL_COND_MSG ( data . 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-09 22:10:30 -03:00
ERR_FAIL_NULL ( p_child ) ;
2023-01-07 12:12:24 +01: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 22:31:47 +02: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-09 00:00:52 +01:00
2023-01-07 12:12:24 +01:00
data . blocked + + ;
2020-04-02 01:20:12 +02:00
p_child - > _set_tree ( nullptr ) ;
2016-03-09 00:00:52 +01:00
remove_child_notify ( p_child ) ;
2014-02-09 22:10:30 -03:00
p_child - > notification ( NOTIFICATION_UNPARENTED ) ;
2016-03-09 00:00:52 +01:00
2023-04-03 22:31:47 +02:00
data . blocked - - ;
2016-03-09 00:00:52 +01:00
2023-04-03 22:31:47 +02: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 20:47:57 +02:00
2020-04-02 01:20:12 +02:00
p_child - > data . parent = nullptr ;
2022-10-14 19:21:41 +01:00
p_child - > data . index = - 1 ;
2014-02-09 22:10:30 -03:00
2023-06-08 22:49:40 +02:00
notification ( NOTIFICATION_CHILD_ORDER_CHANGED ) ;
emit_signal ( SNAME ( " child_order_changed " ) ) ;
2025-05-28 15:24:49 +02:00
if ( data . tree ) {
2018-09-07 15:31:19 -03:00
p_child - > _propagate_after_exit_tree ( ) ;
}
2014-02-09 22:10:30 -03:00
}
2023-04-03 22:31:47 +02: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 15:49:30 +02:00
int Node : : get_child_count ( bool p_include_internal ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( 0 ) ;
2021-08-25 15:49:30 +02:00
if ( p_include_internal ) {
2025-05-10 01:57:12 +01:00
return data . children . size ( ) ;
2021-08-25 15:49:30 +02:00
}
2025-05-10 01:57:12 +01:00
_update_children_cache ( ) ;
return data . children_cache . size ( ) - data . internal_children_front_count_cache - data . internal_children_back_count_cache ;
2014-02-09 22:10:30 -03:00
}
2020-05-14 14:29:06 +02:00
2021-08-25 15:49:30 +02:00
Node * Node : : get_child ( int p_index , bool p_include_internal ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2023-04-03 22:31:47 +02:00
_update_children_cache ( ) ;
2021-08-25 15:49:30 +02:00
if ( p_include_internal ) {
if ( p_index < 0 ) {
2023-04-03 22:31:47 +02:00
p_index + = data . children_cache . size ( ) ;
2021-08-25 15:49:30 +02:00
}
2023-04-03 22:31:47 +02:00
ERR_FAIL_INDEX_V ( p_index , ( int ) data . children_cache . size ( ) , nullptr ) ;
return data . children_cache [ p_index ] ;
2021-08-25 15:49:30 +02:00
} else {
if ( p_index < 0 ) {
2023-04-03 22:31:47 +02:00
p_index + = ( int ) data . children_cache . size ( ) - data . internal_children_front_count_cache - data . internal_children_back_count_cache ;
2021-08-25 15:49:30 +02:00
}
2023-04-03 22:31:47 +02: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 14:46:33 +02:00
}
2014-02-09 22:10:30 -03:00
}
2022-11-07 20:27:50 -06:00
TypedArray < Node > Node : : get_children ( bool p_include_internal ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( TypedArray < Node > ( ) ) ;
2022-11-07 20:27:50 -06: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 ;
}
2015-10-10 09:09:09 -03:00
Node * Node : : _get_child_by_name ( const StringName & p_name ) const {
2023-04-03 22:31:47 +02:00
const Node * const * node = data . children . getptr ( p_name ) ;
if ( node ) {
return const_cast < Node * > ( * node ) ;
} else {
return nullptr ;
2015-10-10 09:09:09 -03:00
}
}
2019-01-29 08:15:34 -08:00
Node * Node : : get_node_or_null ( const NodePath & p_path ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2019-03-08 21:19:56 +01:00
if ( p_path . is_empty ( ) ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2019-03-08 21:19:56 +01:00
}
2025-05-28 15:24:49 +02:00
ERR_FAIL_COND_V_MSG ( ! data . tree & & p_path . is_absolute ( ) , nullptr , " Can't use get_node() with absolute paths from outside the active scene tree. " ) ;
2016-03-09 00:00:52 +01:00
2020-04-02 01:20:12 +02:00
Node * current = nullptr ;
Node * root = nullptr ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
if ( ! p_path . is_absolute ( ) ) {
current = const_cast < Node * > ( this ) ; //start from this
} else {
2017-01-14 18:03:38 +01:00
root = const_cast < Node * > ( this ) ;
2020-05-14 16:41:43 +02:00
while ( root - > data . parent ) {
2014-02-09 22:10:30 -03:00
root = root - > data . parent ; //start from root
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
for ( int i = 0 ; i < p_path . get_name_count ( ) ; i + + ) {
2016-03-09 00:00:52 +01:00
StringName name = p_path . get_name ( i ) ;
2020-04-02 01:20:12 +02:00
Node * next = nullptr ;
2016-03-09 00:00:52 +01:00
2024-05-14 16:34:59 +02:00
if ( name = = SNAME ( " . " ) ) {
2014-02-09 22:10:30 -03:00
next = current ;
2016-03-09 00:00:52 +01:00
2024-05-14 16:34:59 +02:00
} else if ( name = = SNAME ( " .. " ) ) {
2020-05-14 16:41:43 +02:00
if ( current = = nullptr | | ! current - > data . parent ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
next = current - > data . parent ;
2020-04-02 01:20:12 +02:00
} else if ( current = = nullptr ) {
2020-05-14 16:41:43 +02:00
if ( name = = root - > get_name ( ) ) {
2014-02-09 22:10:30 -03:00
next = root ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2022-04-16 12:23:32 +02:00
} else if ( name . is_node_unique_name ( ) ) {
2024-03-19 22:13:10 +01:00
Node * * unique = current - > data . owned_unique_nodes . getptr ( name ) ;
if ( ! unique & & current - > data . owner ) {
unique = current - > data . owner - > data . owned_unique_nodes . getptr ( name ) ;
}
if ( ! unique ) {
2022-04-16 12:23:32 +02:00
return nullptr ;
}
2024-03-19 22:13:10 +01:00
next = * unique ;
2014-02-09 22:10:30 -03:00
} else {
2020-04-02 01:20:12 +02:00
next = nullptr ;
2023-04-03 22:31:47 +02:00
const Node * const * node = current - > data . children . getptr ( name ) ;
if ( node ) {
next = const_cast < Node * > ( * node ) ;
} else {
2020-04-02 01:20:12 +02:00
return nullptr ;
2023-04-03 22:31:47 +02:00
}
2014-02-09 22:10:30 -03:00
}
current = next ;
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
return current ;
}
Node * Node : : get_node ( const NodePath & p_path ) const {
2019-01-29 08:15:34 -08:00
Node * node = get_node_or_null ( p_path ) ;
2021-02-20 02:05:19 +01:00
2022-01-19 11:33:27 +01:00
if ( unlikely ( ! node ) ) {
2023-06-05 19:57:33 +02:00
const String desc = get_description ( ) ;
2022-01-19 11:33:27 +01:00
if ( p_path . is_absolute ( ) ) {
ERR_FAIL_V_MSG ( nullptr ,
2022-10-16 10:42:09 +08:00
vformat ( R " (Node not found: " % s " (absolute path attempted from " % s " ).) " , p_path , desc ) ) ;
2022-01-19 11:33:27 +01:00
} else {
ERR_FAIL_V_MSG ( nullptr ,
2022-10-16 10:42:09 +08:00
vformat ( R " (Node not found: " % s " (relative to " % s " ).) " , p_path , desc ) ) ;
2022-01-19 11:33:27 +01:00
}
2021-02-20 02:05:19 +01:00
}
2014-02-09 22:10:30 -03:00
return node ;
}
bool Node : : has_node ( const NodePath & p_path ) const {
2020-04-02 01:20:12 +02:00
return get_node_or_null ( p_path ) ! = nullptr ;
2014-02-09 22:10:30 -03:00
}
2022-04-25 15:16:44 +02: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 18:45:53 +02:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2022-04-25 15:16:44 +02:00
ERR_FAIL_COND_V ( p_pattern . is_empty ( ) , nullptr ) ;
2023-04-03 22:31:47 +02:00
_update_children_cache ( ) ;
Node * const * cptr = data . children_cache . ptr ( ) ;
int ccount = data . children_cache . size ( ) ;
2022-04-25 15:16:44 +02: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 18:45:53 +02:00
ERR_THREAD_GUARD_V ( TypedArray < Node > ( ) ) ;
2021-12-17 12:04:35 -06:00
TypedArray < Node > ret ;
2022-04-25 15:16:44 +02:00
ERR_FAIL_COND_V ( p_pattern . is_empty ( ) & & p_type . is_empty ( ) , ret ) ;
2023-04-03 22:31:47 +02:00
_update_children_cache ( ) ;
Node * const * cptr = data . children_cache . ptr ( ) ;
int ccount = data . children_cache . size ( ) ;
2015-06-08 00:33:10 -03:00
for ( int i = 0 ; i < ccount ; i + + ) {
2020-05-14 16:41:43 +02:00
if ( p_owned & & ! cptr [ i ] - > data . owner ) {
2015-06-08 00:33:10 -03:00
continue ;
2020-05-14 16:41:43 +02:00
}
2021-12-17 12:04:35 -06:00
2023-03-29 14:52:16 +02:00
if ( p_pattern . is_empty ( ) | | cptr [ i ] - > data . name . operator String ( ) . match ( p_pattern ) ) {
if ( p_type . is_empty ( ) | | cptr [ i ] - > is_class ( p_type ) ) {
2021-12-17 12:04:35 -06:00
ret . append ( cptr [ i ] ) ;
2023-03-29 14:52:16 +02:00
} else if ( cptr [ i ] - > get_script_instance ( ) ) {
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 ( ) ) {
ret . append ( cptr [ i ] ) ;
break ;
}
2015-06-08 00:33:10 -03:00
2023-03-29 14:52:16 +02:00
scr = scr - > get_base_script ( ) ;
2021-12-17 12:04:35 -06:00
}
}
2020-05-14 16:41:43 +02:00
}
2015-06-08 00:33:10 -03:00
2021-12-17 12:04:35 -06:00
if ( p_recursive ) {
2022-04-25 15:16:44 +02:00
ret . append_array ( cptr [ i ] - > find_children ( p_pattern , p_type , true , p_owned ) ) ;
2020-05-14 16:41:43 +02:00
}
2015-06-08 00:33:10 -03:00
}
2021-12-17 12:04:35 -06:00
return ret ;
2015-06-08 00:33:10 -03:00
}
2020-02-17 18:29:14 +01:00
void Node : : reparent ( Node * p_parent , bool p_keep_global_transform ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2020-02-17 18:29:14 +01:00
ERR_FAIL_NULL ( p_parent ) ;
ERR_FAIL_NULL_MSG ( data . parent , " Node needs a parent to be reparented. " ) ;
2025-02-05 15:15:38 +04:00
ERR_FAIL_COND_MSG ( p_parent = = this , vformat ( " Can't reparent '%s' to itself. " , p_parent - > get_name ( ) ) ) ;
2020-02-17 18:29:14 +01:00
if ( p_parent = = data . parent ) {
return ;
}
2023-09-10 00:09:24 -04:00
bool preserve_owner = data . owner & & ( data . owner = = p_parent | | data . owner - > is_ancestor_of ( p_parent ) ) ;
Node * owner_temp = data . owner ;
LocalVector < Node * > common_parents ;
// If the new parent is related to the owner, find all children of the reparented node who have the same owner so that we can reassign them.
if ( preserve_owner ) {
LocalVector < Node * > to_visit ;
to_visit . push_back ( this ) ;
common_parents . push_back ( this ) ;
while ( to_visit . size ( ) > 0 ) {
Node * check = to_visit [ to_visit . size ( ) - 1 ] ;
to_visit . resize ( to_visit . size ( ) - 1 ) ;
2024-03-17 22:44:05 -04:00
for ( int i = 0 ; i < check - > get_child_count ( false ) ; i + + ) {
2023-09-10 00:09:24 -04:00
Node * child = check - > get_child ( i , false ) ;
to_visit . push_back ( child ) ;
if ( child - > data . owner = = owner_temp ) {
common_parents . push_back ( child ) ;
}
}
}
}
2020-02-17 18:29:14 +01:00
data . parent - > remove_child ( this ) ;
p_parent - > add_child ( this ) ;
2023-09-10 00:09:24 -04:00
// Reassign the old owner to those found nodes.
if ( preserve_owner ) {
for ( Node * E : common_parents ) {
E - > set_owner ( owner_temp ) ;
}
}
2020-02-17 18:29:14 +01:00
}
2014-02-09 22:10:30 -03:00
Node * Node : : get_parent ( ) const {
return data . parent ;
}
2022-04-25 15:16:44 +02:00
Node * Node : : find_parent ( const String & p_pattern ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2018-09-15 18:22:06 +02:00
Node * p = data . parent ;
while ( p ) {
2022-04-25 15:16:44 +02:00
if ( p - > data . name . operator String ( ) . match ( p_pattern ) ) {
2018-09-15 18:22:06 +02:00
return p ;
2020-05-14 16:41:43 +02:00
}
2018-09-15 18:22:06 +02:00
p = p - > data . parent ;
}
2020-04-02 01:20:12 +02:00
return nullptr ;
2018-09-15 18:22:06 +02:00
}
2023-01-10 09:40:44 +02:00
Window * Node : : get_window ( ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2023-01-10 09:40:44 +02:00
Viewport * vp = get_viewport ( ) ;
if ( vp ) {
return vp - > get_base_window ( ) ;
}
return nullptr ;
}
2023-04-20 15:13:21 +02: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 16:02:50 -06:00
bool Node : : is_ancestor_of ( const Node * p_node ) const {
2014-02-09 22:10:30 -03:00
ERR_FAIL_NULL_V ( p_node , false ) ;
Node * p = p_node - > data . parent ;
while ( p ) {
2020-05-14 16:41:43 +02:00
if ( p = = this ) {
2014-02-09 22:10:30 -03:00
return true ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
p = p - > data . parent ;
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
return false ;
}
bool Node : : is_greater_than ( const Node * p_node ) const {
ERR_FAIL_NULL_V ( p_node , false ) ;
2025-05-28 15:24:49 +02:00
ERR_FAIL_COND_V ( ! data . tree , false ) ;
ERR_FAIL_COND_V ( ! p_node - > data . tree , false ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
ERR_FAIL_COND_V ( data . depth < 0 , false ) ;
ERR_FAIL_COND_V ( p_node - > data . depth < 0 , false ) ;
2016-03-09 00:00:52 +01:00
2023-04-03 22:31:47 +02:00
_update_children_cache ( ) ;
2014-02-09 22:10:30 -03:00
int * this_stack = ( int * ) alloca ( sizeof ( int ) * data . depth ) ;
int * that_stack = ( int * ) alloca ( sizeof ( int ) * p_node - > data . depth ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
const Node * n = this ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
int idx = data . depth - 1 ;
while ( n ) {
ERR_FAIL_INDEX_V ( idx , data . depth , false ) ;
2023-04-03 22:31:47 +02:00
this_stack [ idx - - ] = n - > get_index ( ) ;
2014-02-09 22:10:30 -03:00
n = n - > data . parent ;
}
2023-04-03 22:31:47 +02:00
2014-02-09 22:10:30 -03:00
ERR_FAIL_COND_V ( idx ! = - 1 , false ) ;
n = p_node ;
idx = p_node - > data . depth - 1 ;
while ( n ) {
ERR_FAIL_INDEX_V ( idx , p_node - > data . depth , false ) ;
2023-04-03 22:31:47 +02:00
that_stack [ idx - - ] = n - > get_index ( ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
n = n - > data . parent ;
}
ERR_FAIL_COND_V ( idx ! = - 1 , false ) ;
idx = 0 ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
bool res ;
while ( true ) {
// using -2 since out-of-tree or nonroot nodes have -1
int this_idx = ( idx > = data . depth ) ? - 2 : this_stack [ idx ] ;
int that_idx = ( idx > = p_node - > data . depth ) ? - 2 : that_stack [ idx ] ;
if ( this_idx > that_idx ) {
res = true ;
break ;
} else if ( this_idx < that_idx ) {
res = false ;
break ;
} else if ( this_idx = = - 2 ) {
res = false ; // equal
break ;
}
idx + + ;
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
return res ;
}
void Node : : get_owned_by ( Node * p_by , List < Node * > * p_owned ) {
2020-05-14 16:41:43 +02:00
if ( data . owner = = p_by ) {
2014-02-09 22:10:30 -03:00
p_owned - > push_back ( this ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2023-04-03 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > get_owned_by ( p_by , p_owned ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
void Node : : _set_owner_nocheck ( Node * p_owner ) {
2020-05-14 16:41:43 +02:00
if ( data . owner = = p_owner ) {
2017-03-15 12:28:57 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2017-03-15 12:28:57 +01:00
2015-10-16 19:11:23 -03:00
ERR_FAIL_COND ( data . owner ) ;
2014-02-09 22:10:30 -03:00
data . owner = p_owner ;
data . owner - > data . owned . push_back ( this ) ;
data . OW = data . owner - > data . owned . back ( ) ;
2022-06-23 08:19:18 +02:00
owner_changed_notify ( ) ;
2014-02-09 22:10:30 -03:00
}
2022-04-16 12:23:32 +02:00
void Node : : _release_unique_name_in_owner ( ) {
2023-09-28 15:42:55 +02:00
ERR_FAIL_NULL ( data . owner ) ; // Safety check.
2022-04-16 12:23:32 +02:00
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 ( ) {
2023-09-28 15:42:55 +02:00
ERR_FAIL_NULL ( data . owner ) ; // Safety check.
2022-04-16 12:23:32 +02:00
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 ) {
2025-06-11 16:19:23 +02:00
String which_path = String ( is_inside_tree ( ) ? ( * which ) - > get_path ( ) : data . owner - > get_path_to ( * which ) ) ;
2023-11-11 22:59:05 +01:00
WARN_PRINT ( vformat ( " 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. " ,
2022-04-25 15:16:44 +02:00
get_name ( ) , is_inside_tree ( ) ? get_path ( ) : data . owner - > get_path_to ( this ) , which_path , which_path ) ) ;
2022-04-16 12:23:32 +02: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 18:45:53 +02:00
ERR_MAIN_THREAD_GUARD
2022-04-16 12:23:32 +02: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 ( ) ;
2024-11-26 00:04:25 +01:00
_emit_editor_state_changed ( ) ;
2022-04-16 12:23:32 +02:00
}
bool Node : : is_unique_name_in_owner ( ) const {
return data . unique_name_in_owner ;
}
2014-02-09 22:10:30 -03:00
void Node : : set_owner ( Node * p_owner ) {
2023-04-10 18:45:53 +02:00
ERR_MAIN_THREAD_GUARD
2014-02-09 22:10:30 -03:00
if ( data . owner ) {
2023-02-27 16:16:51 +08:00
_clean_up_owner ( ) ;
2014-02-09 22:10:30 -03:00
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
ERR_FAIL_COND ( p_owner = = this ) ;
2016-03-09 00:00:52 +01:00
2020-05-14 16:41:43 +02:00
if ( ! p_owner ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2025-04-13 13:43:57 +08:00
bool owner_valid = p_owner - > is_ancestor_of ( this ) ;
2016-03-09 00:00:52 +01:00
2023-07-03 22:19:24 +02:00
ERR_FAIL_COND_MSG ( ! owner_valid , " Invalid owner. Owner must be an ancestor in the tree. " ) ;
2014-02-09 22:10:30 -03:00
_set_owner_nocheck ( p_owner ) ;
2022-04-16 12:23:32 +02:00
if ( data . unique_name_in_owner ) {
_acquire_unique_name_in_owner ( ) ;
}
2024-11-26 00:04:25 +01:00
_emit_editor_state_changed ( ) ;
2014-02-09 22:10:30 -03:00
}
2020-05-14 14:29:06 +02:00
2014-02-09 22:10:30 -03:00
Node * Node : : get_owner ( ) const {
2016-03-09 00:00:52 +01:00
return data . owner ;
2014-02-09 22:10:30 -03:00
}
2023-02-27 16:16:51 +08:00
void Node : : _clean_up_owner ( ) {
2023-09-28 15:42:55 +02:00
ERR_FAIL_NULL ( data . owner ) ; // Safety check.
2023-02-27 16:16:51 +08:00
if ( data . unique_name_in_owner ) {
_release_unique_name_in_owner ( ) ;
}
data . owner - > data . owned . erase ( data . OW ) ;
data . owner = nullptr ;
data . OW = nullptr ;
}
2016-07-19 20:04:06 -03:00
Node * Node : : find_common_parent_with ( const Node * p_node ) const {
2020-05-14 16:41:43 +02:00
if ( this = = p_node ) {
2016-07-19 20:04:06 -03:00
return const_cast < Node * > ( p_node ) ;
2020-05-14 16:41:43 +02:00
}
2016-07-19 20:04:06 -03:00
2022-05-19 17:00:06 +02:00
HashSet < const Node * > visited ;
2016-07-19 20:04:06 -03:00
const Node * n = this ;
while ( n ) {
visited . insert ( n ) ;
n = n - > data . parent ;
}
const Node * common_parent = p_node ;
while ( common_parent ) {
2020-05-14 16:41:43 +02:00
if ( visited . has ( common_parent ) ) {
2016-07-19 20:04:06 -03:00
break ;
2020-05-14 16:41:43 +02:00
}
2016-07-19 20:04:06 -03:00
common_parent = common_parent - > data . parent ;
}
2020-05-14 16:41:43 +02:00
if ( ! common_parent ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2016-07-19 20:04:06 -03:00
return const_cast < Node * > ( common_parent ) ;
}
2022-11-19 07:23:38 +09:00
NodePath Node : : get_path_to ( const Node * p_node , bool p_use_unique_path ) const {
2014-02-09 22:10:30 -03:00
ERR_FAIL_NULL_V ( p_node , NodePath ( ) ) ;
2020-05-14 16:41:43 +02:00
if ( this = = p_node ) {
2014-02-09 22:10:30 -03:00
return NodePath ( " . " ) ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2022-05-19 17:00:06 +02:00
HashSet < const Node * > visited ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
const Node * n = this ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
while ( n ) {
visited . insert ( n ) ;
n = n - > data . parent ;
}
const Node * common_parent = p_node ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
while ( common_parent ) {
2020-05-14 16:41:43 +02:00
if ( visited . has ( common_parent ) ) {
2014-02-09 22:10:30 -03:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
common_parent = common_parent - > data . parent ;
}
2016-03-09 00:00:52 +01:00
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V ( common_parent , NodePath ( ) ) ; //nodes not in the same tree
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
visited . clear ( ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
Vector < StringName > path ;
2022-11-19 07:23:38 +09:00
StringName up = String ( " .. " ) ;
2016-03-09 00:00:52 +01:00
2022-11-19 07:23:38 +09:00
if ( p_use_unique_path ) {
n = p_node ;
2016-03-09 00:00:52 +01:00
2022-11-19 07:23:38 +09: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-09 00:00:52 +01:00
2022-11-19 07:23:38 +09:00
if ( ! is_detected ) {
n = this ;
2016-03-09 00:00:52 +01:00
2022-11-19 07:23:38 +09: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-09 22:10:30 -03:00
}
2016-03-09 00:00:52 +01:00
2021-03-14 07:21:32 +00:00
path . reverse ( ) ;
2016-03-09 00:00:52 +01:00
return NodePath ( path , false ) ;
2014-02-09 22:10:30 -03:00
}
NodePath Node : : get_path ( ) const {
2019-08-08 22:11:48 +02: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 18:49:50 -03:00
2020-05-14 16:41:43 +02:00
if ( data . path_cache ) {
2016-08-14 18:49:50 -03:00
return * data . path_cache ;
2020-05-14 16:41:43 +02:00
}
2016-08-14 18:49:50 -03:00
2014-02-09 22:10:30 -03:00
const Node * n = this ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
Vector < StringName > path ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
while ( n ) {
path . push_back ( n - > get_name ( ) ) ;
n = n - > data . parent ;
2016-03-09 00:00:52 +01:00
}
2021-03-14 07:21:32 +00:00
path . reverse ( ) ;
2016-03-09 00:00:52 +01:00
2016-08-14 18:49:50 -03:00
data . path_cache = memnew ( NodePath ( path , true ) ) ;
return * data . path_cache ;
2014-02-09 22:10:30 -03:00
}
bool Node : : is_in_group ( const StringName & p_identifier ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( false ) ;
2014-02-09 22:10:30 -03:00
return data . grouped . has ( p_identifier ) ;
}
void Node : : add_to_group ( const StringName & p_identifier , bool p_persistent ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2025-06-21 00:11:31 +04:00
ERR_FAIL_COND_MSG ( p_identifier . is_empty ( ) , vformat ( " Cannot add node '%s' to a group with an empty name. " , get_name ( ) ) ) ;
2016-03-09 00:00:52 +01:00
2020-05-14 16:41:43 +02:00
if ( data . grouped . has ( p_identifier ) ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
GroupData gd ;
2016-03-09 00:00:52 +01:00
2016-06-07 22:08:12 -03:00
if ( data . tree ) {
gd . group = data . tree - > add_to_group ( p_identifier , this ) ;
} else {
2020-04-02 01:20:12 +02:00
gd . group = nullptr ;
2016-06-07 22:08:12 -03:00
}
2014-02-09 22:10:30 -03:00
2016-03-09 00:00:52 +01:00
gd . persistent = p_persistent ;
2014-02-09 22:10:30 -03:00
data . grouped [ p_identifier ] = gd ;
2024-11-26 00:04:25 +01:00
if ( p_persistent ) {
_emit_editor_state_changed ( ) ;
}
2014-02-09 22:10:30 -03:00
}
void Node : : remove_from_group ( const StringName & p_identifier ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2022-05-13 15:04:37 +02:00
HashMap < StringName , GroupData > : : Iterator E = data . grouped . find ( p_identifier ) ;
2016-06-07 22:08:12 -03:00
2022-11-12 16:01:17 +01:00
if ( ! E ) {
return ;
}
2016-03-09 00:00:52 +01:00
2024-11-26 00:04:25 +01:00
# ifdef TOOLS_ENABLED
bool persistent = E - > value . persistent ;
# endif
2020-05-14 16:41:43 +02:00
if ( data . tree ) {
2022-05-13 15:04:37 +02:00
data . tree - > remove_from_group ( E - > key , this ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2022-05-13 15:04:37 +02:00
data . grouped . remove ( E ) ;
2024-11-26 00:04:25 +01:00
# ifdef TOOLS_ENABLED
if ( persistent ) {
_emit_editor_state_changed ( ) ;
}
# endif
2014-02-09 22:10:30 -03:00
}
2022-08-05 20:35:08 +02:00
TypedArray < StringName > Node : : _get_groups ( ) const {
TypedArray < StringName > groups ;
2014-06-16 10:22:26 -03:00
List < GroupInfo > gi ;
get_groups ( & gi ) ;
2021-07-24 15:46:25 +02:00
for ( const GroupInfo & E : gi ) {
2021-07-15 23:45:57 -04:00
groups . push_back ( E . name ) ;
2014-06-16 10:22:26 -03:00
}
return groups ;
}
2014-02-09 22:10:30 -03:00
void Node : : get_groups ( List < GroupInfo > * p_groups ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2021-08-09 14:13:42 -06:00
for ( const KeyValue < StringName , GroupData > & E : data . grouped ) {
2014-02-09 22:10:30 -03:00
GroupInfo gi ;
2021-08-09 14:13:42 -06:00
gi . name = E . key ;
gi . persistent = E . value . persistent ;
2014-02-09 22:10:30 -03:00
p_groups - > push_back ( gi ) ;
}
}
2019-08-16 22:30:31 +02:00
int Node : : get_persistent_group_count ( ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( 0 ) ;
2019-08-16 22:30:31 +02:00
int count = 0 ;
2014-02-09 22:10:30 -03:00
2021-08-09 14:13:42 -06:00
for ( const KeyValue < StringName , GroupData > & E : data . grouped ) {
if ( E . value . persistent ) {
2019-08-16 22:30:31 +02:00
count + = 1 ;
}
2016-06-04 13:17:56 -03:00
}
2019-08-16 22:30:31 +02:00
return count ;
2016-06-04 13:17:56 -03:00
}
2020-05-14 14:29:06 +02:00
2023-05-21 18:04:03 +02:00
void Node : : print_tree_pretty ( ) {
print_line ( _get_tree_string_pretty ( " " , true ) ) ;
}
void Node : : print_tree ( ) {
print_line ( _get_tree_string ( this ) ) ;
}
String Node : : _get_tree_string_pretty ( const String & p_prefix , bool p_last ) {
String new_prefix = p_last ? String : : utf8 ( " ┖╴ " ) : String : : utf8 ( " ┠╴ " ) ;
2023-04-03 22:31:47 +02:00
_update_children_cache ( ) ;
2023-05-21 18:04:03 +02:00
String return_tree = p_prefix + new_prefix + String ( get_name ( ) ) + " \n " ;
2023-04-03 22:31:47 +02:00
for ( uint32_t i = 0 ; i < data . children_cache . size ( ) ; i + + ) {
2023-05-21 18:04:03 +02:00
new_prefix = p_last ? String : : utf8 ( " " ) : String : : utf8 ( " ┃ " ) ;
return_tree + = data . children_cache [ i ] - > _get_tree_string_pretty ( p_prefix + new_prefix , i = = data . children_cache . size ( ) - 1 ) ;
2018-02-28 10:12:06 +01:00
}
2023-05-21 18:04:03 +02:00
return return_tree ;
2018-02-28 10:12:06 +01:00
}
2023-05-21 18:04:03 +02:00
String Node : : get_tree_string_pretty ( ) {
return _get_tree_string_pretty ( " " , true ) ;
2014-02-09 22:10:30 -03:00
}
2023-05-21 18:04:03 +02:00
String Node : : _get_tree_string ( const Node * p_node ) {
2023-04-03 22:31:47 +02:00
_update_children_cache ( ) ;
2023-05-21 18:04:03 +02:00
String return_tree = String ( p_node - > get_path_to ( this ) ) + " \n " ;
2023-04-03 22:31:47 +02:00
for ( uint32_t i = 0 ; i < data . children_cache . size ( ) ; i + + ) {
2023-05-21 18:04:03 +02:00
return_tree + = data . children_cache [ i ] - > _get_tree_string ( p_node ) ;
2020-05-14 16:41:43 +02:00
}
2023-05-21 18:04:03 +02:00
return return_tree ;
}
String Node : : get_tree_string ( ) {
return _get_tree_string ( this ) ;
2018-02-28 10:12:06 +01:00
}
2014-02-09 22:10:30 -03:00
void Node : : _propagate_reverse_notification ( int p_notification ) {
2016-03-09 00:00:52 +01:00
data . blocked + + ;
2023-04-03 22:31:47 +02:00
for ( HashMap < StringName , Node * > : : Iterator I = data . children . last ( ) ; I ; - - I ) {
I - > value - > _propagate_reverse_notification ( p_notification ) ;
2014-02-09 22:10:30 -03:00
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
notification ( p_notification , true ) ;
data . blocked - - ;
}
void Node : : _propagate_deferred_notification ( int p_notification , bool p_reverse ) {
2014-11-05 21:20:42 -03:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2014-02-09 22:10:30 -03:00
data . blocked + + ;
2020-05-14 16:41:43 +02:00
if ( ! p_reverse ) {
2014-02-09 22:10:30 -03:00
MessageQueue : : get_singleton ( ) - > push_notification ( this , p_notification ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2023-04-03 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _propagate_deferred_notification ( p_notification , p_reverse ) ;
2014-02-09 22:10:30 -03:00
}
2020-05-14 16:41:43 +02:00
if ( p_reverse ) {
2014-02-09 22:10:30 -03:00
MessageQueue : : get_singleton ( ) - > push_notification ( this , p_notification ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
data . blocked - - ;
}
void Node : : propagate_notification ( int p_notification ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2016-03-09 00:00:52 +01:00
data . blocked + + ;
2014-02-09 22:10:30 -03:00
notification ( p_notification ) ;
2016-03-09 00:00:52 +01:00
2023-04-03 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > propagate_notification ( p_notification ) ;
2014-02-09 22:10:30 -03:00
}
2016-03-09 00:00:52 +01:00
data . blocked - - ;
2014-02-09 22:10:30 -03:00
}
2017-08-19 15:17:06 +02:00
void Node : : propagate_call ( const StringName & p_method , const Array & p_args , const bool p_parent_first ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2017-08-19 15:17:06 +02:00
data . blocked + + ;
2020-05-14 16:41:43 +02:00
if ( p_parent_first & & has_method ( p_method ) ) {
2017-08-19 15:17:06 +02:00
callv ( p_method , p_args ) ;
2020-05-14 16:41:43 +02:00
}
2017-08-19 15:17:06 +02:00
2023-04-03 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > propagate_call ( p_method , p_args , p_parent_first ) ;
2017-08-19 15:17:06 +02:00
}
2020-05-14 16:41:43 +02:00
if ( ! p_parent_first & & has_method ( p_method ) ) {
2017-08-19 15:17:06 +02:00
callv ( p_method , p_args ) ;
2020-05-14 16:41:43 +02:00
}
2017-08-19 15:17:06 +02:00
data . blocked - - ;
}
2016-03-09 00:00:52 +01:00
void Node : : _propagate_replace_owner ( Node * p_owner , Node * p_by_owner ) {
2020-05-14 16:41:43 +02:00
if ( get_owner ( ) = = p_owner ) {
2014-02-09 22:10:30 -03:00
set_owner ( p_by_owner ) ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
data . blocked + + ;
2023-04-03 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > _propagate_replace_owner ( p_owner , p_by_owner ) ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
data . blocked - - ;
2014-02-09 22:10:30 -03:00
}
2020-09-05 03:05:30 +02:00
Ref < Tween > Node : : create_tween ( ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( Ref < Tween > ( ) ) ;
2024-01-29 14:10:07 +01:00
SceneTree * tree = data . tree ;
if ( ! tree ) {
tree = SceneTree : : get_singleton ( ) ;
}
ERR_FAIL_NULL_V_MSG ( tree , Ref < Tween > ( ) , " No available SceneTree to create the Tween. " ) ;
Ref < Tween > tween = tree - > create_tween ( ) ;
2020-09-05 03:05:30 +02:00
tween - > bind_node ( this ) ;
return tween ;
}
2021-09-30 16:30:55 +02:00
void Node : : set_scene_file_path ( const String & p_scene_file_path ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2021-09-30 16:30:55 +02:00
data . scene_file_path = p_scene_file_path ;
2024-11-26 00:04:25 +01:00
_emit_editor_state_changed ( ) ;
2014-02-09 22:10:30 -03:00
}
2020-05-14 14:29:06 +02:00
2021-09-30 16:30:55 +02:00
String Node : : get_scene_file_path ( ) const {
return data . scene_file_path ;
2014-02-09 22:10:30 -03:00
}
2019-08-15 14:50:26 +02:00
void Node : : set_editor_description ( const String & p_editor_description ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2022-09-22 18:29:11 +02:00
if ( data . editor_description = = p_editor_description ) {
return ;
}
2021-02-18 15:52:29 -03:00
data . editor_description = p_editor_description ;
2023-11-14 13:00:41 +08:00
emit_signal ( SNAME ( " editor_description_changed " ) , this ) ;
2019-08-15 14:50:26 +02:00
}
2020-05-14 14:29:06 +02:00
2019-08-15 14:50:26 +02:00
String Node : : get_editor_description ( ) const {
2021-02-18 15:52:29 -03:00
return data . editor_description ;
2019-08-15 14:50:26 +02:00
}
2015-10-10 09:09:09 -03:00
void Node : : set_editable_instance ( Node * p_node , bool p_editable ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2015-10-10 09:09:09 -03:00
ERR_FAIL_NULL ( p_node ) ;
2021-06-18 16:02:50 -06:00
ERR_FAIL_COND ( ! is_ancestor_of ( p_node ) ) ;
2017-04-07 15:48:07 +02:00
if ( ! p_editable ) {
2021-01-17 23:37:40 +01:00
p_node - > data . editable_instance = false ;
2017-04-07 15:48:07 +02:00
// Avoid this flag being needlessly saved;
2021-03-12 19:05:16 +05:30
// also give more visual feedback if editable children are re-enabled
2017-04-07 15:48:07 +02:00
set_display_folded ( false ) ;
} else {
2021-01-17 23:37:40 +01:00
p_node - > data . editable_instance = true ;
2017-04-07 15:48:07 +02:00
}
2024-11-26 00:04:25 +01:00
p_node - > _emit_editor_state_changed ( ) ;
2015-10-10 09:09:09 -03:00
}
2018-10-29 16:36:31 -03:00
bool Node : : is_editable_instance ( const Node * p_node ) const {
2020-05-14 16:41:43 +02:00
if ( ! p_node ) {
2021-01-17 23:37:40 +01:00
return false ; // Easier, null is never editable. :)
2020-05-14 16:41:43 +02:00
}
2021-06-18 16:02:50 -06:00
ERR_FAIL_COND_V ( ! is_ancestor_of ( p_node ) , false ) ;
2021-01-17 23:37:40 +01:00
return p_node - > data . editable_instance ;
2016-04-12 18:21:37 +02:00
}
2021-02-21 09:19:48 +01:00
Node * Node : : get_deepest_editable_node ( Node * p_start_node ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2021-02-21 09:19:48 +01:00
ERR_FAIL_NULL_V ( p_start_node , nullptr ) ;
2021-06-18 16:02:50 -06:00
ERR_FAIL_COND_V ( ! is_ancestor_of ( p_start_node ) , p_start_node ) ;
2021-02-21 09:19:48 +01: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 14:09:59 +02:00
if ( ! is_editable_instance ( iterated_item - > get_owner ( ) ) ) {
2021-02-21 09:19:48 +01:00
node = iterated_item - > get_owner ( ) ;
2021-04-05 14:09:59 +02:00
}
2021-02-21 09:19:48 +01:00
iterated_item = iterated_item - > get_owner ( ) ;
}
return node ;
}
2021-10-26 21:12:25 +02:00
# ifdef TOOLS_ENABLED
void Node : : set_property_pinned ( const String & p_property , bool p_pinned ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2021-10-26 21:12:25 +02:00
bool current_pinned = false ;
2022-04-01 20:30:23 +02: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 21:12:25 +02:00
if ( current_pinned ! = p_pinned ) {
if ( p_pinned ) {
pinned . append ( psa ) ;
} else {
pinned . erase ( psa ) ;
}
}
2022-04-01 20:30:23 +02:00
if ( pinned . is_empty ( ) ) {
remove_meta ( " _edit_pinned_properties_ " ) ;
} else {
set_meta ( " _edit_pinned_properties_ " , pinned ) ;
}
2021-10-26 21:12:25 +02:00
}
bool Node : : is_property_pinned ( const StringName & p_property ) const {
2022-04-01 20:30:23 +02:00
Array pinned = get_meta ( " _edit_pinned_properties_ " , Array ( ) ) ;
StringName psa = get_property_store_alias ( p_property ) ;
2021-10-26 21:12:25 +02:00
return pinned . has ( psa ) ;
}
StringName Node : : get_property_store_alias ( const StringName & p_property ) const {
return p_property ;
}
2023-03-17 01:58:30 +01:00
bool Node : : is_part_of_edited_scene ( ) const {
2025-05-28 15:24:49 +02:00
return Engine : : get_singleton ( ) - > is_editor_hint ( ) & & is_inside_tree ( ) & & data . tree - > get_edited_scene_root ( ) & &
data . tree - > get_edited_scene_root ( ) - > get_parent ( ) - > is_ancestor_of ( this ) ;
2023-03-17 01:58:30 +01:00
}
2021-10-26 21:12:25 +02:00
# endif
2022-05-19 17:00:06 +02:00
void Node : : get_storable_properties ( HashSet < StringName > & r_storable_properties ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2025-02-03 14:16:27 +08:00
List < PropertyInfo > property_list ;
get_property_list ( & property_list ) ;
for ( const PropertyInfo & pi : property_list ) {
if ( ( pi . usage & PROPERTY_USAGE_STORAGE ) ) {
r_storable_properties . insert ( pi . name ) ;
2021-10-26 21:12:25 +02:00
}
}
}
2021-07-12 00:40:18 +10:00
String Node : : to_string ( ) {
2024-06-06 04:43:13 +02:00
// Keep this method in sync with `Object::to_string`.
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( String ( ) ) ;
2021-07-12 00:40:18 +10:00
if ( get_script_instance ( ) ) {
bool valid ;
String ret = get_script_instance ( ) - > to_string ( & valid ) ;
if ( valid ) {
return ret ;
}
}
2024-06-06 04:43:13 +02:00
if ( _get_extension ( ) & & _get_extension ( ) - > to_string ) {
String ret ;
GDExtensionBool is_valid ;
_get_extension ( ) - > to_string ( _get_extension_instance ( ) , & is_valid , & ret ) ;
2025-04-19 10:45:12 +12:00
if ( is_valid ) {
return ret ;
}
2024-06-06 04:43:13 +02:00
}
2021-07-12 00:40:18 +10:00
return ( get_name ( ) ? String ( get_name ( ) ) + " : " : " " ) + Object : : to_string ( ) ;
}
2015-10-10 09:09:09 -03:00
void Node : : set_scene_instance_state ( const Ref < SceneState > & p_state ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2015-10-10 09:09:09 -03:00
data . instance_state = p_state ;
}
Ref < SceneState > Node : : get_scene_instance_state ( ) const {
return data . instance_state ;
}
void Node : : set_scene_inherited_state ( const Ref < SceneState > & p_state ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2015-10-10 09:09:09 -03:00
data . inherited_state = p_state ;
2024-11-26 00:04:25 +01:00
_emit_editor_state_changed ( ) ;
2015-10-10 09:09:09 -03:00
}
Ref < SceneState > Node : : get_scene_inherited_state ( ) const {
return data . inherited_state ;
}
2015-10-16 19:11:23 -03:00
void Node : : set_scene_instance_load_placeholder ( bool p_enable ) {
data . use_placeholder = p_enable ;
2014-02-09 22:10:30 -03:00
}
2015-10-16 19:11:23 -03:00
bool Node : : get_scene_instance_load_placeholder ( ) const {
return data . use_placeholder ;
2014-02-09 22:10:30 -03:00
}
2022-05-13 15:04:37 +02:00
Node * Node : : _duplicate ( int p_flags , HashMap < const Node * , Node * > * r_duplimap ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2020-04-02 01:20:12 +02:00
Node * node = nullptr ;
2014-02-09 22:10:30 -03:00
2021-06-17 16:03:09 -06:00
bool instantiated = false ;
2015-08-02 12:29:37 -03:00
2017-08-24 22:58:51 +02:00
if ( Object : : cast_to < InstancePlaceholder > ( this ) ) {
const InstancePlaceholder * ip = Object : : cast_to < const InstancePlaceholder > ( this ) ;
2016-01-22 19:36:40 -03:00
InstancePlaceholder * nip = memnew ( InstancePlaceholder ) ;
nip - > set_instance_path ( ip - > get_instance_path ( ) ) ;
node = nip ;
2024-12-15 17:01:30 +01:00
} else if ( ( p_flags & DUPLICATE_USE_INSTANTIATION ) & & is_instance ( ) ) {
2021-09-30 16:30:55 +02:00
Ref < PackedScene > res = ResourceLoader : : load ( get_scene_file_path ( ) ) ;
2020-04-02 01:20:12 +02:00
ERR_FAIL_COND_V ( res . is_null ( ) , nullptr ) ;
2023-02-01 10:49:05 +01:00
PackedScene : : GenEditState edit_state = PackedScene : : GEN_EDIT_STATE_DISABLED ;
2017-11-19 14:32:10 +01:00
# ifdef TOOLS_ENABLED
2020-05-14 16:41:43 +02:00
if ( p_flags & DUPLICATE_FROM_EDITOR ) {
2023-02-01 10:49:05 +01:00
edit_state = PackedScene : : GEN_EDIT_STATE_INSTANCE ;
2020-05-14 16:41:43 +02:00
}
2017-11-19 14:32:10 +01:00
# endif
2023-02-01 10:49:05 +01:00
node = res - > instantiate ( edit_state ) ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V ( node , nullptr ) ;
2022-01-16 15:08:03 +08:00
node - > set_scene_instance_load_placeholder ( get_scene_instance_load_placeholder ( ) ) ;
2015-08-02 12:29:37 -03:00
2021-06-17 16:03:09 -06:00
instantiated = true ;
2015-08-02 12:29:37 -03:00
} else {
2021-06-17 16:03:09 -06:00
Object * obj = ClassDB : : instantiate ( get_class ( ) ) ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V ( obj , nullptr ) ;
2017-08-24 22:58:51 +02:00
node = Object : : cast_to < Node > ( obj ) ;
2020-05-14 16:41:43 +02:00
if ( ! node ) {
2015-08-02 12:29:37 -03:00
memdelete ( obj ) ;
2020-05-14 16:41:43 +02:00
}
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V ( node , nullptr ) ;
2015-08-02 12:29:37 -03:00
}
2014-02-09 22:10:30 -03:00
2024-12-15 17:01:30 +01:00
if ( is_instance ( ) ) {
2021-09-30 16:30:55 +02:00
node - > set_scene_file_path ( get_scene_file_path ( ) ) ;
2021-02-28 17:19:01 +01:00
node - > data . editable_instance = data . editable_instance ;
2017-10-13 17:03:33 -05:00
}
2014-02-09 22:10:30 -03:00
2017-12-08 15:05:15 +01:00
List < const Node * > hidden_roots ;
2017-10-13 17:03:33 -05:00
List < const Node * > node_tree ;
node_tree . push_front ( this ) ;
2021-06-17 16:03:09 -06: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 21:13:52 +01:00
2021-02-22 16:50:44 +01:00
Vector < const Node * > instance_roots ;
instance_roots . push_back ( this ) ;
2017-10-13 17:03:33 -05:00
for ( List < const Node * > : : Element * N = node_tree . front ( ) ; N ; N = N - > next ( ) ) {
2024-03-13 13:22:42 +01:00
for ( int i = 0 ; i < N - > get ( ) - > get_child_count ( false ) ; + + i ) {
Node * descendant = N - > get ( ) - > get_child ( i , false ) ;
2023-11-13 09:44:07 +08:00
2021-06-17 16:03:09 -06: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 16:50:44 +01: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 15:05:15 +01:00
hidden_roots . push_back ( descendant ) ;
2020-05-14 16:41:43 +02:00
}
2017-11-25 21:13:52 +01:00
continue ;
2017-12-08 15:05:15 +01:00
}
2017-11-25 21:13:52 +01:00
2017-12-08 15:05:15 +01:00
node_tree . push_back ( descendant ) ;
2021-02-22 16:50:44 +01:00
2024-12-15 17:01:30 +01:00
if ( descendant - > is_instance ( ) & & instance_roots . has ( descendant - > get_owner ( ) ) ) {
2021-02-22 16:50:44 +01:00
instance_roots . push_back ( descendant ) ;
}
2017-10-13 17:03:33 -05:00
}
2017-09-06 19:21:19 +07:00
}
}
2019-05-28 12:40:39 +02:00
if ( get_name ( ) ! = String ( ) ) {
node - > set_name ( get_name ( ) ) ;
}
2014-02-09 22:10:30 -03:00
2017-11-19 14:32:10 +01:00
# ifdef TOOLS_ENABLED
2020-05-14 16:41:43 +02:00
if ( ( p_flags & DUPLICATE_FROM_EDITOR ) & & r_duplimap ) {
2017-11-19 14:32:10 +01:00
r_duplimap - > insert ( this , node ) ;
2020-05-14 16:41:43 +02:00
}
2017-11-19 14:32:10 +01:00
# endif
2017-02-20 20:05:01 +01:00
if ( p_flags & DUPLICATE_GROUPS ) {
List < GroupInfo > gi ;
get_groups ( & gi ) ;
2021-07-24 15:46:25 +02:00
for ( const GroupInfo & E : gi ) {
2017-11-19 14:32:10 +01:00
# ifdef TOOLS_ENABLED
2021-07-15 23:45:57 -04:00
if ( ( p_flags & DUPLICATE_FROM_EDITOR ) & & ! E . persistent ) {
2017-11-19 14:32:10 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2017-11-19 14:32:10 +01:00
# endif
2021-07-15 23:45:57 -04:00
node - > add_to_group ( E . name , E . persistent ) ;
2017-02-20 20:05:01 +01:00
}
2016-01-20 00:08:04 +01:00
}
2024-03-13 13:22:42 +01:00
for ( int i = 0 ; i < get_child_count ( false ) ; i + + ) {
2025-05-11 17:32:29 +02:00
if ( instantiated & & get_child ( i , false ) - > data . owner = = this ) {
2015-08-02 12:29:37 -03:00
continue ; //part of instance
2020-05-14 16:41:43 +02:00
}
2015-08-02 12:29:37 -03:00
2025-05-11 17:32:29 +02:00
Node * dup = get_child ( i , false ) - > _duplicate ( p_flags , r_duplimap ) ;
2014-02-09 22:10:30 -03:00
if ( ! dup ) {
memdelete ( node ) ;
2020-04-02 01:20:12 +02:00
return nullptr ;
2014-02-09 22:10:30 -03:00
}
node - > add_child ( dup ) ;
2025-05-11 17:32:29 +02:00
if ( i < node - > get_child_count ( false ) - 1 ) {
2017-12-08 15:05:15 +01:00
node - > move_child ( dup , i ) ;
}
}
2021-07-15 23:45:57 -04:00
for ( const Node * & E : hidden_roots ) {
Node * parent = node - > get_node ( get_path_to ( E - > data . parent ) ) ;
2017-12-08 15:05:15 +01:00
if ( ! parent ) {
memdelete ( node ) ;
2020-04-02 01:20:12 +02:00
return nullptr ;
2017-12-08 15:05:15 +01:00
}
2021-07-15 23:45:57 -04:00
Node * dup = E - > _duplicate ( p_flags , r_duplimap ) ;
2017-12-08 15:05:15 +01:00
if ( ! dup ) {
memdelete ( node ) ;
2020-04-02 01:20:12 +02:00
return nullptr ;
2017-12-08 15:05:15 +01:00
}
parent - > add_child ( dup ) ;
2025-05-11 17:32:29 +02:00
int pos = E - > get_index ( false ) ;
2017-12-08 15:05:15 +01:00
2025-05-11 17:32:29 +02:00
if ( pos < parent - > get_child_count ( false ) - 1 ) {
2017-12-08 15:05:15 +01:00
parent - > move_child ( dup , pos ) ;
}
2014-02-09 22:10:30 -03:00
}
return node ;
}
2017-11-19 13:05:18 +01:00
Node * Node : : duplicate ( int p_flags ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2017-11-19 13:05:18 +01:00
Node * dupe = _duplicate ( p_flags ) ;
2024-08-02 16:26:19 +03:00
ERR_FAIL_NULL_V_MSG ( dupe , nullptr , " Failed to duplicate node. " ) ;
2024-06-02 13:27:35 +03:00
_duplicate_properties ( this , this , dupe , p_flags ) ;
2024-08-02 16:26:19 +03:00
if ( p_flags & DUPLICATE_SIGNALS ) {
2017-11-19 13:05:18 +01:00
_duplicate_signals ( this , dupe ) ;
}
return dupe ;
}
2017-11-19 14:32:10 +01:00
# ifdef TOOLS_ENABLED
2022-05-13 15:04:37 +02: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 17:36:37 +01:00
}
2022-05-13 15:04:37 +02:00
Node * Node : : duplicate_from_editor ( HashMap < const Node * , Node * > & r_duplimap , const HashMap < Ref < Resource > , Ref < Resource > > & p_resource_remap ) const {
2024-04-29 22:13:12 +03:00
int flags = DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR ;
Node * dupe = _duplicate ( flags , & r_duplimap ) ;
2017-11-19 14:32:10 +01:00
2024-08-02 16:26:19 +03:00
ERR_FAIL_NULL_V_MSG ( dupe , nullptr , " Failed to duplicate node. " ) ;
2024-06-02 13:27:35 +03:00
_duplicate_properties ( this , this , dupe , flags ) ;
2021-02-12 17:36:37 +01: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 14:32:10 +01: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 17:36:37 +01:00
2022-05-13 15:04:37 +02:00
void Node : : remap_node_resources ( Node * p_node , const HashMap < Ref < Resource > , Ref < Resource > > & p_resource_remap ) const {
2021-02-12 17:36:37 +01:00
List < PropertyInfo > props ;
p_node - > get_property_list ( & props ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : props ) {
2021-07-15 23:45:57 -04:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2021-02-12 17:36:37 +01:00
continue ;
}
2021-07-15 23:45:57 -04:00
Variant v = p_node - > get ( E . name ) ;
2021-08-26 21:37:17 +02:00
if ( v . is_ref_counted ( ) ) {
2022-05-03 01:43:50 +02:00
Ref < Resource > res = v ;
2021-02-12 17:36:37 +01:00
if ( res . is_valid ( ) ) {
if ( p_resource_remap . has ( res ) ) {
2021-07-15 23:45:57 -04:00
p_node - > set ( E . name , p_resource_remap [ res ] ) ;
2021-02-12 17:36:37 +01: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 15:04:37 +02:00
void Node : : remap_nested_resources ( Ref < Resource > p_resource , const HashMap < Ref < Resource > , Ref < Resource > > & p_resource_remap ) const {
2021-02-12 17:36:37 +01:00
List < PropertyInfo > props ;
p_resource - > get_property_list ( & props ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : props ) {
2021-07-15 23:45:57 -04:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2021-02-12 17:36:37 +01:00
continue ;
}
2021-07-15 23:45:57 -04:00
Variant v = p_resource - > get ( E . name ) ;
2021-08-26 21:37:17 +02:00
if ( v . is_ref_counted ( ) ) {
2022-05-03 01:43:50 +02:00
Ref < Resource > res = v ;
2021-02-12 17:36:37 +01:00
if ( res . is_valid ( ) ) {
if ( p_resource_remap . has ( res ) ) {
2021-07-15 23:45:57 -04:00
p_resource - > set ( E . name , p_resource_remap [ res ] ) ;
2021-02-12 17:36:37 +01:00
remap_nested_resources ( res , p_resource_remap ) ;
}
}
}
}
}
2024-11-26 00:04:25 +01:00
void Node : : _emit_editor_state_changed ( ) {
// This is required for the SceneTreeEditor to properly keep track of when an update is needed.
// This signal might be expensive and not needed for anything outside of the editor.
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
emit_signal ( SNAME ( " editor_state_changed " ) ) ;
}
}
2017-11-19 14:32:10 +01:00
# endif
2024-04-29 22:13:12 +03:00
// Duplicate node's properties.
// This has to be called after nodes have been duplicated since there might be properties
// of type Node that can be updated properly only if duplicated node tree is complete.
void Node : : _duplicate_properties ( const Node * p_root , const Node * p_original , Node * p_copy , int p_flags ) const {
2024-01-19 22:57:31 +02:00
List < PropertyInfo > props ;
2024-04-29 22:13:12 +03:00
p_original - > get_property_list ( & props ) ;
2024-05-13 12:26:34 +02:00
const StringName & script_property_name = CoreStringName ( script ) ;
2024-04-29 22:13:12 +03:00
if ( p_flags & DUPLICATE_SCRIPTS ) {
bool is_valid = false ;
Variant scr = p_original - > get ( script_property_name , & is_valid ) ;
if ( is_valid ) {
p_copy - > set ( script_property_name , scr ) ;
}
}
2024-01-19 22:57:31 +02:00
for ( const PropertyInfo & E : props ) {
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
continue ;
}
2024-04-29 22:13:12 +03:00
const StringName name = E . name ;
if ( name = = script_property_name ) {
continue ;
}
Overhaul `Variant::duplicate()` for resources
This in the scope of a duplication triggered via any type in the `Variant` realm. that is, the following: `Variant` itself, `Array` and `Dictionary`. That includes invoking `duplicate()` from scripts.
A `duplicate_deep(deep_subresources_mode)` method is added to `Variant`, `Array` and `Dictionary` (for compatibility reasons, simply adding an extra parameter was not possible). The default value for it is `RESOURCE_DEEP_DUPLICATE_NONE`, which is like calling `duplicate(true)`.
Remarks:
- The results of copying resources via those `Variant` types are exactly the same as if the copy were initiated from the `Resource` type at C++.
- In order to keep some separation between `Variant` and the higher-level animal which is `Resource`, `Variant` still contains the original code for that, so it's self-sufficient unless there's a `Resource` involved. Once the deep copy finds a `Resource` that has to be copied according to the duplication parameters, the algorithm invokes the `Resource` duplication machinery. When the stack is unwind back to a nesting level `Variant` can handle, `Variant` duplication logic keeps functioning.
While that is good from a responsibility separation standpoint, that would have a caveat: `Variant` would not be aware of the mapping between original and duplicate subresources and so wouldn't be able to keep preventing multiple duplicates.
To avoid that, this commit also introduces a wormwhole, a sharing mechanism by which `Variant` and `Resource` can collaborate in managing the lifetime of the original-to-duplicates map. The user-visible benefit is that the overduplicate prevention works as broadly as the whole `Variant` entity being copied, including all nesting levels, regardless how disconnected the data members containing resources may be across al the nesting levels. In other words, despite the aforementioned division of duties between `Variant` and `Resource` duplication logic, the duplicates map is shared among them. It's created when first finding a `Resource` and, however how deep the copy was working at that point, the map kept alive unitl the stack is unwind to the root user call, until the first step of the recursion.
Thanks to that common map of duplicates, this commit is able to fix the issue that `Resource::duplicate_for_local_scene()` used to ignore overridden duplicate logic.
2025-01-21 11:55:23 +01:00
Variant value = p_original - > get ( name ) ;
// To keep classic behavior, because, in contrast, nowadays a resource would be duplicated.
if ( value . get_type ( ) ! = Variant : : OBJECT ) {
value = value . duplicate ( true ) ;
}
2024-04-29 22:13:12 +03:00
if ( E . usage & PROPERTY_USAGE_ALWAYS_DUPLICATE ) {
Resource * res = Object : : cast_to < Resource > ( value ) ;
if ( res ) { // Duplicate only if it's a resource
p_copy - > set ( name , res - > duplicate ( ) ) ;
2024-01-19 22:57:31 +02:00
}
2024-04-29 22:13:12 +03:00
} else {
if ( value . get_type ( ) = = Variant : : OBJECT ) {
Node * property_node = Object : : cast_to < Node > ( value ) ;
Variant out_value = value ;
if ( property_node & & ( p_root = = property_node | | p_root - > is_ancestor_of ( property_node ) ) ) {
out_value = p_copy - > get_node_or_null ( p_original - > get_path_to ( property_node ) ) ;
}
p_copy - > set ( name , out_value ) ;
} else if ( value . get_type ( ) = = Variant : : ARRAY ) {
Array arr = value ;
if ( arr . get_typed_builtin ( ) = = Variant : : OBJECT ) {
for ( int i = 0 ; i < arr . size ( ) ; i + + ) {
Node * property_node = Object : : cast_to < Node > ( arr [ i ] ) ;
if ( property_node & & ( p_root = = property_node | | p_root - > is_ancestor_of ( property_node ) ) ) {
arr [ i ] = p_copy - > get_node_or_null ( p_original - > get_path_to ( property_node ) ) ;
}
2024-01-19 22:57:31 +02:00
}
}
2024-06-27 19:17:50 +02:00
p_copy - > set ( name , arr ) ;
2024-04-29 22:13:12 +03:00
} else {
2024-01-19 22:57:31 +02:00
p_copy - > set ( name , value ) ;
}
}
}
2024-03-13 13:22:42 +01:00
for ( int i = 0 ; i < p_original - > get_child_count ( false ) ; i + + ) {
Node * copy_child = p_copy - > get_child ( i , false ) ;
2024-05-07 21:43:13 +02:00
ERR_FAIL_NULL_MSG ( copy_child , " Child node disappeared while duplicating. " ) ;
2024-03-13 13:22:42 +01:00
_duplicate_properties ( p_root , p_original - > get_child ( i , false ) , copy_child , p_flags ) ;
2024-01-19 22:57:31 +02:00
}
}
2017-11-19 13:05:18 +01: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
2015-05-10 15:45:33 -03:00
void Node : : _duplicate_signals ( const Node * p_original , Node * p_copy ) const {
2021-06-18 16:02:50 -06:00
if ( ( this ! = p_original ) & & ! ( p_original - > is_ancestor_of ( this ) ) ) {
2015-05-10 15:45:33 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2015-05-10 15:45:33 -03:00
2020-06-08 17:19:50 +08: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 17:19:50 +08:00
const Node * n = process_list . front ( ) - > get ( ) ;
process_list . pop_front ( ) ;
2015-05-10 15:45:33 -03:00
2020-06-08 17:19:50 +08:00
List < Connection > conns ;
n - > get_all_signal_connections ( & conns ) ;
2015-05-10 15:45:33 -03:00
2021-07-24 15:46:25 +02:00
for ( const Connection & E : conns ) {
2021-07-15 23:45:57 -04:00
if ( E . flags & CONNECT_PERSIST ) {
2020-06-08 17:19:50 +08:00
//user connected
NodePath p = p_original - > get_path_to ( n ) ;
Node * copy = p_copy - > get_node ( p ) ;
2015-05-10 15:45:33 -03:00
2021-07-15 23:45:57 -04:00
Node * target = Object : : cast_to < Node > ( E . callable . get_object ( ) ) ;
2020-06-08 17:19:50 +08:00
if ( ! target ) {
continue ;
}
2024-08-31 10:41:19 +01:00
2020-06-08 17:19:50 +08:00
NodePath ptarget = p_original - > get_path_to ( target ) ;
2024-08-31 10:41:19 +01:00
if ( ptarget . is_empty ( ) ) {
continue ;
}
2018-10-03 14:59:16 +02:00
2020-06-08 17:19:50 +08:00
Node * copytarget = target ;
2018-10-03 14:59:16 +02:00
2020-06-08 17:19:50 +08: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 13:05:18 +01:00
2020-06-08 17:19:50 +08:00
if ( p_copy - > has_node ( ptarget ) ) {
copytarget = p_copy - > get_node ( ptarget ) ;
}
2023-08-16 14:02:43 +02:00
if ( copy & & copytarget & & E . callable . get_method ( ) ! = StringName ( ) ) {
Callable copy_callable = Callable ( copytarget , E . callable . get_method ( ) ) ;
2021-07-15 23:45:57 -04:00
if ( ! copy - > is_connected ( E . signal . get_name ( ) , copy_callable ) ) {
2024-11-01 02:28:21 +03:00
int unbound_arg_count = E . callable . get_unbound_arguments_count ( ) ;
if ( unbound_arg_count > 0 ) {
copy_callable = copy_callable . unbind ( unbound_arg_count ) ;
}
if ( E . callable . get_bound_arguments_count ( ) > 0 ) {
2023-08-16 14:02:43 +02:00
copy_callable = copy_callable . bindv ( E . callable . get_bound_arguments ( ) ) ;
}
2022-07-28 22:56:41 +02:00
copy - > connect ( E . signal . get_name ( ) , copy_callable , E . flags ) ;
2020-06-08 17:19:50 +08:00
}
2020-02-21 23:26:13 +01:00
}
2015-05-10 15:45:33 -03:00
}
}
2020-06-08 17:19:50 +08:00
for ( int i = 0 ; i < n - > get_child_count ( ) ; i + + ) {
process_list . push_back ( n - > get_child ( i ) ) ;
}
2015-05-10 15:45:33 -03:00
}
}
2014-02-09 22:10:30 -03:00
static void find_owned_by ( Node * p_by , Node * p_node , List < Node * > * p_owned ) {
2020-05-14 16:41:43 +02:00
if ( p_node - > get_owner ( ) = = p_by ) {
2014-02-09 22:10:30 -03:00
p_owned - > push_back ( p_node ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
find_owned_by ( p_by , p_node - > get_child ( i ) , p_owned ) ;
}
}
2024-04-09 18:07:07 +02:00
void Node : : replace_by ( Node * p_node , bool p_keep_groups ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2014-02-09 22:10:30 -03:00
ERR_FAIL_NULL ( p_node ) ;
ERR_FAIL_COND ( p_node - > data . parent ) ;
List < Node * > owned = data . owned ;
List < Node * > owned_by_owner ;
Node * owner = ( data . owner = = this ) ? p_node : data . owner ;
2021-01-31 13:55:13 +01:00
if ( p_keep_groups ) {
2016-11-03 00:19:32 +01:00
List < GroupInfo > groups ;
get_groups ( & groups ) ;
2021-07-24 15:46:25 +02:00
for ( const GroupInfo & E : groups ) {
2021-07-15 23:45:57 -04:00
p_node - > add_to_group ( E . name , E . persistent ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
2016-06-09 16:24:12 +02:00
_replace_connections_target ( p_node ) ;
2014-02-09 22:10:30 -03:00
if ( data . owner ) {
2024-04-09 18:07:07 +02:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
find_owned_by ( data . owner , get_child ( i ) , & owned_by_owner ) ;
2020-05-14 16:41:43 +02:00
}
2024-04-09 18:07:07 +02:00
2023-02-27 16:16:51 +08:00
_clean_up_owner ( ) ;
2014-02-09 22:10:30 -03:00
}
2024-04-09 18:07:07 +02:00
2014-02-09 22:10:30 -03:00
Node * parent = data . parent ;
2024-01-03 13:04:16 +01:00
int index_in_parent = get_index ( false ) ;
2014-02-09 22:10:30 -03:00
if ( data . parent ) {
parent - > remove_child ( this ) ;
parent - > add_child ( p_node ) ;
2022-10-14 19:21:41 +01:00
parent - > move_child ( p_node , index_in_parent ) ;
2014-02-09 22:10:30 -03:00
}
2022-11-13 14:52:37 +08:00
emit_signal ( SNAME ( " replacing_by " ) , p_node ) ;
2024-04-09 18:07:07 +02:00
while ( get_child_count ( ) ) {
Node * child = get_child ( 0 ) ;
remove_child ( child ) ;
2024-03-13 13:22:42 +01:00
if ( ! child - > is_internal ( ) ) {
// Add the custom children to the p_node.
2024-04-09 18:07:07 +02:00
Node * child_owner = child - > get_owner ( ) = = this ? p_node : child - > get_owner ( ) ;
child - > set_owner ( nullptr ) ;
p_node - > add_child ( child ) ;
child - > set_owner ( child_owner ) ;
2018-03-07 08:21:46 +08:00
}
2024-04-09 18:07:07 +02:00
}
2014-02-09 22:10:30 -03:00
2024-04-09 18:07:07 +02:00
p_node - > set_owner ( owner ) ;
for ( Node * E : owned ) {
if ( E - > data . owner ! = p_node ) {
E - > set_owner ( p_node ) ;
2024-02-26 22:24:57 +01:00
}
2024-04-09 18:07:07 +02:00
}
2014-02-09 22:10:30 -03:00
2024-04-09 18:07:07 +02:00
for ( Node * E : owned_by_owner ) {
if ( E - > data . owner ! = owner ) {
E - > set_owner ( owner ) ;
2024-02-26 22:24:57 +01:00
}
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2021-09-30 16:30:55 +02:00
p_node - > set_scene_file_path ( get_scene_file_path ( ) ) ;
2014-02-09 22:10:30 -03:00
}
2016-06-09 16:24:12 +02:00
void Node : : _replace_connections_target ( Node * p_new_target ) {
List < Connection > cl ;
get_signals_connected_to_this ( & cl ) ;
2021-07-24 15:46:25 +02:00
for ( const Connection & c : cl ) {
2017-03-11 20:21:04 +01:00
if ( c . flags & CONNECT_PERSIST ) {
2020-02-21 23:26:13 +01:00
c . signal . get_object ( ) - > disconnect ( c . signal . get_name ( ) , Callable ( this , c . callable . get_method ( ) ) ) ;
2020-02-19 16:27:19 -03: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 16:42:47 +02: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 22:56:41 +02:00
c . signal . get_object ( ) - > connect ( c . signal . get_name ( ) , Callable ( p_new_target , c . callable . get_method ( ) ) , c . flags ) ;
2017-03-11 20:21:04 +01:00
}
2016-06-09 16:24:12 +02:00
}
}
2014-02-09 22:10:30 -03:00
bool Node : : has_node_and_resource ( const NodePath & p_path ) const {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD_V ( false ) ;
2020-05-14 16:41:43 +02:00
if ( ! has_node ( p_path ) ) {
2014-02-09 22:10:30 -03:00
return false ;
2020-05-14 16:41:43 +02:00
}
2022-05-03 01:43:50 +02:00
Ref < Resource > res ;
2019-06-26 15:15:11 +02:00
Vector < StringName > leftover_path ;
Node * node = get_node_and_resource ( p_path , res , leftover_path , false ) ;
2014-02-09 22:10:30 -03:00
2019-07-10 21:03:04 +03:00
return node ;
2014-02-09 22:10:30 -03:00
}
Array Node : : _get_node_and_resource ( const NodePath & p_path ) {
2022-05-03 01:43:50 +02:00
Ref < Resource > res ;
2017-05-30 23:20:15 +03:00
Vector < StringName > leftover_path ;
2019-06-26 15:15:11 +02:00
Node * node = get_node_and_resource ( p_path , res , leftover_path , false ) ;
2014-02-09 22:10:30 -03:00
Array result ;
2020-05-14 16:41:43 +02:00
if ( node ) {
2014-02-09 22:10:30 -03:00
result . push_back ( node ) ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-09 22:10:30 -03:00
result . push_back ( Variant ( ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2020-05-14 16:41:43 +02:00
if ( res . is_valid ( ) ) {
2014-02-09 22:10:30 -03:00
result . push_back ( res ) ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-09 22:10:30 -03:00
result . push_back ( Variant ( ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2017-05-30 23:20:15 +03:00
result . push_back ( NodePath ( Vector < StringName > ( ) , leftover_path , false ) ) ;
2014-02-09 22:10:30 -03:00
return result ;
}
2022-05-03 01:43:50 +02: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 18:45:53 +02:00
ERR_THREAD_GUARD_V ( nullptr ) ;
2022-05-03 01:43:50 +02:00
r_res = Ref < Resource > ( ) ;
2017-05-30 23:20:15 +03:00
r_leftover_subpath = Vector < StringName > ( ) ;
2024-02-19 09:29:36 -05:00
Node * node = get_node_or_null ( p_path ) ;
2020-05-14 16:41:43 +02:00
if ( ! node ) {
2020-04-02 01:20:12 +02:00
return nullptr ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
if ( p_path . get_subname_count ( ) ) {
2017-05-30 23:20:15 +03: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 15:15:11 +02:00
for ( ; j < p_path . get_subname_count ( ) - ( int ) p_last_is_property ; j + + ) {
2022-05-16 19:40:59 +02: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 21:03:04 +03:00
2022-05-16 19:40:59 +02:00
if ( ! is_valid ) { // Found nothing on that path
2020-04-02 01:20:12 +02:00
return nullptr ;
2019-07-10 21:03:04 +03:00
}
2022-05-03 01:43:50 +02:00
Ref < Resource > new_res = new_res_v ;
2017-05-30 23:20:15 +03:00
2019-07-10 21:03:04 +03:00
if ( new_res . is_null ( ) ) { // No longer a resource, assume property
2017-05-30 23:20:15 +03: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-09 22:10:30 -03:00
}
}
return node ;
}
2014-11-05 21:20:42 -03:00
void Node : : _set_tree ( SceneTree * p_tree ) {
2020-04-02 01:20:12 +02:00
SceneTree * tree_changed_a = nullptr ;
SceneTree * tree_changed_b = nullptr ;
2014-02-09 22:10:30 -03:00
2017-01-14 12:26:56 +01:00
//ERR_FAIL_COND(p_scene && data.parent && !data.parent->data.scene); //nobug if both are null
2014-02-09 22:10:30 -03:00
2014-11-05 21:20:42 -03:00
if ( data . tree ) {
_propagate_exit_tree ( ) ;
2014-02-09 22:10:30 -03:00
2014-11-05 21:20:42 -03:00
tree_changed_a = data . tree ;
2014-02-09 22:10:30 -03:00
}
2014-11-05 21:20:42 -03:00
data . tree = p_tree ;
2014-02-09 22:10:30 -03:00
2014-11-05 21:20:42 -03:00
if ( data . tree ) {
_propagate_enter_tree ( ) ;
2016-11-30 00:07:29 +01:00
if ( ! data . parent | | data . parent - > data . ready_notified ) { // No parent (root) or parent ready
_propagate_ready ( ) ; //reverse_notification(NOTIFICATION_READY);
}
2014-02-09 22:10:30 -03:00
2014-11-05 21:20:42 -03:00
tree_changed_b = data . tree ;
2014-02-09 22:10:30 -03:00
}
2020-05-14 16:41:43 +02:00
if ( tree_changed_a ) {
2014-02-09 22:10:30 -03:00
tree_changed_a - > tree_changed ( ) ;
2020-05-14 16:41:43 +02:00
}
if ( tree_changed_b ) {
2014-02-09 22:10:30 -03:00
tree_changed_b - > tree_changed ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
2018-10-03 16:13:34 +02:00
# ifdef DEBUG_ENABLED
2023-03-09 16:47:38 +01:00
static HashMap < ObjectID , List < String > > _print_orphan_nodes_map ;
static void _print_orphan_nodes_routine ( Object * p_obj ) {
2017-08-24 22:58:51 +02:00
Node * n = Object : : cast_to < Node > ( p_obj ) ;
2020-05-14 16:41:43 +02:00
if ( ! n ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2020-05-14 16:41:43 +02:00
if ( n - > is_inside_tree ( ) ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
Node * p = n ;
while ( p - > get_parent ( ) ) {
p = p - > get_parent ( ) ;
}
String path ;
2020-05-14 16:41:43 +02:00
if ( p = = n ) {
2014-02-09 22:10:30 -03:00
path = n - > get_name ( ) ;
2020-05-14 16:41:43 +02:00
} else {
2025-06-11 16:19:23 +02:00
path = String ( p - > get_name ( ) ) + " / " + String ( p - > get_path_to ( n ) ) ;
2020-05-14 16:41:43 +02:00
}
2023-03-09 16:47:38 +01:00
2023-10-20 21:30:21 -07:00
String source ;
Variant script = n - > get_script ( ) ;
if ( ! script . is_null ( ) ) {
Resource * obj = Object : : cast_to < Resource > ( script ) ;
source = obj - > get_path ( ) ;
}
2023-03-09 16:47:38 +01:00
List < String > info_strings ;
info_strings . push_back ( path ) ;
info_strings . push_back ( n - > get_class ( ) ) ;
2023-10-20 21:30:21 -07:00
info_strings . push_back ( source ) ;
2023-03-09 16:47:38 +01:00
_print_orphan_nodes_map [ p_obj - > get_instance_id ( ) ] = info_strings ;
2014-02-09 22:10:30 -03:00
}
2018-10-03 16:13:34 +02:00
# endif // DEBUG_ENABLED
2014-02-09 22:10:30 -03:00
2022-03-27 19:30:49 +02:00
void Node : : print_orphan_nodes ( ) {
2014-02-09 22:10:30 -03:00
# ifdef DEBUG_ENABLED
2023-03-09 16:47:38 +01: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 ) {
2023-10-20 21:30:21 -07:00
print_line ( itos ( E . key ) + " - Stray Node: " + E . value . get ( 0 ) + " (Type: " + E . value . get ( 1 ) + " ) (Source: " + E . value . get ( 2 ) + " ) " ) ;
}
// Flush it after use.
_print_orphan_nodes_map . clear ( ) ;
# endif
}
TypedArray < int > Node : : get_orphan_node_ids ( ) {
TypedArray < int > ret ;
# ifdef DEBUG_ENABLED
// Make sure it's empty.
_print_orphan_nodes_map . clear ( ) ;
// Collect and return information about orphan nodes.
ObjectDB : : debug_objects ( _print_orphan_nodes_routine ) ;
for ( const KeyValue < ObjectID , List < String > > & E : _print_orphan_nodes_map ) {
ret . push_back ( E . key ) ;
2023-03-09 16:47:38 +01:00
}
// Flush it after use.
_print_orphan_nodes_map . clear ( ) ;
2014-02-09 22:10:30 -03:00
# endif
2023-10-20 21:30:21 -07:00
return ret ;
2014-02-09 22:10:30 -03:00
}
2022-10-24 22:07:02 +01:00
void Node : : queue_free ( ) {
2022-10-25 09:31:56 +08:00
// There are users which instantiate multiple scene trees for their games.
// Use the node's own tree to handle its deletion when relevant.
2025-05-28 15:24:49 +02:00
if ( data . tree ) {
data . tree - > queue_delete ( this ) ;
2017-09-20 21:49:46 +02:00
} else {
2022-10-25 09:31:56 +08: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 21:49:46 +02:00
}
2014-02-09 22:10:30 -03:00
}
2014-06-19 02:23:03 -03:00
void Node : : set_import_path ( const NodePath & p_import_path ) {
2018-04-29 19:49:26 +02:00
# ifdef TOOLS_ENABLED
2014-06-19 02:23:03 -03:00
data . import_path = p_import_path ;
2018-04-29 19:49:26 +02:00
# endif
2014-06-19 02:23:03 -03:00
}
NodePath Node : : get_import_path ( ) const {
2018-04-29 19:49:26 +02:00
# ifdef TOOLS_ENABLED
2014-06-19 02:23:03 -03:00
return data . import_path ;
2018-04-29 19:49:26 +02:00
# else
return NodePath ( ) ;
2014-06-19 02:23:03 -03:00
# endif
2018-04-29 19:49:26 +02:00
}
2014-06-19 02:23:03 -03:00
2024-01-03 12:10:11 +01:00
# ifdef TOOLS_ENABLED
2014-12-16 22:31:57 -03:00
static void _add_nodes_to_options ( const Node * p_base , const Node * p_node , List < String > * r_options ) {
2020-05-14 16:41:43 +02:00
if ( p_node ! = p_base & & ! p_node - > get_owner ( ) ) {
2014-12-16 22:31:57 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2023-11-26 15:41:29 +01:00
if ( p_node - > is_unique_name_in_owner ( ) & & p_node - > get_owner ( ) = = p_base ) {
String n = " % " + p_node - > get_name ( ) ;
r_options - > push_back ( n . quote ( ) ) ;
}
2025-06-11 16:19:23 +02:00
String n = String ( p_base - > get_path_to ( p_node ) ) ;
2021-10-01 17:06:48 +02:00
r_options - > push_back ( n . quote ( ) ) ;
2014-12-16 22:31:57 -03: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 ) ;
}
}
void Node : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
2024-01-03 12:10:11 +01:00
const String pf = p_function ;
2024-01-06 17:33:32 +01:00
if ( p_idx = = 0 & & ( pf = = " has_node " | | pf = = " get_node " | | pf = = " get_node_or_null " ) ) {
2014-12-16 22:31:57 -03:00
_add_nodes_to_options ( this , this , r_options ) ;
2022-05-12 15:20:12 +07:00
} else if ( p_idx = = 0 & & ( pf = = " add_to_group " | | pf = = " remove_from_group " | | pf = = " is_in_group " ) ) {
HashMap < StringName , String > global_groups = ProjectSettings : : get_singleton ( ) - > get_global_groups_list ( ) ;
for ( const KeyValue < StringName , String > & E : global_groups ) {
r_options - > push_back ( E . key . operator String ( ) . quote ( ) ) ;
}
2014-12-16 22:31:57 -03:00
}
Object : : get_argument_options ( p_function , p_idx , r_options ) ;
}
2024-01-03 12:10:11 +01:00
# endif
2014-02-09 22:10:30 -03:00
2015-06-22 00:03:19 -03:00
void Node : : clear_internal_tree_resource_paths ( ) {
clear_internal_resource_paths ( ) ;
2023-04-03 22:31:47 +02:00
for ( KeyValue < StringName , Node * > & K : data . children ) {
K . value - > clear_internal_tree_resource_paths ( ) ;
2015-06-22 00:03:19 -03:00
}
}
2025-03-21 16:42:23 +02:00
PackedStringArray Node : : get_accessibility_configuration_warnings ( ) const {
ERR_THREAD_GUARD_V ( PackedStringArray ( ) ) ;
PackedStringArray ret ;
Vector < String > warnings ;
if ( GDVIRTUAL_CALL ( _get_accessibility_configuration_warnings , warnings ) ) {
ret . append_array ( warnings ) ;
}
return ret ;
}
2024-02-17 19:04:18 +01:00
PackedStringArray Node : : get_configuration_warnings ( ) const {
ERR_THREAD_GUARD_V ( PackedStringArray ( ) ) ;
PackedStringArray ret ;
2022-04-16 12:23:32 +02:00
2024-02-17 19:04:18 +01:00
Vector < String > warnings ;
if ( GDVIRTUAL_CALL ( _get_configuration_warnings , warnings ) ) {
2023-07-05 14:45:10 +02:00
ret . append_array ( warnings ) ;
}
2024-02-17 19:04:18 +01:00
return ret ;
2023-07-05 14:45:10 +02:00
}
2020-10-29 05:01:28 -05:00
void Node : : update_configuration_warnings ( ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2016-05-17 18:27:15 -03:00
# ifdef TOOLS_ENABLED
2025-05-28 15:24:49 +02:00
if ( ! data . tree ) {
2016-05-17 18:27:15 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2025-05-28 15:24:49 +02:00
if ( data . tree - > get_edited_scene_root ( ) & & ( data . tree - > get_edited_scene_root ( ) = = this | | data . tree - > get_edited_scene_root ( ) - > is_ancestor_of ( this ) ) ) {
data . tree - > emit_signal ( SceneStringName ( node_configuration_warning_changed ) , this ) ;
2016-05-17 18:27:15 -03:00
}
# endif
}
2016-06-28 13:10:15 -03:00
void Node : : set_display_folded ( bool p_folded ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2016-06-28 13:10:15 -03:00
data . display_folded = p_folded ;
}
bool Node : : is_displayed_folded ( ) const {
return data . display_folded ;
}
2023-04-06 14:47:49 +02:00
bool Node : : is_ready ( ) const {
return ! data . ready_first ;
}
2017-01-10 18:02:19 -03:00
void Node : : request_ready ( ) {
2023-04-10 18:45:53 +02:00
ERR_THREAD_GUARD
2017-01-10 18:02:19 -03:00
data . ready_first = true ;
}
2021-08-22 12:37:22 -03:00
void Node : : _call_input ( const Ref < InputEvent > & p_event ) {
2022-11-28 22:54:47 +01:00
if ( p_event - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL ) {
GDVIRTUAL_CALL ( _input , p_event ) ;
}
2021-08-22 12:37:22 -03:00
if ( ! is_inside_tree ( ) | | ! get_viewport ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
return ;
}
input ( p_event ) ;
}
2022-01-11 15:59:52 +02:00
void Node : : _call_shortcut_input ( const Ref < InputEvent > & p_event ) {
2022-11-28 22:54:47 +01:00
if ( p_event - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL ) {
GDVIRTUAL_CALL ( _shortcut_input , p_event ) ;
}
2022-01-11 15:59:52 +02:00
if ( ! is_inside_tree ( ) | | ! get_viewport ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
return ;
}
shortcut_input ( p_event ) ;
}
2021-08-22 12:37:22 -03:00
void Node : : _call_unhandled_input ( const Ref < InputEvent > & p_event ) {
2022-11-28 22:54:47 +01:00
if ( p_event - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL ) {
GDVIRTUAL_CALL ( _unhandled_input , p_event ) ;
}
2021-08-22 12:37:22 -03:00
if ( ! is_inside_tree ( ) | | ! get_viewport ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
return ;
}
unhandled_input ( p_event ) ;
}
2022-01-11 15:59:52 +02:00
2021-08-22 12:37:22 -03:00
void Node : : _call_unhandled_key_input ( const Ref < InputEvent > & p_event ) {
2022-11-28 22:54:47 +01:00
if ( p_event - > get_device ( ) ! = InputEvent : : DEVICE_ID_INTERNAL ) {
GDVIRTUAL_CALL ( _unhandled_key_input , p_event ) ;
}
2021-08-22 12:37:22 -03:00
if ( ! is_inside_tree ( ) | | ! get_viewport ( ) | | get_viewport ( ) - > is_input_handled ( ) ) {
return ;
}
unhandled_key_input ( p_event ) ;
}
2023-04-10 18:45:53 +02: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 12:37:22 -03:00
void Node : : input ( const Ref < InputEvent > & p_event ) {
}
2022-01-11 15:59:52 +02:00
void Node : : shortcut_input ( const Ref < InputEvent > & p_key_event ) {
}
2021-08-22 12:37:22 -03:00
void Node : : unhandled_input ( const Ref < InputEvent > & p_event ) {
}
void Node : : unhandled_key_input ( const Ref < InputEvent > & p_key_event ) {
}
2023-04-10 18:45:53 +02: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 ;
2023-09-29 19:19:46 +03:00
r_error . expected = 1 ;
2023-04-10 18:45:53 +02:00
return Variant ( ) ;
}
2023-12-28 14:44:23 -08:00
if ( ! p_args [ 0 ] - > is_string ( ) ) {
2023-04-10 18:45:53 +02:00
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 ;
2023-09-29 19:19:46 +03:00
r_error . expected = 1 ;
2023-04-10 18:45:53 +02:00
return Variant ( ) ;
}
2023-12-28 14:44:23 -08:00
if ( ! p_args [ 0 ] - > is_string ( ) ) {
2023-04-10 18:45:53 +02:00
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 ) ;
}
2025-03-21 16:42:23 +02:00
2023-04-10 18:45:53 +02:00
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 ) ;
}
2025-03-21 16:42:23 +02:00
2023-04-10 18:45:53 +02:00
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 ) ;
}
}
2025-03-21 16:42:23 +02:00
2023-04-10 18:45:53 +02:00
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 ) ;
}
}
2025-03-21 16:42:23 +02:00
2023-04-10 18:45:53 +02:00
void Node : : notify_thread_safe ( int p_notification ) {
if ( is_accessible_from_caller_thread ( ) ) {
notification ( p_notification ) ;
} else {
notify_deferred_thread_group ( p_notification ) ;
}
}
2025-03-21 16:42:23 +02:00
RID Node : : get_focused_accessibility_element ( ) const {
RID id ;
if ( GDVIRTUAL_CALL ( _get_focused_accessibility_element , id ) ) {
return id ;
} else {
return get_accessibility_element ( ) ;
}
}
void Node : : queue_accessibility_update ( ) {
if ( is_inside_tree ( ) & & ! is_part_of_edited_scene ( ) ) {
2025-05-28 15:24:49 +02:00
data . tree - > _accessibility_notify_change ( this ) ;
2025-03-21 16:42:23 +02:00
}
}
RID Node : : get_accessibility_element ( ) const {
if ( is_part_of_edited_scene ( ) ) {
return RID ( ) ;
}
if ( unlikely ( data . accessibility_element . is_null ( ) ) ) {
if ( get_window ( ) & & get_window ( ) - > get_window_id ( ) ! = DisplayServer : : INVALID_WINDOW_ID ) {
data . accessibility_element = DisplayServer : : get_singleton ( ) - > accessibility_create_element ( get_window ( ) - > get_window_id ( ) , DisplayServer : : ROLE_CONTAINER ) ;
}
}
return data . accessibility_element ;
}
2014-02-09 22:10:30 -03:00
void Node : : _bind_methods ( ) {
2023-01-12 11:41:13 +03:00
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " editor/naming/node_name_num_separator " , PROPERTY_HINT_ENUM , " None,Space,Underscore,Dash " ) , 0 ) ;
2024-07-28 21:32:28 +02:00
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " editor/naming/node_name_casing " , PROPERTY_HINT_ENUM , " PascalCase,camelCase,snake_case,kebab-case " ) , NAME_CASING_PASCAL_CASE ) ;
2016-10-07 20:25:29 +02:00
2022-11-12 16:54:06 +01:00
ClassDB : : bind_static_method ( " Node " , D_METHOD ( " print_orphan_nodes " ) , & Node : : print_orphan_nodes ) ;
2023-10-20 21:30:21 -07:00
ClassDB : : bind_static_method ( " Node " , D_METHOD ( " get_orphan_node_ids " ) , & Node : : get_orphan_node_ids ) ;
2022-08-15 19:55:38 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_sibling " , " sibling " , " force_readable_name " ) , & Node : : add_sibling , DEFVAL ( false ) ) ;
2017-02-13 12:47:24 +01: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 19:55:38 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_child " , " node " , " force_readable_name " , " internal " ) , & Node : : add_child , DEFVAL ( false ) , DEFVAL ( 0 ) ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " remove_child " , " node " ) , & Node : : remove_child ) ;
2020-02-17 18:29:14 +01:00
ClassDB : : bind_method ( D_METHOD ( " reparent " , " new_parent " , " keep_global_transform " ) , & Node : : reparent , DEFVAL ( true ) ) ;
2021-08-25 15:49:30 +02: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-07 20:27:50 -06:00
ClassDB : : bind_method ( D_METHOD ( " get_children " , " include_internal " ) , & Node : : get_children , DEFVAL ( false ) ) ;
2021-08-25 15:49:30 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_child " , " idx " , " include_internal " ) , & Node : : get_child , DEFVAL ( false ) ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " has_node " , " path " ) , & Node : : has_node ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_node " , " path " ) , & Node : : get_node ) ;
2019-01-29 08:15:34 -08:00
ClassDB : : bind_method ( D_METHOD ( " get_node_or_null " , " path " ) , & Node : : get_node_or_null ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_parent " ) , & Node : : get_parent ) ;
2022-04-25 15:16:44 +02: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-02-13 12:47:24 +01: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 ) ;
2017-03-05 16:44:50 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_inside_tree " ) , & Node : : is_inside_tree ) ;
2023-11-29 16:54:34 +01:00
ClassDB : : bind_method ( D_METHOD ( " is_part_of_edited_scene " ) , & Node : : is_part_of_edited_scene ) ;
2021-06-18 16:02:50 -06:00
ClassDB : : bind_method ( D_METHOD ( " is_ancestor_of " , " node " ) , & Node : : is_ancestor_of ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_greater_than " , " node " ) , & Node : : is_greater_than ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_path " ) , & Node : : get_path ) ;
2022-11-19 07:23:38 +09:00
ClassDB : : bind_method ( D_METHOD ( " get_path_to " , " node " , " use_unique_path " ) , & Node : : get_path_to , DEFVAL ( false ) ) ;
2017-02-13 12:47:24 +01: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 19:21:41 +01:00
ClassDB : : bind_method ( D_METHOD ( " move_child " , " child_node " , " to_index " ) , & Node : : move_child ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_groups " ) , & Node : : _get_groups ) ;
2017-08-09 13:19:41 +02: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 15:49:30 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_index " , " include_internal " ) , & Node : : get_index , DEFVAL ( false ) ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " print_tree " ) , & Node : : print_tree ) ;
2018-02-28 10:12:06 +01:00
ClassDB : : bind_method ( D_METHOD ( " print_tree_pretty " ) , & Node : : print_tree_pretty ) ;
2023-05-21 18:04:03 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_tree_string " ) , & Node : : get_tree_string ) ;
ClassDB : : bind_method ( D_METHOD ( " get_tree_string_pretty " ) , & Node : : get_tree_string_pretty ) ;
2021-09-30 16:30:55 +02: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-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " propagate_notification " , " what " ) , & Node : : propagate_notification ) ;
2017-08-19 15:17:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " propagate_call " , " method " , " args " , " parent_first " ) , & Node : : propagate_call , DEFVAL ( Array ( ) ) , DEFVAL ( false ) ) ;
2017-09-30 16:19:07 +02: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-02-13 12:47:24 +01: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 07:30:40 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_process_priority " , " priority " ) , & Node : : set_process_priority ) ;
2019-11-16 22:07:02 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_process_priority " ) , & Node : : get_process_priority ) ;
2023-04-10 18:45:53 +02: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-02-13 12:47:24 +01: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 15:59:52 +02: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-02-13 12:47:24 +01: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 15:52:29 -03: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-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " can_process " ) , & Node : : can_process ) ;
2019-04-11 14:35:23 -03:00
2023-04-10 18:45:53 +02: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 ) ;
2025-03-21 16:42:23 +02:00
ClassDB : : bind_method ( D_METHOD ( " queue_accessibility_update " ) , & Node : : queue_accessibility_update ) ;
ClassDB : : bind_method ( D_METHOD ( " get_accessibility_element " ) , & Node : : get_accessibility_element ) ;
2017-02-13 12:47:24 +01: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 ) ;
2017-03-05 16:44:50 +01:00
2017-02-13 12:47:24 +01:00
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-03-05 16:44:50 +01:00
2017-09-30 16:19:07 +02: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 16:44:50 +01:00
2024-02-17 00:57:32 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_physics_interpolation_mode " , " mode " ) , & Node : : set_physics_interpolation_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_physics_interpolation_mode " ) , & Node : : get_physics_interpolation_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " is_physics_interpolated " ) , & Node : : is_physics_interpolated ) ;
ClassDB : : bind_method ( D_METHOD ( " is_physics_interpolated_and_enabled " ) , & Node : : is_physics_interpolated_and_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " reset_physics_interpolation " ) , & Node : : reset_physics_interpolation ) ;
2024-01-23 18:29:45 -03:00
ClassDB : : bind_method ( D_METHOD ( " set_auto_translate_mode " , " mode " ) , & Node : : set_auto_translate_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_auto_translate_mode " ) , & Node : : get_auto_translate_mode ) ;
2025-06-10 12:05:33 +08:00
ClassDB : : bind_method ( D_METHOD ( " can_auto_translate " ) , & Node : : can_auto_translate ) ;
2024-08-16 17:25:24 +08:00
ClassDB : : bind_method ( D_METHOD ( " set_translation_domain_inherited " ) , & Node : : set_translation_domain_inherited ) ;
2024-01-23 18:29:45 -03:00
2023-01-10 09:40:44 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_window " ) , & Node : : get_window ) ;
2023-04-20 15:13:21 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_last_exclusive_window " ) , & Node : : get_last_exclusive_window ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_tree " ) , & Node : : get_tree ) ;
2020-09-05 03:05:30 +02:00
ClassDB : : bind_method ( D_METHOD ( " create_tween " ) , & Node : : create_tween ) ;
2017-03-05 16:44:50 +01:00
2022-11-16 00:13:39 +01:00
ClassDB : : bind_method ( D_METHOD ( " duplicate " , " flags " ) , & Node : : duplicate , DEFVAL ( DUPLICATE_USE_INSTANTIATION | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS ) ) ;
2024-04-09 18:07:07 +02:00
ClassDB : : bind_method ( D_METHOD ( " replace_by " , " node " , " keep_groups " ) , & Node : : replace_by , DEFVAL ( false ) ) ;
2017-03-05 16:44:50 +01:00
2017-02-13 12:47:24 +01: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-22 19:18:29 -07: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 16:44:50 +01:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_viewport " ) , & Node : : get_viewport ) ;
2017-03-05 16:44:50 +01:00
2022-10-24 22:07:02 +01:00
ClassDB : : bind_method ( D_METHOD ( " queue_free " ) , & Node : : queue_free ) ;
2017-03-05 16:44:50 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " request_ready " ) , & Node : : request_ready ) ;
2023-04-06 14:47:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_node_ready " ) , & Node : : is_ready ) ;
2017-03-05 16:44:50 +01:00
2021-09-07 23:35:19 +02: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 16:44:50 +01:00
2021-09-07 23:35:19 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_multiplayer_authority " ) , & Node : : is_multiplayer_authority ) ;
2017-03-05 16:44:50 +01:00
2018-05-08 10:51:04 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_multiplayer " ) , & Node : : get_multiplayer ) ;
2022-07-12 23:12:42 +02:00
ClassDB : : bind_method ( D_METHOD ( " rpc_config " , " method " , " config " ) , & Node : : rpc_config ) ;
2025-05-26 22:17:21 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_node_rpc_config " ) , & Node : : _get_node_rpc_config_bind ) ;
2016-05-17 18:27:15 -03:00
2021-02-18 15:52:29 -03: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 14:50:26 +02:00
2017-02-13 12:47:24 +01: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 15:52:29 -03:00
2022-04-16 12:23:32 +02: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 ) ;
2024-01-23 18:29:45 -03:00
ClassDB : : bind_method ( D_METHOD ( " atr " , " message " , " context " ) , & Node : : atr , DEFVAL ( " " ) ) ;
ClassDB : : bind_method ( D_METHOD ( " atr_n " , " message " , " plural_message " , " n " , " context " ) , & Node : : atr_n , DEFVAL ( " " ) ) ;
2021-10-26 21:12:25 +02:00
# ifdef TOOLS_ENABLED
ClassDB : : bind_method ( D_METHOD ( " _set_property_pinned " , " property " , " pinned " ) , & Node : : set_property_pinned ) ;
# endif
2021-11-03 23:06:17 +01: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 02:23:03 -03:00
2016-08-14 18:49:50 -03:00
{
MethodInfo mi ;
2016-08-19 16:48:08 -03:00
2020-02-20 18:58:05 -03:00
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " method " ) ) ;
2016-08-14 18:49:50 -03:00
2016-08-19 16:48:08 -03:00
mi . name = " rpc " ;
2017-01-02 23:03:46 -03:00
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " rpc " , & Node : : _rpc_bind , mi ) ;
2024-05-07 12:48:51 +02:00
}
2016-08-14 18:49:50 -03:00
2024-05-07 12:48:51 +02:00
{
MethodInfo mi ;
mi . arguments . push_back ( PropertyInfo ( Variant : : INT , " peer_id " ) ) ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " method " ) ) ;
2016-08-14 18:49:50 -03:00
2016-08-19 16:48:08 -03:00
mi . name = " rpc_id " ;
2017-01-02 23:03:46 -03:00
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " rpc_id " , & Node : : _rpc_id_bind , mi ) ;
2016-08-14 18:49:50 -03:00
}
2020-10-29 05:01:28 -05:00
ClassDB : : bind_method ( D_METHOD ( " update_configuration_warnings " ) , & Node : : update_configuration_warnings ) ;
2019-10-17 12:20:35 +02:00
2023-04-10 18:45:53 +02: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 ) ;
2014-11-05 21:20:42 -03:00
BIND_CONSTANT ( NOTIFICATION_ENTER_TREE ) ;
BIND_CONSTANT ( NOTIFICATION_EXIT_TREE ) ;
2014-02-09 22:10:30 -03:00
BIND_CONSTANT ( NOTIFICATION_MOVED_IN_PARENT ) ;
BIND_CONSTANT ( NOTIFICATION_READY ) ;
2017-10-22 01:58:02 +07:00
BIND_CONSTANT ( NOTIFICATION_PAUSED ) ;
BIND_CONSTANT ( NOTIFICATION_UNPAUSED ) ;
2017-09-30 16:19:07 +02:00
BIND_CONSTANT ( NOTIFICATION_PHYSICS_PROCESS ) ;
2014-02-09 22:10:30 -03:00
BIND_CONSTANT ( NOTIFICATION_PROCESS ) ;
BIND_CONSTANT ( NOTIFICATION_PARENTED ) ;
BIND_CONSTANT ( NOTIFICATION_UNPARENTED ) ;
2022-08-15 00:50:31 +02:00
BIND_CONSTANT ( NOTIFICATION_SCENE_INSTANTIATED ) ;
2016-05-11 11:46:08 -03:00
BIND_CONSTANT ( NOTIFICATION_DRAG_BEGIN ) ;
BIND_CONSTANT ( NOTIFICATION_DRAG_END ) ;
2021-09-04 00:12:37 +02:00
BIND_CONSTANT ( NOTIFICATION_PATH_RENAMED ) ;
2023-04-05 18:53:32 +02:00
BIND_CONSTANT ( NOTIFICATION_CHILD_ORDER_CHANGED ) ;
2017-01-10 18:02:19 -03:00
BIND_CONSTANT ( NOTIFICATION_INTERNAL_PROCESS ) ;
2017-09-30 16:19:07 +02:00
BIND_CONSTANT ( NOTIFICATION_INTERNAL_PHYSICS_PROCESS ) ;
2020-08-12 13:31:32 +02:00
BIND_CONSTANT ( NOTIFICATION_POST_ENTER_TREE ) ;
2021-06-17 18:09:40 -07:00
BIND_CONSTANT ( NOTIFICATION_DISABLED ) ;
BIND_CONSTANT ( NOTIFICATION_ENABLED ) ;
2024-02-17 00:57:32 +01:00
BIND_CONSTANT ( NOTIFICATION_RESET_PHYSICS_INTERPOLATION ) ;
2017-03-05 16:44:50 +01: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 14:02:24 -04:00
BIND_CONSTANT ( NOTIFICATION_EDITOR_PRE_SAVE ) ;
BIND_CONSTANT ( NOTIFICATION_EDITOR_POST_SAVE ) ;
2019-04-04 10:34:03 -03:00
BIND_CONSTANT ( NOTIFICATION_WM_MOUSE_ENTER ) ;
BIND_CONSTANT ( NOTIFICATION_WM_MOUSE_EXIT ) ;
2020-06-29 20:47:18 -03:00
BIND_CONSTANT ( NOTIFICATION_WM_WINDOW_FOCUS_IN ) ;
BIND_CONSTANT ( NOTIFICATION_WM_WINDOW_FOCUS_OUT ) ;
2020-03-04 13:36:09 -03:00
BIND_CONSTANT ( NOTIFICATION_WM_CLOSE_REQUEST ) ;
2019-04-04 10:34:03 -03:00
BIND_CONSTANT ( NOTIFICATION_WM_GO_BACK_REQUEST ) ;
2020-03-06 14:00:16 -03:00
BIND_CONSTANT ( NOTIFICATION_WM_SIZE_CHANGED ) ;
2022-02-15 22:14:39 +01:00
BIND_CONSTANT ( NOTIFICATION_WM_DPI_CHANGE ) ;
BIND_CONSTANT ( NOTIFICATION_VP_MOUSE_ENTER ) ;
BIND_CONSTANT ( NOTIFICATION_VP_MOUSE_EXIT ) ;
2025-03-13 16:12:16 -04:00
BIND_CONSTANT ( NOTIFICATION_WM_POSITION_CHANGED ) ;
2019-04-04 10:34:03 -03: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 20:47:18 -03: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 14:22:16 +03:00
BIND_CONSTANT ( NOTIFICATION_TEXT_SERVER_CHANGED ) ;
2019-04-04 10:34:03 -03:00
2025-03-21 16:42:23 +02:00
BIND_CONSTANT ( NOTIFICATION_ACCESSIBILITY_UPDATE ) ;
BIND_CONSTANT ( NOTIFICATION_ACCESSIBILITY_INVALIDATE ) ;
2021-02-18 15:52:29 -03: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 17:45:01 +02:00
2023-04-10 18:45:53 +02:00
BIND_ENUM_CONSTANT ( PROCESS_THREAD_GROUP_INHERIT ) ;
BIND_ENUM_CONSTANT ( PROCESS_THREAD_GROUP_MAIN_THREAD ) ;
BIND_ENUM_CONSTANT ( PROCESS_THREAD_GROUP_SUB_THREAD ) ;
2023-06-15 17:06:22 +03:00
BIND_BITFIELD_FLAG ( FLAG_PROCESS_THREAD_MESSAGES ) ;
BIND_BITFIELD_FLAG ( FLAG_PROCESS_THREAD_MESSAGES_PHYSICS ) ;
BIND_BITFIELD_FLAG ( FLAG_PROCESS_THREAD_MESSAGES_ALL ) ;
2023-04-10 18:45:53 +02:00
2024-02-17 00:57:32 +01:00
BIND_ENUM_CONSTANT ( PHYSICS_INTERPOLATION_MODE_INHERIT ) ;
BIND_ENUM_CONSTANT ( PHYSICS_INTERPOLATION_MODE_ON ) ;
BIND_ENUM_CONSTANT ( PHYSICS_INTERPOLATION_MODE_OFF ) ;
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( DUPLICATE_SIGNALS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_GROUPS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_SCRIPTS ) ;
2022-11-16 00:13:39 +01:00
BIND_ENUM_CONSTANT ( DUPLICATE_USE_INSTANTIATION ) ;
2017-03-05 16:44:50 +01:00
2021-08-25 15:49:30 +02:00
BIND_ENUM_CONSTANT ( INTERNAL_MODE_DISABLED ) ;
BIND_ENUM_CONSTANT ( INTERNAL_MODE_FRONT ) ;
BIND_ENUM_CONSTANT ( INTERNAL_MODE_BACK ) ;
2024-01-23 18:29:45 -03:00
BIND_ENUM_CONSTANT ( AUTO_TRANSLATE_MODE_INHERIT ) ;
BIND_ENUM_CONSTANT ( AUTO_TRANSLATE_MODE_ALWAYS ) ;
BIND_ENUM_CONSTANT ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2018-01-20 21:57:59 +00:00
ADD_SIGNAL ( MethodInfo ( " ready " ) ) ;
2014-02-09 22:10:30 -03:00
ADD_SIGNAL ( MethodInfo ( " renamed " ) ) ;
2017-01-12 00:51:08 -03:00
ADD_SIGNAL ( MethodInfo ( " tree_entered " ) ) ;
2018-01-12 08:28:39 -03:00
ADD_SIGNAL ( MethodInfo ( " tree_exiting " ) ) ;
2017-01-12 00:51:08 -03:00
ADD_SIGNAL ( MethodInfo ( " tree_exited " ) ) ;
2022-02-02 11:22:11 +01:00
ADD_SIGNAL ( MethodInfo ( " child_entered_tree " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT , " Node " ) ) ) ;
2022-06-20 09:53:44 +02:00
ADD_SIGNAL ( MethodInfo ( " child_exiting_tree " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT , " Node " ) ) ) ;
2022-11-13 14:52:37 +08:00
2023-04-05 18:53:32 +02:00
ADD_SIGNAL ( MethodInfo ( " child_order_changed " ) ) ;
2022-11-13 14:52:37 +08:00
ADD_SIGNAL ( MethodInfo ( " replacing_by " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT , " Node " ) ) ) ;
2023-11-14 13:00:41 +08:00
ADD_SIGNAL ( MethodInfo ( " editor_description_changed " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_DEFAULT , " Node " ) ) ) ;
2024-11-26 00:04:25 +01:00
ADD_SIGNAL ( MethodInfo ( " editor_state_changed " ) ) ;
2014-02-09 22:10:30 -03:00
2021-06-17 19:10:18 -04:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING_NAME , " name " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " set_name " , " get_name " ) ;
2022-04-25 15:16:44 +02: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 16:30:55 +02: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 19:10:18 -04: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 15:52:29 -03:00
ADD_GROUP ( " Process " , " process_ " ) ;
2021-05-22 04:30:58 +02: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 22:07:02 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " process_priority " ) , " set_process_priority " , " get_process_priority " ) ;
2023-04-10 18:45:53 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " process_physics_priority " ) , " set_physics_process_priority " , " get_physics_process_priority " ) ;
2024-01-23 18:29:45 -03:00
2023-04-10 18:45:53 +02:00
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 16:44:50 +01:00
2024-02-17 00:57:32 +01:00
ADD_GROUP ( " Physics Interpolation " , " physics_interpolation_ " ) ;
2024-04-05 10:18:00 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " physics_interpolation_mode " , PROPERTY_HINT_ENUM , " Inherit,On,Off " ) , " set_physics_interpolation_mode " , " get_physics_interpolation_mode " ) ;
2024-02-17 00:57:32 +01:00
2024-01-23 18:29:45 -03:00
ADD_GROUP ( " Auto Translate " , " auto_translate_ " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " auto_translate_mode " , PROPERTY_HINT_ENUM , " Inherit,Always,Disabled " ) , " set_auto_translate_mode " , " get_auto_translate_mode " ) ;
2021-02-18 15:52:29 -03:00
ADD_GROUP ( " Editor Description " , " editor_ " ) ;
2021-06-18 06:49:30 -07:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " editor_description " , PROPERTY_HINT_MULTILINE_TEXT ) , " set_editor_description " , " get_editor_description " ) ;
2021-02-18 15:52:29 -03:00
2021-08-21 22:52:44 -03: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 ) ;
2025-03-21 16:42:23 +02:00
GDVIRTUAL_BIND ( _get_accessibility_configuration_warnings ) ;
2021-08-22 12:37:22 -03:00
GDVIRTUAL_BIND ( _input , " event " ) ;
2022-01-11 15:59:52 +02:00
GDVIRTUAL_BIND ( _shortcut_input , " event " ) ;
2021-08-22 12:37:22 -03:00
GDVIRTUAL_BIND ( _unhandled_input , " event " ) ;
GDVIRTUAL_BIND ( _unhandled_key_input , " event " ) ;
2025-03-21 16:42:23 +02:00
GDVIRTUAL_BIND ( _get_focused_accessibility_element ) ;
2014-02-09 22:10:30 -03:00
}
2016-10-07 20:25:29 +02:00
String Node : : _get_name_num_separator ( ) {
2023-01-12 11:41:13 +03:00
switch ( GLOBAL_GET ( " editor/naming/node_name_num_separator " ) . operator int ( ) ) {
2020-05-10 13:00:47 +02:00
case 0 :
return " " ;
case 1 :
return " " ;
case 2 :
return " _ " ;
case 3 :
return " - " ;
2016-10-07 20:25:29 +02:00
}
return " " ;
}
2014-02-09 22:10:30 -03:00
Node : : Node ( ) {
2019-04-17 22:46:21 +02:00
orphan_node_count + + ;
2024-02-17 00:57:32 +01:00
// Default member initializer for bitfield is a C++20 extension, so:
data . process_mode = PROCESS_MODE_INHERIT ;
data . physics_interpolation_mode = PHYSICS_INTERPOLATION_MODE_INHERIT ;
data . physics_process = false ;
data . process = false ;
data . physics_process_internal = false ;
data . process_internal = false ;
data . input = false ;
data . shortcut_input = false ;
data . unhandled_input = false ;
data . unhandled_key_input = false ;
2024-04-05 10:18:00 +02:00
data . physics_interpolated = true ;
2024-05-26 19:39:28 +02:00
data . physics_interpolation_reset_requested = false ;
data . physics_interpolated_client_side = false ;
data . use_identity_transform = false ;
2024-02-17 00:57:32 +01:00
data . use_placeholder = false ;
data . display_folded = false ;
data . editable_instance = false ;
data . ready_notified = false ; // This is a small hack, so if a node is added during _ready() to the tree, it correctly gets the _ready() notification.
data . ready_first = true ;
2025-06-08 17:32:08 +03:00
data . auto_translate_mode = AUTO_TRANSLATE_MODE_INHERIT ;
data . is_auto_translating = true ;
data . is_auto_translate_dirty = true ;
data . is_translation_domain_inherited = true ;
data . is_translation_domain_dirty = true ;
2014-02-09 22:10:30 -03:00
}
Node : : ~ Node ( ) {
data . grouped . clear ( ) ;
data . owned . clear ( ) ;
data . children . clear ( ) ;
2023-04-03 22:31:47 +02:00
data . children_cache . clear ( ) ;
2016-03-09 00:00:52 +01:00
2014-02-09 22:10:30 -03:00
ERR_FAIL_COND ( data . parent ) ;
2023-04-03 22:31:47 +02:00
ERR_FAIL_COND ( data . children_cache . size ( ) ) ;
2019-04-17 22:46:21 +02:00
orphan_node_count - - ;
2014-02-09 22:10:30 -03:00
}
2015-10-16 19:11:23 -03:00
////////////////////////////////
2023-05-12 13:53:15 +02: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 ) ;
2024-11-26 00:04:25 +01:00
_emit_editor_state_changed ( ) ;
2023-05-12 13:53:15 +02:00
}
void Node : : remove_meta ( const StringName & p_name ) {
ERR_THREAD_GUARD ;
Object : : remove_meta ( p_name ) ;
2024-11-26 00:04:25 +01:00
_emit_editor_state_changed ( ) ;
2023-05-12 13:53:15 +02:00
}
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 ) ;
2024-11-26 00:04:25 +01:00
Error retval = Object : : connect ( p_signal , p_callable , p_flags ) ;
# ifdef TOOLS_ENABLED
if ( p_flags & CONNECT_PERSIST ) {
_emit_editor_state_changed ( ) ;
}
# endif
return retval ;
2023-05-12 13:53:15 +02:00
}
void Node : : disconnect ( const StringName & p_signal , const Callable & p_callable ) {
ERR_THREAD_GUARD ;
2024-11-26 00:04:25 +01:00
# ifdef TOOLS_ENABLED
// Already under thread guard, don't check again.
int old_connection_count = Object : : get_persistent_signal_connection_count ( ) ;
# endif
2023-05-12 13:53:15 +02:00
Object : : disconnect ( p_signal , p_callable ) ;
2024-11-26 00:04:25 +01:00
# ifdef TOOLS_ENABLED
int new_connection_count = Object : : get_persistent_signal_connection_count ( ) ;
if ( old_connection_count ! = new_connection_count ) {
_emit_editor_state_changed ( ) ;
}
# endif
2023-05-12 13:53:15 +02:00
}
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 ) ;
}
2024-01-18 17:20:56 +01:00
bool Node : : has_connections ( const StringName & p_signal ) const {
ERR_THREAD_GUARD_V ( false ) ;
return Object : : has_connections ( p_signal ) ;
}
2023-05-12 13:53:15 +02:00
# endif