2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* node.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2021-01-01 19:13:46 +00:00
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 01:10:30 +00:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "node.h"
2017-08-27 19:07:15 +00:00
2017-09-06 12:21:19 +00:00
# include "core/core_string_names.h"
2018-09-11 16:13:45 +00:00
# include "core/io/resource_loader.h"
2020-11-07 22:33:38 +00:00
# include "core/object/message_queue.h"
# include "core/string/print_string.h"
2017-03-05 15:44:50 +00:00
# include "instance_placeholder.h"
2020-09-05 01:05:30 +00:00
# include "scene/animation/tween.h"
2020-02-07 01:52:05 +00:00
# include "scene/debugger/scene_debugger.h"
2014-02-10 01:10:30 +00:00
# include "scene/resources/packed_scene.h"
2017-03-05 15:44:50 +00:00
# include "scene/scene_string_names.h"
2014-04-10 03:18:27 +00:00
# include "viewport.h"
2014-02-10 01:10:30 +00:00
2018-12-18 01:53:54 +00:00
# ifdef TOOLS_ENABLED
# include "editor/editor_settings.h"
# endif
2020-02-21 22:26:13 +00:00
# include <stdint.h>
2021-02-18 18:52:29 +00:00
VARIANT_ENUM_CAST ( Node : : ProcessMode ) ;
2014-02-10 01:10:30 +00:00
2019-04-17 20:46:21 +00:00
int Node : : orphan_node_count = 0 ;
2014-02-10 01:10:30 +00:00
void Node : : _notification ( int p_notification ) {
2017-03-05 15:44:50 +00:00
switch ( p_notification ) {
2014-02-10 01:10:30 +00:00
case NOTIFICATION_PROCESS : {
if ( get_script_instance ( ) ) {
2017-03-05 15:44:50 +00:00
Variant time = get_process_delta_time ( ) ;
2020-07-24 17:13:58 +00:00
get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > _process , time ) ;
2014-02-10 01:10:30 +00:00
}
} break ;
2017-09-30 14:19:07 +00:00
case NOTIFICATION_PHYSICS_PROCESS : {
2014-02-10 01:10:30 +00:00
if ( get_script_instance ( ) ) {
2017-09-30 14:19:07 +00:00
Variant time = get_physics_process_delta_time ( ) ;
2020-07-24 17:13:58 +00:00
get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > _physics_process , time ) ;
2014-02-10 01:10:30 +00:00
}
} break ;
2014-11-06 00:20:42 +00:00
case NOTIFICATION_ENTER_TREE : {
2019-06-22 12:52:51 +00:00
ERR_FAIL_COND ( ! get_viewport ( ) ) ;
ERR_FAIL_COND ( ! get_tree ( ) ) ;
2014-02-10 01:10:30 +00:00
2021-02-18 18:52:29 +00:00
if ( data . process_mode = = PROCESS_MODE_INHERIT ) {
2020-05-14 14:41:43 +00:00
if ( data . parent ) {
2021-02-18 18:52:29 +00:00
data . process_owner = data . parent - > data . process_owner ;
2020-05-14 14:41:43 +00:00
} else {
2021-02-18 18:52:29 +00:00
data . process_owner = nullptr ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
} else {
2021-02-18 18:52:29 +00:00
data . process_owner = this ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 14:41:43 +00:00
if ( data . input ) {
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
if ( data . unhandled_input ) {
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
if ( data . unhandled_key_input ) {
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-04-10 03:18:27 +00:00
2014-11-06 00:20:42 +00:00
get_tree ( ) - > node_count + + ;
2019-04-17 20:46:21 +00:00
orphan_node_count - - ;
2014-02-10 01:10:30 +00:00
} break ;
2014-11-06 00:20:42 +00:00
case NOTIFICATION_EXIT_TREE : {
2019-06-22 12:52:51 +00:00
ERR_FAIL_COND ( ! get_viewport ( ) ) ;
ERR_FAIL_COND ( ! get_tree ( ) ) ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
get_tree ( ) - > node_count - - ;
2019-04-17 20:46:21 +00:00
orphan_node_count + + ;
2020-05-14 14:41:43 +00:00
if ( data . input ) {
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
if ( data . unhandled_input ) {
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
if ( data . unhandled_key_input ) {
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
2016-08-14 21:49:50 +00:00
2021-02-18 18:52:29 +00:00
data . process_owner = nullptr ;
2016-08-14 21:49:50 +00:00
if ( data . path_cache ) {
memdelete ( data . path_cache ) ;
2020-04-01 23:20:12 +00:00
data . path_cache = nullptr ;
2016-08-14 21:49:50 +00:00
}
2021-07-30 00:14:37 +00:00
if ( data . filename . length ( ) ) {
get_multiplayer ( ) - > scene_enter_exit_notify ( data . filename , this , false ) ;
}
2016-08-14 21:49:50 +00:00
} break ;
case NOTIFICATION_PATH_CHANGED : {
if ( data . path_cache ) {
memdelete ( data . path_cache ) ;
2020-04-01 23:20:12 +00:00
data . path_cache = nullptr ;
2016-08-14 21:49:50 +00:00
}
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_READY : {
if ( get_script_instance ( ) ) {
2017-01-10 21:02:19 +00:00
if ( get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _input ) ) {
set_process_input ( true ) ;
}
if ( get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _unhandled_input ) ) {
set_process_unhandled_input ( true ) ;
}
if ( get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _unhandled_key_input ) ) {
set_process_unhandled_key_input ( true ) ;
}
if ( get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _process ) ) {
set_process ( true ) ;
}
2017-09-30 14:19:07 +00:00
if ( get_script_instance ( ) - > has_method ( SceneStringNames : : get_singleton ( ) - > _physics_process ) ) {
set_physics_process ( true ) ;
2017-01-10 21:02:19 +00:00
}
2020-07-24 17:13:58 +00:00
get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > _ready ) ;
2014-02-10 01:10:30 +00:00
}
2021-07-30 00:14:37 +00:00
if ( data . filename . length ( ) ) {
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
get_multiplayer ( ) - > scene_enter_exit_notify ( data . filename , this , true ) ;
}
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_POSTINITIALIZE : {
2017-03-05 15:44:50 +00:00
data . in_constructor = false ;
2014-02-10 01:10:30 +00:00
} break ;
case NOTIFICATION_PREDELETE : {
2020-04-01 23:20:12 +00:00
set_owner ( nullptr ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( data . owned . size ( ) ) {
2020-04-01 23:20:12 +00:00
data . owned . front ( ) - > get ( ) - > set_owner ( nullptr ) ;
2014-02-10 01:10:30 +00:00
}
if ( data . parent ) {
data . parent - > remove_child ( this ) ;
}
// kill children as cleanly as possible
2017-03-05 15:44:50 +00:00
while ( data . children . size ( ) ) {
2018-11-18 14:47:19 +00:00
Node * child = data . children [ data . children . size ( ) - 1 ] ; //begin from the end because its faster and more consistent with creation
2014-02-10 01:10:30 +00:00
remove_child ( child ) ;
2017-03-05 15:44:50 +00:00
memdelete ( child ) ;
2014-02-10 01:10:30 +00:00
}
} break ;
}
}
void Node : : _propagate_ready ( ) {
2017-03-05 15:44:50 +00:00
data . ready_notified = true ;
2014-02-10 01:10:30 +00:00
data . blocked + + ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
data . children [ i ] - > _propagate_ready ( ) ;
}
data . blocked - - ;
2018-05-15 20:12:35 +00:00
notification ( NOTIFICATION_POST_ENTER_TREE ) ;
2017-01-10 21:02:19 +00:00
if ( data . ready_first ) {
2017-03-05 15:44:50 +00:00
data . ready_first = false ;
2017-12-14 11:59:46 +00:00
notification ( NOTIFICATION_READY ) ;
2018-01-20 21:57:59 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > ready ) ;
2017-01-10 21:02:19 +00:00
}
2014-02-10 01:10:30 +00:00
}
2014-11-06 00:20:42 +00:00
void Node : : _propagate_enter_tree ( ) {
2018-01-18 20:37:17 +00:00
// this needs to happen to all children before any enter_tree
2014-02-10 01:10:30 +00:00
if ( data . parent ) {
2017-03-05 15:44:50 +00:00
data . tree = data . parent - > data . tree ;
data . depth = data . parent - > data . depth + 1 ;
2014-02-10 01:10:30 +00:00
} else {
2017-03-05 15:44:50 +00:00
data . depth = 1 ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-08-24 20:58:51 +00:00
data . viewport = Object : : cast_to < Viewport > ( this ) ;
2020-05-14 14:41:43 +00:00
if ( ! data . viewport & & data . parent ) {
2014-04-10 03:18:27 +00:00
data . viewport = data . parent - > data . viewport ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . inside_tree = true ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( Map < StringName , GroupData > : : Element * E = data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
E - > get ( ) . group = data . tree - > add_to_group ( E - > key ( ) , this ) ;
2014-02-10 01:10:30 +00:00
}
2014-11-06 00:20:42 +00:00
notification ( NOTIFICATION_ENTER_TREE ) ;
2014-02-10 01:10:30 +00:00
if ( get_script_instance ( ) ) {
2020-07-24 17:13:58 +00:00
get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > _enter_tree ) ;
2014-02-10 01:10:30 +00:00
}
2017-01-12 03:51:08 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > tree_entered ) ;
2014-02-10 01:10:30 +00:00
2017-10-19 00:30:27 +00:00
data . tree - > node_added ( this ) ;
2014-02-10 01:10:30 +00:00
data . blocked + + ;
//block while adding children
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2020-05-14 14:41:43 +00:00
if ( ! data . children [ i ] - > is_inside_tree ( ) ) { // could have been added in enter_tree
2014-11-06 00:20:42 +00:00
data . children [ i ] - > _propagate_enter_tree ( ) ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
}
2014-02-10 01:10:30 +00:00
data . blocked - - ;
2015-08-02 15:29:37 +00:00
# ifdef DEBUG_ENABLED
2020-02-07 01:52:05 +00:00
SceneDebugger : : add_to_cache ( data . filename , this ) ;
2015-08-02 15:29:37 +00:00
# endif
2014-02-10 01:10:30 +00:00
// enter groups
}
2018-09-07 18:31:19 +00:00
void Node : : _propagate_after_exit_tree ( ) {
data . blocked + + ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > _propagate_after_exit_tree ( ) ;
}
data . blocked - - ;
emit_signal ( SceneStringNames : : get_singleton ( ) - > tree_exited ) ;
}
2014-11-06 00:20:42 +00:00
void Node : : _propagate_exit_tree ( ) {
2018-08-21 19:28:06 +00:00
//block while removing children
2014-02-10 01:10:30 +00:00
2015-08-02 15:29:37 +00:00
# ifdef DEBUG_ENABLED
2020-02-07 01:52:05 +00:00
SceneDebugger : : remove_from_cache ( data . filename , this ) ;
2015-08-02 15:29:37 +00:00
# endif
2014-02-10 01:10:30 +00:00
data . blocked + + ;
2017-03-05 15:44:50 +00:00
for ( int i = data . children . size ( ) - 1 ; i > = 0 ; i - - ) {
2014-11-06 00:20:42 +00:00
data . children [ i ] - > _propagate_exit_tree ( ) ;
2014-02-10 01:10:30 +00:00
}
data . blocked - - ;
if ( get_script_instance ( ) ) {
2020-07-24 17:13:58 +00:00
get_script_instance ( ) - > call ( SceneStringNames : : get_singleton ( ) - > _exit_tree ) ;
2014-02-10 01:10:30 +00:00
}
2018-01-12 11:28:39 +00:00
emit_signal ( SceneStringNames : : get_singleton ( ) - > tree_exiting ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
notification ( NOTIFICATION_EXIT_TREE , true ) ;
2020-05-14 14:41:43 +00:00
if ( data . tree ) {
2014-11-06 00:20:42 +00:00
data . tree - > node_removed ( this ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
// exit groups
2017-03-05 15:44:50 +00:00
for ( Map < StringName , GroupData > : : Element * E = data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
data . tree - > remove_from_group ( E - > key ( ) , this ) ;
2020-04-01 23:20:12 +00:00
E - > get ( ) . group = nullptr ;
2014-02-10 01:10:30 +00:00
}
2020-04-01 23:20:12 +00:00
data . viewport = nullptr ;
2014-04-10 03:18:27 +00:00
2020-05-14 14:41:43 +00:00
if ( data . tree ) {
2014-11-06 00:20:42 +00:00
data . tree - > tree_changed ( ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . inside_tree = false ;
data . ready_notified = false ;
2020-04-01 23:20:12 +00:00
data . tree = nullptr ;
2017-03-05 15:44:50 +00:00
data . depth = - 1 ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : move_child ( Node * p_child , int p_pos ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL_NULL ( p_child ) ;
2021-05-23 14:42:47 +00:00
ERR_FAIL_INDEX_MSG ( p_pos , data . children . size ( ) + 1 , vformat ( " Invalid new child position: %d. " , p_pos ) ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_MSG ( p_child - > data . parent ! = this , " Child is not a child of this node. " ) ;
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, move_child() failed. Consider using call_deferred( \" move_child \" ) instead (or \" popup \" if this is from a popup). " ) ;
2016-06-14 01:46:18 +00:00
2017-07-25 03:11:00 +00:00
// Specifying one place beyond the end
// means the same as moving to the last position
2020-05-14 14:41:43 +00:00
if ( p_pos = = data . children . size ( ) ) {
2017-07-25 03:11:00 +00:00
p_pos - - ;
2020-05-14 14:41:43 +00:00
}
2017-07-25 03:11:00 +00:00
2020-05-14 14:41:43 +00:00
if ( p_child - > data . pos = = p_pos ) {
2016-10-03 19:33:42 +00:00
return ; //do nothing
2020-05-14 14:41:43 +00:00
}
2016-10-03 19:33:42 +00:00
2017-03-05 15:44:50 +00:00
int motion_from = MIN ( p_pos , p_child - > data . pos ) ;
int motion_to = MAX ( p_pos , p_child - > data . pos ) ;
2016-10-03 19:33:42 +00:00
2017-03-05 15:44:50 +00:00
data . children . remove ( p_child - > data . pos ) ;
data . children . insert ( p_pos , p_child ) ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree ) {
data . tree - > tree_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
data . blocked + + ;
//new pos first
2017-03-05 15:44:50 +00:00
for ( int i = motion_from ; i < = motion_to ; i + + ) {
data . children [ i ] - > data . pos = i ;
2014-02-10 01:10:30 +00:00
}
// notification second
2014-12-03 05:29:28 +00:00
move_child_notify ( p_child ) ;
2017-03-05 15:44:50 +00:00
for ( int i = motion_from ; i < = motion_to ; i + + ) {
data . children [ i ] - > notification ( NOTIFICATION_MOVED_IN_PARENT ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
for ( const Map < StringName , GroupData > : : Element * E = p_child - > data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
2020-05-14 14:41:43 +00:00
if ( E - > get ( ) . group ) {
2017-12-23 11:16:27 +00:00
E - > get ( ) . group - > changed = true ;
2020-05-14 14:41:43 +00:00
}
2016-06-08 01:08:12 +00:00
}
2014-02-10 01:10:30 +00:00
data . blocked - - ;
}
void Node : : raise ( ) {
2020-05-14 14:41:43 +00:00
if ( ! data . parent ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . parent - > move_child ( this , data . parent - > data . children . size ( ) - 1 ) ;
2014-02-10 01:10:30 +00:00
}
void Node : : add_child_notify ( Node * p_child ) {
2016-03-08 23:00:52 +00:00
// to be used when not wanted
2014-02-10 01:10:30 +00:00
}
void Node : : remove_child_notify ( Node * p_child ) {
2016-03-08 23:00:52 +00:00
// to be used when not wanted
2014-02-10 01:10:30 +00:00
}
2014-12-03 04:17:23 +00:00
void Node : : move_child_notify ( Node * p_child ) {
2016-03-08 23:00:52 +00:00
// to be used when not wanted
2014-12-03 04:17:23 +00:00
}
2017-09-30 14:19:07 +00:00
void Node : : set_physics_process ( bool p_process ) {
2020-05-14 14:41:43 +00:00
if ( data . physics_process = = p_process ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-09-30 14:19:07 +00:00
data . physics_process = p_process ;
2016-03-08 23:00:52 +00:00
2020-05-14 14:41:43 +00:00
if ( data . physics_process ) {
2017-09-30 14:19:07 +00:00
add_to_group ( " physics_process " , false ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-09-30 14:19:07 +00:00
remove_from_group ( " physics_process " ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-09-30 14:19:07 +00:00
bool Node : : is_physics_processing ( ) const {
return data . physics_process ;
2017-01-10 21:02:19 +00:00
}
2017-09-30 14:19:07 +00:00
void Node : : set_physics_process_internal ( bool p_process_internal ) {
2020-05-14 14:41:43 +00:00
if ( data . physics_process_internal = = p_process_internal ) {
2017-01-10 21:02:19 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-01-10 21:02:19 +00:00
2017-09-30 14:19:07 +00:00
data . physics_process_internal = p_process_internal ;
2017-01-10 21:02:19 +00:00
2020-05-14 14:41:43 +00:00
if ( data . physics_process_internal ) {
2017-09-30 14:19:07 +00:00
add_to_group ( " physics_process_internal " , false ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-09-30 14:19:07 +00:00
remove_from_group ( " physics_process_internal " ) ;
2020-05-14 14:41:43 +00:00
}
2017-01-10 21:02:19 +00:00
}
2017-09-30 14:19:07 +00:00
bool Node : : is_physics_processing_internal ( ) const {
return data . physics_process_internal ;
2017-01-10 21:02:19 +00:00
}
2021-02-18 18:52:29 +00:00
void Node : : set_process_mode ( ProcessMode p_mode ) {
if ( data . process_mode = = p_mode ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2021-02-18 18:52:29 +00:00
data . process_mode = p_mode ;
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2021-02-18 18:52:29 +00:00
bool prev_can_process = can_process ( ) ;
2021-06-18 01:09:40 +00:00
bool prev_enabled = _is_enabled ( ) ;
2021-02-18 18:52:29 +00:00
data . process_mode = p_mode ;
2014-02-10 01:10:30 +00:00
2021-02-18 18:52:29 +00:00
if ( data . process_mode = = PROCESS_MODE_INHERIT ) {
2020-05-14 14:41:43 +00:00
if ( data . parent ) {
2021-02-18 18:52:29 +00:00
data . process_owner = data . parent - > data . owner ;
} else {
data . process_owner = nullptr ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
} else {
2021-02-18 18:52:29 +00:00
data . process_owner = this ;
}
bool next_can_process = can_process ( ) ;
2021-06-18 01:09:40 +00:00
bool next_enabled = _is_enabled ( ) ;
2021-02-18 18:52:29 +00:00
int pause_notification = 0 ;
if ( prev_can_process & & ! next_can_process ) {
pause_notification = NOTIFICATION_PAUSED ;
} else if ( ! prev_can_process & & next_can_process ) {
pause_notification = NOTIFICATION_UNPAUSED ;
}
2021-06-18 01:09:40 +00:00
int enabled_notification = 0 ;
if ( prev_enabled & & ! next_enabled ) {
enabled_notification = NOTIFICATION_DISABLED ;
} else if ( ! prev_enabled & & next_enabled ) {
enabled_notification = NOTIFICATION_ENABLED ;
}
_propagate_process_owner ( data . process_owner , pause_notification , enabled_notification ) ;
2021-02-18 18:52:29 +00:00
# ifdef TOOLS_ENABLED
// This is required for the editor to update the visibility of disabled nodes
2021-03-12 13:35:16 +00:00
// It's very expensive during runtime to change, so editor-only
2021-02-18 18:52:29 +00:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2021-07-17 21:22:52 +00:00
get_tree ( ) - > emit_signal ( SNAME ( " tree_process_mode_changed " ) ) ;
2014-02-10 01:10:30 +00:00
}
2021-02-18 18:52:29 +00:00
# endif
}
void Node : : _propagate_pause_notification ( bool p_enable ) {
bool prev_can_process = _can_process ( ! p_enable ) ;
bool next_can_process = _can_process ( p_enable ) ;
2014-02-10 01:10:30 +00:00
2021-02-18 18:52:29 +00:00
if ( prev_can_process & & ! next_can_process ) {
notification ( NOTIFICATION_PAUSED ) ;
} else if ( ! prev_can_process & & next_can_process ) {
notification ( NOTIFICATION_UNPAUSED ) ;
}
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > _propagate_pause_notification ( p_enable ) ;
}
2014-02-10 01:10:30 +00:00
}
2021-02-18 18:52:29 +00:00
Node : : ProcessMode Node : : get_process_mode ( ) const {
return data . process_mode ;
2014-02-10 01:10:30 +00:00
}
2021-06-18 01:09:40 +00:00
void Node : : _propagate_process_owner ( Node * p_owner , int p_pause_notification , int p_enabled_notification ) {
2021-02-18 18:52:29 +00:00
data . process_owner = p_owner ;
2021-06-18 01:09:40 +00:00
if ( p_pause_notification ! = 0 ) {
notification ( p_pause_notification ) ;
}
if ( p_enabled_notification ! = 0 ) {
notification ( p_enabled_notification ) ;
2020-05-14 14:41:43 +00:00
}
2021-02-18 18:52:29 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2021-02-18 18:52:29 +00:00
Node * c = data . children [ i ] ;
if ( c - > data . process_mode = = PROCESS_MODE_INHERIT ) {
2021-06-18 01:09:40 +00:00
c - > _propagate_process_owner ( p_owner , p_pause_notification , p_enabled_notification ) ;
2021-02-18 18:52:29 +00:00
}
2014-02-10 01:10:30 +00:00
}
}
2017-07-03 13:44:45 +00:00
void Node : : set_network_master ( int p_peer_id , bool p_recursive ) {
data . network_master = p_peer_id ;
2016-08-14 21:49:50 +00:00
2017-07-03 13:44:45 +00:00
if ( p_recursive ) {
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > set_network_master ( p_peer_id , true ) ;
}
2016-08-14 21:49:50 +00:00
}
}
2017-07-03 13:44:45 +00:00
int Node : : get_network_master ( ) const {
return data . network_master ;
2016-08-14 21:49:50 +00:00
}
bool Node : : is_network_master ( ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , false ) ;
2016-08-14 21:49:50 +00:00
2018-05-08 08:51:04 +00:00
return get_multiplayer ( ) - > get_network_unique_id ( ) = = data . network_master ;
2016-08-14 21:49:50 +00:00
}
2016-08-19 19:48:08 +00:00
/***** RPC CONFIG ********/
2016-08-14 21:49:50 +00:00
2021-07-12 14:11:05 +00:00
uint16_t Node : : rpc_config ( const StringName & p_method , MultiplayerAPI : : RPCMode p_rpc_mode , MultiplayerPeer : : TransferMode p_transfer_mode , int p_channel ) {
2021-05-26 12:07:57 +00:00
for ( int i = 0 ; i < data . rpc_methods . size ( ) ; i + + ) {
if ( data . rpc_methods [ i ] . name = = p_method ) {
MultiplayerAPI : : RPCConfig & nd = data . rpc_methods . write [ i ] ;
nd . rpc_mode = p_rpc_mode ;
nd . transfer_mode = p_transfer_mode ;
nd . channel = p_channel ;
return i | ( 1 < < 15 ) ;
}
2020-02-12 10:51:50 +00:00
}
2021-05-26 12:07:57 +00:00
// New method
MultiplayerAPI : : RPCConfig nd ;
nd . name = p_method ;
nd . rpc_mode = p_rpc_mode ;
nd . transfer_mode = p_transfer_mode ;
nd . channel = p_channel ;
data . rpc_methods . push_back ( nd ) ;
return ( ( uint16_t ) data . rpc_methods . size ( ) - 1 ) | ( 1 < < 15 ) ;
2016-08-14 21:49:50 +00:00
}
2016-08-19 19:48:08 +00:00
/***** RPC FUNCTIONS ********/
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
void Node : : rpc ( const StringName & p_method , VARIANT_ARG_DECLARE ) {
2016-08-19 19:48:08 +00:00
VARIANT_ARGPTRS ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
2020-05-14 14:41:43 +00:00
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL ) {
2016-08-19 19:48:08 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2016-08-19 19:48:08 +00:00
argc + + ;
2016-08-14 21:49:50 +00:00
}
2016-08-19 19:48:08 +00:00
2021-05-26 12:07:57 +00:00
rpcp ( 0 , p_method , argptr , argc ) ;
2016-08-14 21:49:50 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : rpc_id ( int p_peer_id , const StringName & p_method , VARIANT_ARG_DECLARE ) {
2016-08-14 21:49:50 +00:00
VARIANT_ARGPTRS ;
2017-03-05 15:44:50 +00:00
int argc = 0 ;
for ( int i = 0 ; i < VARIANT_ARG_MAX ; i + + ) {
2020-05-14 14:41:43 +00:00
if ( argptr [ i ] - > get_type ( ) = = Variant : : NIL ) {
2016-08-14 21:49:50 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2016-08-14 21:49:50 +00:00
argc + + ;
}
2021-05-26 12:07:57 +00:00
rpcp ( p_peer_id , p_method , argptr , argc ) ;
2016-08-14 21:49:50 +00:00
}
2020-02-19 19:27:19 +00:00
Variant Node : : _rpc_bind ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2017-03-05 15:44:50 +00:00
if ( p_argcount < 1 ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2017-03-05 15:44:50 +00:00
r_error . argument = 1 ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2016-08-14 21:49:50 +00:00
2021-02-11 10:52:52 +00:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : STRING_NAME ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2017-03-05 15:44:50 +00:00
r_error . argument = 0 ;
2021-05-03 13:45:36 +00:00
r_error . expected = Variant : : STRING_NAME ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2016-08-14 21:49:50 +00:00
2016-08-19 19:48:08 +00:00
StringName method = * p_args [ 0 ] ;
2016-08-14 21:49:50 +00:00
2021-05-26 12:07:57 +00:00
rpcp ( 0 , method , & p_args [ 1 ] , p_argcount - 1 ) ;
2016-08-14 21:49:50 +00:00
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_OK ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
2016-08-14 21:49:50 +00:00
}
2020-02-19 19:27:19 +00:00
Variant Node : : _rpc_id_bind ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2017-03-05 15:44:50 +00:00
if ( p_argcount < 2 ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2017-03-05 15:44:50 +00:00
r_error . argument = 2 ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
if ( p_args [ 0 ] - > get_type ( ) ! = Variant : : INT ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2017-03-05 15:44:50 +00:00
r_error . argument = 0 ;
r_error . expected = Variant : : INT ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2021-02-11 10:52:52 +00:00
if ( p_args [ 1 ] - > get_type ( ) ! = Variant : : STRING_NAME ) {
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2017-03-05 15:44:50 +00:00
r_error . argument = 1 ;
2021-05-03 13:45:36 +00:00
r_error . expected = Variant : : STRING_NAME ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
int peer_id = * p_args [ 0 ] ;
StringName method = * p_args [ 1 ] ;
2021-05-26 12:07:57 +00:00
rpcp ( peer_id , method , & p_args [ 2 ] , p_argcount - 2 ) ;
2016-08-19 19:48:08 +00:00
2020-02-19 19:27:19 +00:00
r_error . error = Callable : : CallError : : CALL_OK ;
2016-08-19 19:48:08 +00:00
return Variant ( ) ;
}
2021-05-26 12:07:57 +00:00
void Node : : rpcp ( int p_peer_id , const StringName & p_method , const Variant * * p_arg , int p_argcount ) {
2016-08-19 19:48:08 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2021-05-26 12:07:57 +00:00
get_multiplayer ( ) - > rpcp ( this , p_peer_id , true , p_method , p_arg , p_argcount ) ;
2016-08-19 19:48:08 +00:00
}
2018-05-08 08:51:04 +00:00
Ref < MultiplayerAPI > Node : : get_multiplayer ( ) const {
2020-05-14 14:41:43 +00:00
if ( multiplayer . is_valid ( ) ) {
2018-05-08 08:51:04 +00:00
return multiplayer ;
2020-05-14 14:41:43 +00:00
}
if ( ! is_inside_tree ( ) ) {
2018-03-03 17:30:11 +00:00
return Ref < MultiplayerAPI > ( ) ;
2020-05-14 14:41:43 +00:00
}
2018-05-08 08:51:04 +00:00
return get_tree ( ) - > get_multiplayer ( ) ;
2018-03-03 17:30:11 +00:00
}
2018-05-08 08:51:04 +00:00
Ref < MultiplayerAPI > Node : : get_custom_multiplayer ( ) const {
return multiplayer ;
2018-03-03 17:30:11 +00:00
}
2018-05-08 08:51:04 +00:00
void Node : : set_custom_multiplayer ( Ref < MultiplayerAPI > p_multiplayer ) {
multiplayer = p_multiplayer ;
2018-03-03 17:30:11 +00:00
}
2021-05-26 12:07:57 +00:00
Vector < MultiplayerAPI : : RPCConfig > Node : : get_node_rpc_methods ( ) const {
return data . rpc_methods ;
2018-03-03 17:30:11 +00:00
}
2021-05-26 12:07:57 +00:00
//////////// end of rpc
2016-08-19 19:48:08 +00:00
2018-07-30 00:20:41 +00:00
bool Node : : can_process_notification ( int p_what ) const {
switch ( p_what ) {
2020-05-10 11:00:47 +00:00
case NOTIFICATION_PHYSICS_PROCESS :
return data . physics_process ;
case NOTIFICATION_PROCESS :
2020-12-22 09:50:29 +00:00
return data . process ;
2020-05-10 11:00:47 +00:00
case NOTIFICATION_INTERNAL_PROCESS :
2020-12-22 09:50:29 +00:00
return data . process_internal ;
2020-05-10 11:00:47 +00:00
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS :
return data . physics_process_internal ;
2018-07-30 00:20:41 +00:00
}
return true ;
}
2014-02-10 01:10:30 +00:00
bool Node : : can_process ( ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , false ) ;
2021-02-18 18:52:29 +00:00
return _can_process ( get_tree ( ) - > is_paused ( ) ) ;
}
2014-02-10 01:10:30 +00:00
2021-02-18 18:52:29 +00:00
bool Node : : _can_process ( bool p_paused ) const {
ProcessMode process_mode ;
2014-02-10 01:10:30 +00:00
2021-02-18 18:52:29 +00:00
if ( data . process_mode = = PROCESS_MODE_INHERIT ) {
if ( ! data . process_owner ) {
process_mode = PROCESS_MODE_PAUSABLE ;
} else {
process_mode = data . process_owner - > data . process_mode ;
2014-02-10 01:10:30 +00:00
}
2021-02-18 18:52:29 +00:00
} else {
process_mode = data . process_mode ;
2014-02-10 01:10:30 +00:00
}
2021-02-18 18:52:29 +00:00
if ( process_mode = = PROCESS_MODE_DISABLED ) {
return false ;
} else if ( process_mode = = PROCESS_MODE_ALWAYS ) {
return true ;
}
if ( p_paused ) {
return process_mode = = PROCESS_MODE_WHEN_PAUSED ;
} else {
return process_mode = = PROCESS_MODE_PAUSABLE ;
}
2014-02-10 01:10:30 +00:00
}
2021-06-18 01:09:40 +00:00
bool Node : : _is_enabled ( ) const {
ProcessMode process_mode ;
if ( data . process_mode = = PROCESS_MODE_INHERIT ) {
if ( ! data . process_owner ) {
process_mode = PROCESS_MODE_PAUSABLE ;
} else {
process_mode = data . process_owner - > data . process_mode ;
}
} else {
process_mode = data . process_mode ;
}
return ( process_mode ! = PROCESS_MODE_DISABLED ) ;
}
bool Node : : is_enabled ( ) const {
ERR_FAIL_COND_V ( ! is_inside_tree ( ) , false ) ;
return _is_enabled ( ) ;
}
2021-02-02 02:16:37 +00:00
double Node : : get_physics_process_delta_time ( ) const {
2020-05-14 14:41:43 +00:00
if ( data . tree ) {
2017-09-30 14:19:07 +00:00
return data . tree - > get_physics_process_time ( ) ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
return 0 ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2021-02-02 02:16:37 +00:00
double Node : : get_process_delta_time ( ) const {
2020-05-14 14:41:43 +00:00
if ( data . tree ) {
2020-12-22 09:50:29 +00:00
return data . tree - > get_process_time ( ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-01-10 21:02:19 +00:00
return 0 ;
2020-05-14 14:41:43 +00:00
}
2017-01-10 21:02:19 +00:00
}
2020-12-22 09:50:29 +00:00
void Node : : set_process ( bool p_process ) {
if ( data . process = = p_process ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-12-22 09:50:29 +00:00
data . process = p_process ;
2014-02-10 01:10:30 +00:00
2020-12-22 09:50:29 +00:00
if ( data . process ) {
add_to_group ( " process " , false ) ;
2020-05-14 14:41:43 +00:00
} else {
2020-12-22 09:50:29 +00:00
remove_from_group ( " process " ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-01-10 21:02:19 +00:00
bool Node : : is_processing ( ) const {
2020-12-22 09:50:29 +00:00
return data . process ;
2014-02-10 01:10:30 +00:00
}
2020-12-22 09:50:29 +00:00
void Node : : set_process_internal ( bool p_process_internal ) {
if ( data . process_internal = = p_process_internal ) {
2017-01-10 21:02:19 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-01-10 21:02:19 +00:00
2020-12-22 09:50:29 +00:00
data . process_internal = p_process_internal ;
2017-01-10 21:02:19 +00:00
2020-12-22 09:50:29 +00:00
if ( data . process_internal ) {
add_to_group ( " process_internal " , false ) ;
2020-05-14 14:41:43 +00:00
} else {
2020-12-22 09:50:29 +00:00
remove_from_group ( " process_internal " ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-01-10 21:02:19 +00:00
bool Node : : is_processing_internal ( ) const {
2020-12-22 09:50:29 +00:00
return data . process_internal ;
2014-02-10 01:10:30 +00:00
}
2018-07-02 05:30:40 +00:00
void Node : : set_process_priority ( int p_priority ) {
data . process_priority = p_priority ;
2019-11-21 16:26:28 +00:00
// Make sure we are in SceneTree.
2020-04-01 23:20:12 +00:00
if ( data . tree = = nullptr ) {
2019-11-21 16:26:28 +00:00
return ;
}
2019-06-22 12:52:51 +00:00
2019-11-21 16:26:28 +00:00
if ( is_processing ( ) ) {
2020-12-22 09:50:29 +00:00
data . tree - > make_group_changed ( " process " ) ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
2019-11-21 16:26:28 +00:00
if ( is_processing_internal ( ) ) {
2020-12-22 09:50:29 +00:00
data . tree - > make_group_changed ( " process_internal " ) ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
2019-11-21 16:26:28 +00:00
if ( is_physics_processing ( ) ) {
2018-07-02 05:30:40 +00:00
data . tree - > make_group_changed ( " physics_process " ) ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
2019-11-21 16:26:28 +00:00
if ( is_physics_processing_internal ( ) ) {
2018-07-02 05:30:40 +00:00
data . tree - > make_group_changed ( " physics_process_internal " ) ;
2019-11-21 16:26:28 +00:00
}
2018-07-02 05:30:40 +00:00
}
2019-11-16 21:07:02 +00:00
int Node : : get_process_priority ( ) const {
return data . process_priority ;
}
2014-02-10 01:10:30 +00:00
void Node : : set_process_input ( bool p_enable ) {
2020-05-14 14:41:43 +00:00
if ( p_enable = = data . input ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-04-10 03:18:27 +00:00
2017-03-05 15:44:50 +00:00
data . input = p_enable ;
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2014-04-10 03:18:27 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-04-10 03:18:27 +00:00
2020-05-14 14:41:43 +00:00
if ( p_enable ) {
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
bool Node : : is_processing_input ( ) const {
return data . input ;
}
void Node : : set_process_unhandled_input ( bool p_enable ) {
2020-05-14 14:41:43 +00:00
if ( p_enable = = data . unhandled_input ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
data . unhandled_input = p_enable ;
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2014-04-10 03:18:27 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( p_enable ) {
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_unhandled_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
bool Node : : is_processing_unhandled_input ( ) const {
return data . unhandled_input ;
}
2014-04-10 03:18:27 +00:00
void Node : : set_process_unhandled_key_input ( bool p_enable ) {
2020-05-14 14:41:43 +00:00
if ( p_enable = = data . unhandled_key_input ) {
2014-04-10 03:18:27 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
data . unhandled_key_input = p_enable ;
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2014-04-10 03:18:27 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-04-10 03:18:27 +00:00
2020-05-14 14:41:43 +00:00
if ( p_enable ) {
2017-08-07 10:17:31 +00:00
add_to_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-08-07 10:17:31 +00:00
remove_from_group ( " _vp_unhandled_key_input " + itos ( get_viewport ( ) - > get_instance_id ( ) ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-04-10 03:18:27 +00:00
}
bool Node : : is_processing_unhandled_key_input ( ) const {
return data . unhandled_key_input ;
}
2014-02-10 01:10:30 +00:00
StringName Node : : get_name ( ) const {
return data . name ;
}
2017-03-05 15:44:50 +00:00
void Node : : _set_name_nocheck ( const StringName & p_name ) {
data . name = p_name ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : set_name ( const String & p_name ) {
2021-01-28 20:48:12 +00:00
String name = p_name . validate_node_name ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( name = = " " ) ;
data . name = name ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( data . parent ) {
data . parent - > _validate_child_name ( this ) ;
}
2016-08-14 21:49:50 +00:00
propagate_notification ( NOTIFICATION_PATH_CHANGED ) ;
2014-11-06 00:20:42 +00:00
if ( is_inside_tree ( ) ) {
2021-07-17 21:22:52 +00:00
emit_signal ( SNAME ( " renamed " ) ) ;
2019-05-24 13:27:22 +00:00
get_tree ( ) - > node_renamed ( this ) ;
2014-11-06 00:20:42 +00:00
get_tree ( ) - > tree_changed ( ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
static bool node_hrcr = false ;
2014-02-22 23:28:19 +00:00
static SafeRefCount node_hrcr_count ;
void Node : : init_node_hrcr ( ) {
node_hrcr_count . init ( 1 ) ;
}
void Node : : set_human_readable_collision_renaming ( bool p_enabled ) {
2017-03-05 15:44:50 +00:00
node_hrcr = p_enabled ;
2014-02-22 23:28:19 +00:00
}
2016-10-07 18:25:29 +00:00
# ifdef TOOLS_ENABLED
2017-03-05 15:44:50 +00:00
String Node : : validate_child_name ( Node * p_child ) {
2019-01-10 21:52:47 +00:00
StringName name = p_child - > data . name ;
_generate_serial_child_name ( p_child , name ) ;
return name ;
2015-08-02 15:29:37 +00:00
}
2016-10-07 18:25:29 +00:00
# endif
2015-08-02 15:29:37 +00:00
2015-12-08 14:21:12 +00:00
void Node : : _validate_child_name ( Node * p_child , bool p_force_human_readable ) {
2014-02-10 01:10:30 +00:00
/* Make sure the name is unique */
2015-12-08 14:21:12 +00:00
if ( node_hrcr | | p_force_human_readable ) {
2014-02-22 23:28:19 +00:00
//this approach to autoset node names is human readable but very slow
//it's turned on while running in the editor
2019-01-10 21:52:47 +00:00
StringName name = p_child - > data . name ;
_generate_serial_child_name ( p_child , name ) ;
p_child - > data . name = name ;
2014-02-22 23:28:19 +00:00
} else {
//this approach to autoset node names is fast but not as readable
//it's the default and reserves the '@' character for unique names.
2017-03-05 15:44:50 +00:00
bool unique = true ;
2014-02-22 23:28:19 +00:00
2020-07-26 13:29:50 +00:00
if ( p_child - > data . name = = StringName ( ) ) {
2014-02-22 23:28:19 +00:00
//new unique name must be assigned
2017-03-05 15:44:50 +00:00
unique = false ;
2014-02-22 23:28:19 +00:00
} else {
//check if exists
2018-01-18 20:37:17 +00:00
Node * * children = data . children . ptrw ( ) ;
2014-02-22 23:28:19 +00:00
int cc = data . children . size ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < cc ; i + + ) {
2020-05-14 14:41:43 +00:00
if ( children [ i ] = = p_child ) {
2014-02-26 13:08:17 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2018-01-18 20:37:17 +00:00
if ( children [ i ] - > data . name = = p_child - > data . name ) {
2017-03-05 15:44:50 +00:00
unique = false ;
2014-02-22 23:28:19 +00:00
break ;
}
}
}
if ( ! unique ) {
2019-08-07 10:54:30 +00:00
ERR_FAIL_COND ( ! node_hrcr_count . ref ( ) ) ;
2017-03-05 15:44:50 +00:00
String name = " @ " + String ( p_child - > get_name ( ) ) + " @ " + itos ( node_hrcr_count . get ( ) ) ;
p_child - > data . name = name ;
2014-02-10 01:10:30 +00:00
}
}
}
2019-01-10 21:52:47 +00:00
// Return s + 1 as if it were an integer
String increase_numeric_string ( const String & s ) {
String res = s ;
bool carry = res . length ( ) > 0 ;
2016-10-07 18:25:29 +00:00
2019-01-10 21:52:47 +00:00
for ( int i = res . length ( ) - 1 ; i > = 0 ; i - - ) {
if ( ! carry ) {
break ;
}
2020-07-27 10:43:20 +00:00
char32_t n = s [ i ] ;
2019-01-10 21:52:47 +00:00
if ( n = = ' 9 ' ) { // keep carry as true: 9 + 1
res [ i ] = ' 0 ' ;
} else {
res [ i ] = s [ i ] + 1 ;
carry = false ;
}
}
if ( carry ) {
res = " 1 " + res ;
}
return res ;
}
void Node : : _generate_serial_child_name ( const Node * p_child , StringName & name ) const {
if ( name = = StringName ( ) ) {
2021-03-12 13:35:16 +00:00
//no name and a new name is needed, create one.
2016-10-07 18:25:29 +00:00
2017-01-03 02:03:46 +00:00
name = p_child - > get_class ( ) ;
2017-01-12 18:13:09 +00:00
// Adjust casing according to project setting. The current type name is expected to be in PascalCase.
2021-02-17 16:44:49 +00:00
switch ( ProjectSettings : : get_singleton ( ) - > get ( " editor/node_naming/name_casing " ) . operator int ( ) ) {
2017-01-12 18:13:09 +00:00
case NAME_CASING_PASCAL_CASE :
break ;
2019-01-10 21:52:47 +00:00
case NAME_CASING_CAMEL_CASE : {
String n = name ;
n [ 0 ] = n . to_lower ( ) [ 0 ] ;
name = n ;
} break ;
2017-01-12 18:13:09 +00:00
case NAME_CASING_SNAKE_CASE :
2019-01-10 21:52:47 +00:00
name = String ( name ) . camelcase_to_underscore ( true ) ;
2017-01-12 18:13:09 +00:00
break ;
}
2016-10-07 18:25:29 +00:00
}
2019-01-10 21:52:47 +00:00
//quickly test if proposed name exists
int cc = data . children . size ( ) ; //children count
const Node * const * children_ptr = data . children . ptr ( ) ;
{
bool exists = false ;
for ( int i = 0 ; i < cc ; i + + ) {
2021-03-12 13:35:16 +00:00
if ( children_ptr [ i ] = = p_child ) { //exclude self in renaming if it's already a child
2019-01-10 21:52:47 +00:00
continue ;
}
if ( children_ptr [ i ] - > data . name = = name ) {
exists = true ;
}
}
if ( ! exists ) {
return ; //if it does not exist, it does not need validation
}
}
2016-10-10 11:06:13 +00:00
// Extract trailing number
2019-01-10 21:52:47 +00:00
String name_string = name ;
2016-10-07 18:25:29 +00:00
String nums ;
2019-01-10 21:52:47 +00:00
for ( int i = name_string . length ( ) - 1 ; i > = 0 ; i - - ) {
2020-07-27 10:43:20 +00:00
char32_t n = name_string [ i ] ;
2017-03-05 15:44:50 +00:00
if ( n > = ' 0 ' & & n < = ' 9 ' ) {
2019-01-10 21:52:47 +00:00
nums = String : : chr ( name_string [ i ] ) + nums ;
2016-10-07 18:25:29 +00:00
} else {
break ;
}
}
2017-03-05 15:44:50 +00:00
String nnsep = _get_name_num_separator ( ) ;
2019-01-10 21:52:47 +00:00
int name_last_index = name_string . length ( ) - nnsep . length ( ) - nums . length ( ) ;
// Assign the base name + separator to name if we have numbers preceded by a separator
if ( nums . length ( ) > 0 & & name_string . substr ( name_last_index , nnsep . length ( ) ) = = nnsep ) {
2019-01-11 22:02:07 +00:00
name_string = name_string . substr ( 0 , name_last_index + nnsep . length ( ) ) ;
2019-01-10 21:52:47 +00:00
} else {
nums = " " ;
2016-10-07 18:25:29 +00:00
}
2017-03-05 15:44:50 +00:00
for ( ; ; ) {
2019-01-10 21:52:47 +00:00
StringName attempt = name_string + nums ;
bool exists = false ;
for ( int i = 0 ; i < cc ; i + + ) {
if ( children_ptr [ i ] = = p_child ) {
2019-01-10 21:39:49 +00:00
continue ;
2019-01-10 21:52:47 +00:00
}
if ( children_ptr [ i ] - > data . name = = attempt ) {
exists = true ;
2019-01-10 21:39:49 +00:00
}
}
2019-01-10 21:52:47 +00:00
if ( ! exists ) {
name = attempt ;
return ;
2016-10-07 18:25:29 +00:00
} else {
2019-01-10 21:52:47 +00:00
if ( nums . length ( ) = = 0 ) {
// Name was undecorated so skip to 2 for a more natural result
nums = " 2 " ;
name_string + = nnsep ; // Add separator because nums.length() > 0 was false
2016-10-10 11:06:13 +00:00
} else {
2019-01-10 21:52:47 +00:00
nums = increase_numeric_string ( nums ) ;
2016-10-10 11:06:13 +00:00
}
2016-10-07 18:25:29 +00:00
}
}
}
2017-03-05 15:44:50 +00:00
void Node : : _add_child_nocheck ( Node * p_child , const StringName & p_name ) {
2014-02-10 01:10:30 +00:00
//add a child node quickly, without name validation
2017-03-05 15:44:50 +00:00
p_child - > data . name = p_name ;
p_child - > data . pos = data . children . size ( ) ;
data . children . push_back ( p_child ) ;
p_child - > data . parent = this ;
2015-06-14 05:13:47 +00:00
p_child - > notification ( NOTIFICATION_PARENTED ) ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree ) {
p_child - > _set_tree ( data . tree ) ;
2014-02-10 01:10:30 +00:00
}
/* Notify */
2018-01-18 20:37:17 +00:00
//recognize children created in this node constructor
2017-03-05 15:44:50 +00:00
p_child - > data . parent_owned = data . in_constructor ;
2014-02-10 01:10:30 +00:00
add_child_notify ( p_child ) ;
}
2015-12-08 14:21:12 +00:00
void Node : : add_child ( Node * p_child , bool p_legible_unique_name ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL_NULL ( p_child ) ;
2021-05-23 14:42:47 +00:00
ERR_FAIL_COND_MSG ( p_child = = this , vformat ( " Can't add child '%s' to itself. " , p_child - > get_name ( ) ) ) ; // adding to itself!
ERR_FAIL_COND_MSG ( p_child - > data . parent , vformat ( " Can't add child '%s' to '%s', already has a parent '%s'. " , p_child - > get_name ( ) , get_name ( ) , p_child - > data . parent - > get_name ( ) ) ) ; //Fail if node has a parent
# ifdef DEBUG_ENABLED
2021-06-18 22:02:50 +00:00
ERR_FAIL_COND_MSG ( p_child - > is_ancestor_of ( this ) , vformat ( " Can't add child '%s' to '%s' as it would result in a cyclic dependency since '%s' is already a parent of '%s'. " , p_child - > get_name ( ) , get_name ( ) , p_child - > get_name ( ) , get_name ( ) ) ) ;
2021-05-23 14:42:47 +00:00
# endif
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, add_node() failed. Consider using call_deferred( \" add_child \" , child) instead. " ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
/* Validate name */
2017-03-05 15:44:50 +00:00
_validate_child_name ( p_child , p_legible_unique_name ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
_add_child_nocheck ( p_child , p_child - > data . name ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-12 06:12:08 +00:00
void Node : : add_sibling ( Node * p_sibling , bool p_legible_unique_name ) {
ERR_FAIL_NULL ( p_sibling ) ;
2021-05-23 14:42:47 +00:00
ERR_FAIL_COND_MSG ( p_sibling = = this , vformat ( " Can't add sibling '%s' to itself. " , p_sibling - > get_name ( ) ) ) ; // adding to itself!
2020-05-12 06:12:08 +00:00
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, add_sibling() failed. Consider using call_deferred( \" add_sibling \" , sibling) instead. " ) ;
2016-05-13 16:09:49 +00:00
2020-05-12 06:12:08 +00:00
get_parent ( ) - > add_child ( p_sibling , p_legible_unique_name ) ;
get_parent ( ) - > move_child ( p_sibling , this - > get_index ( ) + 1 ) ;
2016-05-13 16:09:49 +00:00
}
2014-02-10 01:10:30 +00:00
void Node : : _propagate_validate_owner ( ) {
if ( data . owner ) {
2017-03-05 15:44:50 +00:00
bool found = false ;
2014-02-10 01:10:30 +00:00
Node * parent = data . parent ;
2017-03-05 15:44:50 +00:00
while ( parent ) {
if ( parent = = data . owner ) {
found = true ;
2014-02-10 01:10:30 +00:00
break ;
}
2017-03-05 15:44:50 +00:00
parent = parent - > data . parent ;
2014-02-10 01:10:30 +00:00
}
if ( ! found ) {
data . owner - > data . owned . erase ( data . OW ) ;
2020-04-01 23:20:12 +00:00
data . owner = nullptr ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
data . children [ i ] - > _propagate_validate_owner ( ) ;
}
}
void Node : : remove_child ( Node * p_child ) {
ERR_FAIL_NULL ( p_child ) ;
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_MSG ( data . blocked > 0 , " Parent node is busy setting up children, remove_node() failed. Consider using call_deferred( \" remove_child \" , child) instead. " ) ;
2016-03-08 23:00:52 +00:00
2018-11-18 14:47:19 +00:00
int child_count = data . children . size ( ) ;
Node * * children = data . children . ptrw ( ) ;
2017-03-05 15:44:50 +00:00
int idx = - 1 ;
2016-03-08 23:00:52 +00:00
2018-11-18 14:47:19 +00:00
if ( p_child - > data . pos > = 0 & & p_child - > data . pos < child_count ) {
if ( children [ p_child - > data . pos ] = = p_child ) {
idx = p_child - > data . pos ;
}
}
if ( idx = = - 1 ) { //maybe removed while unparenting or something and index was not updated, so just in case the above fails, try this.
for ( int i = 0 ; i < child_count ; i + + ) {
if ( children [ i ] = = p_child ) {
idx = i ;
break ;
}
2014-02-10 01:10:30 +00:00
}
}
2016-03-08 23:00:52 +00:00
2021-05-23 14:42:47 +00:00
ERR_FAIL_COND_MSG ( idx = = - 1 , vformat ( " Cannot remove child node '%s' as it is not a child of this node. " , p_child - > get_name ( ) ) ) ;
2015-12-29 19:06:45 +00:00
//ERR_FAIL_COND( p_child->data.blocked > 0 );
2014-02-10 01:10:30 +00:00
//if (data.scene) { does not matter
2016-03-08 23:00:52 +00:00
2020-04-01 23:20:12 +00:00
p_child - > _set_tree ( nullptr ) ;
2014-02-10 01:10:30 +00:00
//}
2016-03-08 23:00:52 +00:00
remove_child_notify ( p_child ) ;
2014-02-10 01:10:30 +00:00
p_child - > notification ( NOTIFICATION_UNPARENTED ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . children . remove ( idx ) ;
2016-03-08 23:00:52 +00:00
2018-11-18 14:47:19 +00:00
//update pointer and size
child_count = data . children . size ( ) ;
children = data . children . ptrw ( ) ;
2016-03-08 23:00:52 +00:00
2018-11-18 14:47:19 +00:00
for ( int i = idx ; i < child_count ; i + + ) {
children [ i ] - > data . pos = i ;
children [ i ] - > notification ( NOTIFICATION_MOVED_IN_PARENT ) ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2020-04-01 23:20:12 +00:00
p_child - > data . parent = nullptr ;
2017-03-05 15:44:50 +00:00
p_child - > data . pos = - 1 ;
2014-02-10 01:10:30 +00:00
// validate owner
p_child - > _propagate_validate_owner ( ) ;
2018-09-07 18:31:19 +00:00
if ( data . inside_tree ) {
p_child - > _propagate_after_exit_tree ( ) ;
}
2014-02-10 01:10:30 +00:00
}
int Node : : get_child_count ( ) const {
2016-03-08 23:00:52 +00:00
return data . children . size ( ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
Node * Node : : get_child ( int p_index ) const {
2020-08-25 12:46:33 +00:00
if ( p_index < 0 ) {
p_index + = data . children . size ( ) ;
}
2020-04-01 23:20:12 +00:00
ERR_FAIL_INDEX_V ( p_index , data . children . size ( ) , nullptr ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return data . children [ p_index ] ;
}
2017-03-05 15:44:50 +00:00
Node * Node : : _get_child_by_name ( const StringName & p_name ) const {
int cc = data . children . size ( ) ;
Node * const * cd = data . children . ptr ( ) ;
2015-10-10 12:09:09 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < cc ; i + + ) {
2020-05-14 14:41:43 +00:00
if ( cd [ i ] - > data . name = = p_name ) {
2015-10-10 12:09:09 +00:00
return cd [ i ] ;
2020-05-14 14:41:43 +00:00
}
2015-10-10 12:09:09 +00:00
}
2020-04-01 23:20:12 +00:00
return nullptr ;
2015-10-10 12:09:09 +00:00
}
2019-01-29 16:15:34 +00:00
Node * Node : : get_node_or_null ( const NodePath & p_path ) const {
2019-03-08 20:19:56 +00:00
if ( p_path . is_empty ( ) ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2019-03-08 20:19:56 +00:00
}
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V_MSG ( ! data . inside_tree & & p_path . is_absolute ( ) , nullptr , " Can't use get_node() with absolute paths from outside the active scene tree. " ) ;
2016-03-08 23:00:52 +00:00
2020-04-01 23:20:12 +00:00
Node * current = nullptr ;
Node * root = nullptr ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
if ( ! p_path . is_absolute ( ) ) {
2017-03-05 15:44:50 +00:00
current = const_cast < Node * > ( this ) ; //start from this
2014-02-10 01:10:30 +00:00
} else {
2017-03-05 15:44:50 +00:00
root = const_cast < Node * > ( this ) ;
2020-05-14 14:41:43 +00:00
while ( root - > data . parent ) {
2017-03-05 15:44:50 +00:00
root = root - > data . parent ; //start from root
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_path . get_name_count ( ) ; i + + ) {
2016-03-08 23:00:52 +00:00
StringName name = p_path . get_name ( i ) ;
2020-04-01 23:20:12 +00:00
Node * next = nullptr ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
if ( name = = SceneStringNames : : get_singleton ( ) - > dot ) { // .
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
next = current ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
} else if ( name = = SceneStringNames : : get_singleton ( ) - > doubledot ) { // ..
2016-03-08 23:00:52 +00:00
2020-05-14 14:41:43 +00:00
if ( current = = nullptr | | ! current - > data . parent ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
next = current - > data . parent ;
2020-04-01 23:20:12 +00:00
} else if ( current = = nullptr ) {
2020-05-14 14:41:43 +00:00
if ( name = = root - > get_name ( ) ) {
2017-03-05 15:44:50 +00:00
next = root ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
} else {
2020-04-01 23:20:12 +00:00
next = nullptr ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
for ( int j = 0 ; j < current - > data . children . size ( ) ; j + + ) {
2014-02-10 01:10:30 +00:00
Node * child = current - > data . children [ j ] ;
2017-03-05 15:44:50 +00:00
if ( child - > data . name = = name ) {
2014-02-10 01:10:30 +00:00
next = child ;
break ;
2016-03-08 23:00:52 +00:00
}
2014-02-10 01:10:30 +00:00
}
2020-04-01 23:20:12 +00:00
if ( next = = nullptr ) {
return nullptr ;
2014-02-10 01:10:30 +00:00
} ;
}
2017-03-05 15:44:50 +00:00
current = next ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return current ;
}
2017-03-05 15:44:50 +00:00
Node * Node : : get_node ( const NodePath & p_path ) const {
2019-01-29 16:15:34 +00:00
Node * node = get_node_or_null ( p_path ) ;
2021-02-20 01:05:19 +00:00
if ( p_path . is_absolute ( ) ) {
ERR_FAIL_COND_V_MSG ( ! node , nullptr ,
vformat ( R " (Node not found: " % s " (absolute path attempted from " % s " ).) " , p_path , get_path ( ) ) ) ;
} else {
ERR_FAIL_COND_V_MSG ( ! node , nullptr ,
vformat ( R " (Node not found: " % s " (relative to " % s " ).) " , p_path , get_path ( ) ) ) ;
}
2014-02-10 01:10:30 +00:00
return node ;
}
2017-03-05 15:44:50 +00:00
bool Node : : has_node ( const NodePath & p_path ) const {
2020-04-01 23:20:12 +00:00
return get_node_or_null ( p_path ) ! = nullptr ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Node * Node : : find_node ( const String & p_mask , bool p_recursive , bool p_owned ) const {
Node * const * cptr = data . children . ptr ( ) ;
2015-06-08 03:33:10 +00:00
int ccount = data . children . size ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < ccount ; i + + ) {
2020-05-14 14:41:43 +00:00
if ( p_owned & & ! cptr [ i ] - > data . owner ) {
2015-06-08 03:33:10 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
if ( cptr [ i ] - > data . name . operator String ( ) . match ( p_mask ) ) {
2015-06-08 03:33:10 +00:00
return cptr [ i ] ;
2020-05-14 14:41:43 +00:00
}
2015-06-08 03:33:10 +00:00
2020-05-14 14:41:43 +00:00
if ( ! p_recursive ) {
2015-06-08 03:33:10 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2015-06-08 03:33:10 +00:00
2017-03-05 15:44:50 +00:00
Node * ret = cptr [ i ] - > find_node ( p_mask , true , p_owned ) ;
2020-05-14 14:41:43 +00:00
if ( ret ) {
2015-06-08 03:33:10 +00:00
return ret ;
2020-05-14 14:41:43 +00:00
}
2015-06-08 03:33:10 +00:00
}
2020-04-01 23:20:12 +00:00
return nullptr ;
2015-06-08 03:33:10 +00:00
}
2014-02-10 01:10:30 +00:00
Node * Node : : get_parent ( ) const {
return data . parent ;
}
2018-09-15 16:22:06 +00:00
Node * Node : : find_parent ( const String & p_mask ) const {
Node * p = data . parent ;
while ( p ) {
2020-05-14 14:41:43 +00:00
if ( p - > data . name . operator String ( ) . match ( p_mask ) ) {
2018-09-15 16:22:06 +00:00
return p ;
2020-05-14 14:41:43 +00:00
}
2018-09-15 16:22:06 +00:00
p = p - > data . parent ;
}
2020-04-01 23:20:12 +00:00
return nullptr ;
2018-09-15 16:22:06 +00:00
}
2021-06-18 22:02:50 +00:00
bool Node : : is_ancestor_of ( const Node * p_node ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_NULL_V ( p_node , false ) ;
Node * p = p_node - > data . parent ;
while ( p ) {
2020-05-14 14:41:43 +00:00
if ( p = = this ) {
2014-02-10 01:10:30 +00:00
return true ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
p = p - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return false ;
}
bool Node : : is_greater_than ( const Node * p_node ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_NULL_V ( p_node , false ) ;
ERR_FAIL_COND_V ( ! data . inside_tree , false ) ;
ERR_FAIL_COND_V ( ! p_node - > data . inside_tree , false ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( data . depth < 0 , false ) ;
ERR_FAIL_COND_V ( p_node - > data . depth < 0 , false ) ;
2014-02-10 01:10:30 +00:00
# ifdef NO_ALLOCA
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
Vector < int > this_stack ;
Vector < int > that_stack ;
this_stack . resize ( data . depth ) ;
that_stack . resize ( p_node - > data . depth ) ;
# else
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
int * this_stack = ( int * ) alloca ( sizeof ( int ) * data . depth ) ;
int * that_stack = ( int * ) alloca ( sizeof ( int ) * p_node - > data . depth ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
# endif
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
const Node * n = this ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
int idx = data . depth - 1 ;
while ( n ) {
ERR_FAIL_INDEX_V ( idx , data . depth , false ) ;
this_stack [ idx - - ] = n - > data . pos ;
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( idx ! = - 1 , false ) ;
2014-02-10 01:10:30 +00:00
n = p_node ;
2017-03-05 15:44:50 +00:00
idx = p_node - > data . depth - 1 ;
while ( n ) {
ERR_FAIL_INDEX_V ( idx , p_node - > data . depth , false ) ;
that_stack [ idx - - ] = n - > data . pos ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( idx ! = - 1 , false ) ;
idx = 0 ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
bool res ;
2017-03-05 15:44:50 +00:00
while ( true ) {
2014-02-10 01:10:30 +00:00
// using -2 since out-of-tree or nonroot nodes have -1
2017-03-05 15:44:50 +00:00
int this_idx = ( idx > = data . depth ) ? - 2 : this_stack [ idx ] ;
int that_idx = ( idx > = p_node - > data . depth ) ? - 2 : that_stack [ idx ] ;
2014-02-10 01:10:30 +00:00
if ( this_idx > that_idx ) {
2017-03-05 15:44:50 +00:00
res = true ;
2014-02-10 01:10:30 +00:00
break ;
} else if ( this_idx < that_idx ) {
2017-03-05 15:44:50 +00:00
res = false ;
2014-02-10 01:10:30 +00:00
break ;
2017-03-05 15:44:50 +00:00
} else if ( this_idx = = - 2 ) {
res = false ; // equal
2014-02-10 01:10:30 +00:00
break ;
}
idx + + ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
return res ;
}
2017-03-05 15:44:50 +00:00
void Node : : get_owned_by ( Node * p_by , List < Node * > * p_owned ) {
2020-05-14 14:41:43 +00:00
if ( data . owner = = p_by ) {
2014-02-10 01:10:30 +00:00
p_owned - > push_back ( this ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2017-03-05 15:44:50 +00:00
get_child ( i ) - > get_owned_by ( p_by , p_owned ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : _set_owner_nocheck ( Node * p_owner ) {
2020-05-14 14:41:43 +00:00
if ( data . owner = = p_owner ) {
2017-03-15 11:28:57 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2017-03-15 11:28:57 +00:00
2015-10-16 22:11:23 +00:00
ERR_FAIL_COND ( data . owner ) ;
2017-03-05 15:44:50 +00:00
data . owner = p_owner ;
data . owner - > data . owned . push_back ( this ) ;
2014-02-10 01:10:30 +00:00
data . OW = data . owner - > data . owned . back ( ) ;
}
void Node : : set_owner ( Node * p_owner ) {
if ( data . owner ) {
2017-03-05 15:44:50 +00:00
data . owner - > data . owned . erase ( data . OW ) ;
2020-04-01 23:20:12 +00:00
data . OW = nullptr ;
data . owner = nullptr ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND ( p_owner = = this ) ;
2016-03-08 23:00:52 +00:00
2020-05-14 14:41:43 +00:00
if ( ! p_owner ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
Node * check = this - > get_parent ( ) ;
bool owner_valid = false ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( check ) {
if ( check = = p_owner ) {
owner_valid = true ;
2014-02-10 01:10:30 +00:00
break ;
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
check = check - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! owner_valid ) ;
_set_owner_nocheck ( p_owner ) ;
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
Node * Node : : get_owner ( ) const {
2016-03-08 23:00:52 +00:00
return data . owner ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Node * Node : : find_common_parent_with ( const Node * p_node ) const {
2020-05-14 14:41:43 +00:00
if ( this = = p_node ) {
2017-03-05 15:44:50 +00:00
return const_cast < Node * > ( p_node ) ;
2020-05-14 14:41:43 +00:00
}
2016-07-19 23:04:06 +00:00
2017-03-05 15:44:50 +00:00
Set < const Node * > visited ;
2016-07-19 23:04:06 +00:00
2017-03-05 15:44:50 +00:00
const Node * n = this ;
2016-07-19 23:04:06 +00:00
2017-03-05 15:44:50 +00:00
while ( n ) {
2016-07-19 23:04:06 +00:00
visited . insert ( n ) ;
2017-03-05 15:44:50 +00:00
n = n - > data . parent ;
2016-07-19 23:04:06 +00:00
}
2017-03-05 15:44:50 +00:00
const Node * common_parent = p_node ;
2016-07-19 23:04:06 +00:00
2017-03-05 15:44:50 +00:00
while ( common_parent ) {
2020-05-14 14:41:43 +00:00
if ( visited . has ( common_parent ) ) {
2016-07-19 23:04:06 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
common_parent = common_parent - > data . parent ;
2016-07-19 23:04:06 +00:00
}
2020-05-14 14:41:43 +00:00
if ( ! common_parent ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2016-07-19 23:04:06 +00:00
2017-03-05 15:44:50 +00:00
return const_cast < Node * > ( common_parent ) ;
2016-07-19 23:04:06 +00:00
}
2014-02-10 01:10:30 +00:00
NodePath Node : : get_path_to ( const Node * p_node ) const {
2017-03-05 15:44:50 +00:00
ERR_FAIL_NULL_V ( p_node , NodePath ( ) ) ;
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( this = = p_node ) {
2014-02-10 01:10:30 +00:00
return NodePath ( " . " ) ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
Set < const Node * > visited ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
const Node * n = this ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( n ) {
2014-02-10 01:10:30 +00:00
visited . insert ( n ) ;
2017-03-05 15:44:50 +00:00
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
const Node * common_parent = p_node ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( common_parent ) {
2020-05-14 14:41:43 +00:00
if ( visited . has ( common_parent ) ) {
2014-02-10 01:10:30 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2017-03-05 15:44:50 +00:00
common_parent = common_parent - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
ERR_FAIL_COND_V ( ! common_parent , NodePath ( ) ) ; //nodes not in the same tree
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
visited . clear ( ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
Vector < StringName > path ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
n = p_node ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( n ! = common_parent ) {
path . push_back ( n - > get_name ( ) ) ;
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
n = this ;
StringName up = String ( " .. " ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( n ! = common_parent ) {
path . push_back ( up ) ;
n = n - > data . parent ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2021-03-14 07:21:32 +00:00
path . reverse ( ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
return NodePath ( path , false ) ;
2014-02-10 01:10:30 +00:00
}
NodePath Node : : get_path ( ) const {
2019-08-08 20:11:48 +00:00
ERR_FAIL_COND_V_MSG ( ! is_inside_tree ( ) , NodePath ( ) , " Cannot get path of node as it is not in a scene tree. " ) ;
2016-08-14 21:49:50 +00:00
2020-05-14 14:41:43 +00:00
if ( data . path_cache ) {
2016-08-14 21:49:50 +00:00
return * data . path_cache ;
2020-05-14 14:41:43 +00:00
}
2016-08-14 21:49:50 +00:00
2014-02-10 01:10:30 +00:00
const Node * n = this ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
Vector < StringName > path ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( n ) {
2014-02-10 01:10:30 +00:00
path . push_back ( n - > get_name ( ) ) ;
2017-03-05 15:44:50 +00:00
n = n - > data . parent ;
2016-03-08 23:00:52 +00:00
}
2021-03-14 07:21:32 +00:00
path . reverse ( ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
data . path_cache = memnew ( NodePath ( path , true ) ) ;
2016-08-14 21:49:50 +00:00
return * data . path_cache ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
bool Node : : is_in_group ( const StringName & p_identifier ) const {
2014-02-10 01:10:30 +00:00
return data . grouped . has ( p_identifier ) ;
}
2017-03-05 15:44:50 +00:00
void Node : : add_to_group ( const StringName & p_identifier , bool p_persistent ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( ! p_identifier . operator String ( ) . length ( ) ) ;
2016-03-08 23:00:52 +00:00
2020-05-14 14:41:43 +00:00
if ( data . grouped . has ( p_identifier ) ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
GroupData gd ;
2016-03-08 23:00:52 +00:00
2016-06-08 01:08:12 +00:00
if ( data . tree ) {
2017-03-05 15:44:50 +00:00
gd . group = data . tree - > add_to_group ( p_identifier , this ) ;
2016-06-08 01:08:12 +00:00
} else {
2020-04-01 23:20:12 +00:00
gd . group = nullptr ;
2016-06-08 01:08:12 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
gd . persistent = p_persistent ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
data . grouped [ p_identifier ] = gd ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : remove_from_group ( const StringName & p_identifier ) {
ERR_FAIL_COND ( ! data . grouped . has ( p_identifier ) ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
Map < StringName , GroupData > : : Element * E = data . grouped . find ( p_identifier ) ;
2016-06-08 01:08:12 +00:00
ERR_FAIL_COND ( ! E ) ;
2016-03-08 23:00:52 +00:00
2020-05-14 14:41:43 +00:00
if ( data . tree ) {
2017-03-05 15:44:50 +00:00
data . tree - > remove_from_group ( E - > key ( ) , this ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2016-06-08 01:08:12 +00:00
data . grouped . erase ( E ) ;
2014-02-10 01:10:30 +00:00
}
2014-06-16 13:22:26 +00:00
Array Node : : _get_groups ( ) const {
Array groups ;
List < GroupInfo > gi ;
get_groups ( & gi ) ;
2021-07-24 13:46:25 +00:00
for ( const GroupInfo & E : gi ) {
2021-07-16 03:45:57 +00:00
groups . push_back ( E . name ) ;
2014-06-16 13:22:26 +00:00
}
return groups ;
}
2014-02-10 01:10:30 +00:00
void Node : : get_groups ( List < GroupInfo > * p_groups ) const {
2017-03-05 15:44:50 +00:00
for ( const Map < StringName , GroupData > : : Element * E = data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
GroupInfo gi ;
2017-03-05 15:44:50 +00:00
gi . name = E - > key ( ) ;
gi . persistent = E - > get ( ) . persistent ;
2014-02-10 01:10:30 +00:00
p_groups - > push_back ( gi ) ;
}
}
2019-08-16 20:30:31 +00:00
int Node : : get_persistent_group_count ( ) const {
int count = 0 ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( const Map < StringName , GroupData > : : Element * E = data . grouped . front ( ) ; E ; E = E - > next ( ) ) {
2019-08-16 20:30:31 +00:00
if ( E - > get ( ) . persistent ) {
count + = 1 ;
}
2016-06-04 16:17:56 +00:00
}
2019-08-16 20:30:31 +00:00
return count ;
2016-06-04 16:17:56 +00:00
}
2020-05-14 12:29:06 +00:00
2019-07-10 09:54:12 +00:00
void Node : : _print_tree_pretty ( const String & prefix , const bool last ) {
2018-02-28 09:12:06 +00:00
String new_prefix = last ? String : : utf8 ( " ┖╴ " ) : String : : utf8 ( " ┠╴ " ) ;
print_line ( prefix + new_prefix + String ( get_name ( ) ) ) ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
new_prefix = last ? String : : utf8 ( " " ) : String : : utf8 ( " ┃ " ) ;
data . children [ i ] - > _print_tree_pretty ( prefix + new_prefix , i = = data . children . size ( ) - 1 ) ;
}
}
void Node : : print_tree_pretty ( ) {
_print_tree_pretty ( " " , true ) ;
2014-02-10 01:10:30 +00:00
}
void Node : : print_tree ( ) {
_print_tree ( this ) ;
}
2018-02-28 09:12:06 +00:00
void Node : : _print_tree ( const Node * p_node ) {
print_line ( String ( p_node - > get_path_to ( this ) ) ) ;
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2018-02-28 09:12:06 +00:00
data . children [ i ] - > _print_tree ( p_node ) ;
2020-05-14 14:41:43 +00:00
}
2018-02-28 09:12:06 +00:00
}
2014-02-10 01:10:30 +00:00
void Node : : _propagate_reverse_notification ( int p_notification ) {
2016-03-08 23:00:52 +00:00
data . blocked + + ;
2017-03-05 15:44:50 +00:00
for ( int i = data . children . size ( ) - 1 ; i > = 0 ; i - - ) {
2016-03-08 23:00:52 +00:00
data . children [ i ] - > _propagate_reverse_notification ( p_notification ) ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
notification ( p_notification , true ) ;
2014-02-10 01:10:30 +00:00
data . blocked - - ;
}
void Node : : _propagate_deferred_notification ( int p_notification , bool p_reverse ) {
2014-11-06 00:20:42 +00:00
ERR_FAIL_COND ( ! is_inside_tree ( ) ) ;
2014-02-10 01:10:30 +00:00
data . blocked + + ;
2020-05-14 14:41:43 +00:00
if ( ! p_reverse ) {
2017-03-05 15:44:50 +00:00
MessageQueue : : get_singleton ( ) - > push_notification ( this , p_notification ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > _propagate_deferred_notification ( p_notification , p_reverse ) ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 14:41:43 +00:00
if ( p_reverse ) {
2017-03-05 15:44:50 +00:00
MessageQueue : : get_singleton ( ) - > push_notification ( this , p_notification ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
data . blocked - - ;
}
void Node : : propagate_notification ( int p_notification ) {
2016-03-08 23:00:52 +00:00
data . blocked + + ;
2014-02-10 01:10:30 +00:00
notification ( p_notification ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2016-03-08 23:00:52 +00:00
data . children [ i ] - > propagate_notification ( p_notification ) ;
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
data . blocked - - ;
2014-02-10 01:10:30 +00:00
}
2017-08-19 13:17:06 +00:00
void Node : : propagate_call ( const StringName & p_method , const Array & p_args , const bool p_parent_first ) {
data . blocked + + ;
2020-05-14 14:41:43 +00:00
if ( p_parent_first & & has_method ( p_method ) ) {
2017-08-19 13:17:06 +00:00
callv ( p_method , p_args ) ;
2020-05-14 14:41:43 +00:00
}
2017-08-19 13:17:06 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
data . children [ i ] - > propagate_call ( p_method , p_args , p_parent_first ) ;
}
2020-05-14 14:41:43 +00:00
if ( ! p_parent_first & & has_method ( p_method ) ) {
2017-08-19 13:17:06 +00:00
callv ( p_method , p_args ) ;
2020-05-14 14:41:43 +00:00
}
2017-08-19 13:17:06 +00:00
data . blocked - - ;
}
2017-03-05 15:44:50 +00:00
void Node : : _propagate_replace_owner ( Node * p_owner , Node * p_by_owner ) {
2020-05-14 14:41:43 +00:00
if ( get_owner ( ) = = p_owner ) {
2014-02-10 01:10:30 +00:00
set_owner ( p_by_owner ) ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . blocked + + ;
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2017-03-05 15:44:50 +00:00
data . children [ i ] - > _propagate_replace_owner ( p_owner , p_by_owner ) ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
data . blocked - - ;
2014-02-10 01:10:30 +00:00
}
int Node : : get_index ( ) const {
return data . pos ;
}
2020-04-05 23:06:10 +00:00
2020-09-05 01:05:30 +00:00
Ref < Tween > Node : : create_tween ( ) {
ERR_FAIL_COND_V_MSG ( ! data . tree , nullptr , " Can't create Tween when not inside scene tree. " ) ;
Ref < Tween > tween = get_tree ( ) - > create_tween ( ) ;
tween - > bind_node ( this ) ;
return tween ;
}
2014-02-10 01:10:30 +00:00
void Node : : remove_and_skip ( ) {
ERR_FAIL_COND ( ! data . parent ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
Node * new_owner = get_owner ( ) ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
List < Node * > children ;
2016-03-08 23:00:52 +00:00
2017-03-05 15:44:50 +00:00
while ( true ) {
bool clear = true ;
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2017-03-12 17:50:43 +00:00
Node * c_node = data . children [ i ] ;
2020-05-14 14:41:43 +00:00
if ( ! c_node - > get_owner ( ) ) {
2014-02-10 01:10:30 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2016-03-08 23:00:52 +00:00
2017-03-12 17:50:43 +00:00
remove_child ( c_node ) ;
2020-04-01 23:20:12 +00:00
c_node - > _propagate_replace_owner ( this , nullptr ) ;
2017-03-12 17:50:43 +00:00
children . push_back ( c_node ) ;
2017-03-05 15:44:50 +00:00
clear = false ;
2014-02-10 01:10:30 +00:00
break ;
}
2016-03-08 23:00:52 +00:00
2020-05-14 14:41:43 +00:00
if ( clear ) {
2014-02-10 01:10:30 +00:00
break ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2016-03-08 23:00:52 +00:00
2020-12-15 12:04:21 +00:00
while ( ! children . is_empty ( ) ) {
2017-03-12 17:50:43 +00:00
Node * c_node = children . front ( ) - > get ( ) ;
data . parent - > add_child ( c_node ) ;
2020-04-01 23:20:12 +00:00
c_node - > _propagate_replace_owner ( nullptr , new_owner ) ;
2014-02-10 01:10:30 +00:00
children . pop_front ( ) ;
}
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
data . parent - > remove_child ( this ) ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_filename ( const String & p_filename ) {
data . filename = p_filename ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 12:29:06 +00:00
2014-02-10 01:10:30 +00:00
String Node : : get_filename ( ) const {
return data . filename ;
}
2019-08-15 12:50:26 +00:00
void Node : : set_editor_description ( const String & p_editor_description ) {
2021-02-18 18:52:29 +00:00
data . editor_description = p_editor_description ;
2019-08-15 12:50:26 +00:00
}
2020-05-14 12:29:06 +00:00
2019-08-15 12:50:26 +00:00
String Node : : get_editor_description ( ) const {
2021-02-18 18:52:29 +00:00
return data . editor_description ;
2019-08-15 12:50:26 +00:00
}
2017-03-05 15:44:50 +00:00
void Node : : set_editable_instance ( Node * p_node , bool p_editable ) {
2015-10-10 12:09:09 +00:00
ERR_FAIL_NULL ( p_node ) ;
2021-06-18 22:02:50 +00:00
ERR_FAIL_COND ( ! is_ancestor_of ( p_node ) ) ;
2017-04-07 13:48:07 +00:00
if ( ! p_editable ) {
2021-01-17 22:37:40 +00:00
p_node - > data . editable_instance = false ;
2017-04-07 13:48:07 +00:00
// Avoid this flag being needlessly saved;
2021-03-12 13:35:16 +00:00
// also give more visual feedback if editable children are re-enabled
2017-04-07 13:48:07 +00:00
set_display_folded ( false ) ;
} else {
2021-01-17 22:37:40 +00:00
p_node - > data . editable_instance = true ;
2017-04-07 13:48:07 +00:00
}
2015-10-10 12:09:09 +00:00
}
2018-10-29 19:36:31 +00:00
bool Node : : is_editable_instance ( const Node * p_node ) const {
2020-05-14 14:41:43 +00:00
if ( ! p_node ) {
2021-01-17 22:37:40 +00:00
return false ; // Easier, null is never editable. :)
2020-05-14 14:41:43 +00:00
}
2021-06-18 22:02:50 +00:00
ERR_FAIL_COND_V ( ! is_ancestor_of ( p_node ) , false ) ;
2021-01-17 22:37:40 +00:00
return p_node - > data . editable_instance ;
2016-04-12 16:21:37 +00:00
}
2021-02-21 08:19:48 +00:00
Node * Node : : get_deepest_editable_node ( Node * p_start_node ) const {
ERR_FAIL_NULL_V ( p_start_node , nullptr ) ;
2021-06-18 22:02:50 +00:00
ERR_FAIL_COND_V ( ! is_ancestor_of ( p_start_node ) , p_start_node ) ;
2021-02-21 08:19:48 +00:00
Node const * iterated_item = p_start_node ;
Node * node = p_start_node ;
while ( iterated_item - > get_owner ( ) & & iterated_item - > get_owner ( ) ! = this ) {
2021-04-05 12:09:59 +00:00
if ( ! is_editable_instance ( iterated_item - > get_owner ( ) ) ) {
2021-02-21 08:19:48 +00:00
node = iterated_item - > get_owner ( ) ;
2021-04-05 12:09:59 +00:00
}
2021-02-21 08:19:48 +00:00
iterated_item = iterated_item - > get_owner ( ) ;
}
return node ;
}
2021-07-11 14:40:18 +00:00
String Node : : to_string ( ) {
if ( get_script_instance ( ) ) {
bool valid ;
String ret = get_script_instance ( ) - > to_string ( & valid ) ;
if ( valid ) {
return ret ;
}
}
return ( get_name ( ) ? String ( get_name ( ) ) + " : " : " " ) + Object : : to_string ( ) ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_scene_instance_state ( const Ref < SceneState > & p_state ) {
data . instance_state = p_state ;
2015-10-10 12:09:09 +00:00
}
2017-03-05 15:44:50 +00:00
Ref < SceneState > Node : : get_scene_instance_state ( ) const {
2015-10-10 12:09:09 +00:00
return data . instance_state ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_scene_inherited_state ( const Ref < SceneState > & p_state ) {
data . inherited_state = p_state ;
2015-10-10 12:09:09 +00:00
}
2017-03-05 15:44:50 +00:00
Ref < SceneState > Node : : get_scene_inherited_state ( ) const {
2015-10-10 12:09:09 +00:00
return data . inherited_state ;
}
2015-10-16 22:11:23 +00:00
void Node : : set_scene_instance_load_placeholder ( bool p_enable ) {
2017-03-05 15:44:50 +00:00
data . use_placeholder = p_enable ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
bool Node : : get_scene_instance_load_placeholder ( ) const {
2015-10-16 22:11:23 +00:00
return data . use_placeholder ;
2014-02-10 01:10:30 +00:00
}
2017-11-19 13:32:10 +00:00
Node * Node : : _duplicate ( int p_flags , Map < const Node * , Node * > * r_duplimap ) const {
2020-04-01 23:20:12 +00:00
Node * node = nullptr ;
2014-02-10 01:10:30 +00:00
2021-06-17 22:03:09 +00:00
bool instantiated = false ;
2015-08-02 15:29:37 +00:00
2017-08-24 20:58:51 +00:00
if ( Object : : cast_to < InstancePlaceholder > ( this ) ) {
const InstancePlaceholder * ip = Object : : cast_to < const InstancePlaceholder > ( this ) ;
2017-03-05 15:44:50 +00:00
InstancePlaceholder * nip = memnew ( InstancePlaceholder ) ;
nip - > set_instance_path ( ip - > get_instance_path ( ) ) ;
node = nip ;
2016-01-22 22:36:40 +00:00
2017-03-05 15:44:50 +00:00
} else if ( ( p_flags & DUPLICATE_USE_INSTANCING ) & & get_filename ( ) ! = String ( ) ) {
2015-08-02 15:29:37 +00:00
Ref < PackedScene > res = ResourceLoader : : load ( get_filename ( ) ) ;
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V ( res . is_null ( ) , nullptr ) ;
2017-11-19 13:32:10 +00:00
PackedScene : : GenEditState ges = PackedScene : : GEN_EDIT_STATE_DISABLED ;
# ifdef TOOLS_ENABLED
2020-05-14 14:41:43 +00:00
if ( p_flags & DUPLICATE_FROM_EDITOR ) {
2017-11-19 13:32:10 +00:00
ges = PackedScene : : GEN_EDIT_STATE_INSTANCE ;
2020-05-14 14:41:43 +00:00
}
2017-11-19 13:32:10 +00:00
# endif
2021-06-17 22:03:09 +00:00
node = res - > instantiate ( ges ) ;
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V ( ! node , nullptr ) ;
2015-08-02 15:29:37 +00:00
2021-06-17 22:03:09 +00:00
instantiated = true ;
2015-08-02 15:29:37 +00:00
} else {
2021-06-17 22:03:09 +00:00
Object * obj = ClassDB : : instantiate ( get_class ( ) ) ;
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V ( ! obj , nullptr ) ;
2017-08-24 20:58:51 +00:00
node = Object : : cast_to < Node > ( obj ) ;
2020-05-14 14:41:43 +00:00
if ( ! node ) {
2015-08-02 15:29:37 +00:00
memdelete ( obj ) ;
2020-05-14 14:41:43 +00:00
}
2020-04-01 23:20:12 +00:00
ERR_FAIL_COND_V ( ! node , nullptr ) ;
2015-08-02 15:29:37 +00:00
}
2014-02-10 01:10:30 +00:00
2017-10-13 22:03:33 +00:00
if ( get_filename ( ) ! = " " ) { //an instance
node - > set_filename ( get_filename ( ) ) ;
2021-02-28 16:19:01 +00:00
node - > data . editable_instance = data . editable_instance ;
2017-10-13 22:03:33 +00:00
}
2014-02-10 01:10:30 +00:00
2017-09-06 12:21:19 +00:00
StringName script_property_name = CoreStringNames : : get_singleton ( ) - > _script ;
2017-12-08 14:05:15 +00:00
List < const Node * > hidden_roots ;
2017-10-13 22:03:33 +00:00
List < const Node * > node_tree ;
node_tree . push_front ( this ) ;
2021-06-17 22:03:09 +00:00
if ( instantiated ) {
// Since nodes in the instantiated hierarchy won't be duplicated explicitly, we need to make an inventory
// of all the nodes in the tree of the instantiated scene in order to transfer the values of the properties
2017-11-25 20:13:52 +00:00
2021-02-22 15:50:44 +00:00
Vector < const Node * > instance_roots ;
instance_roots . push_back ( this ) ;
2017-10-13 22:03:33 +00:00
for ( List < const Node * > : : Element * N = node_tree . front ( ) ; N ; N = N - > next ( ) ) {
for ( int i = 0 ; i < N - > get ( ) - > get_child_count ( ) ; + + i ) {
2017-12-08 14:05:15 +00:00
Node * descendant = N - > get ( ) - > get_child ( i ) ;
2021-06-17 22:03:09 +00:00
// Skip nodes not really belonging to the instantiated hierarchy; they'll be processed normally later
// but remember non-instantiated nodes that are hidden below instantiated ones
2021-02-22 15:50:44 +00:00
if ( ! instance_roots . has ( descendant - > get_owner ( ) ) ) {
if ( descendant - > get_parent ( ) & & descendant - > get_parent ( ) ! = this & & descendant - > data . owner ! = descendant - > get_parent ( ) ) {
2017-12-08 14:05:15 +00:00
hidden_roots . push_back ( descendant ) ;
2020-05-14 14:41:43 +00:00
}
2017-11-25 20:13:52 +00:00
continue ;
2017-12-08 14:05:15 +00:00
}
2017-11-25 20:13:52 +00:00
2017-12-08 14:05:15 +00:00
node_tree . push_back ( descendant ) ;
2021-02-22 15:50:44 +00:00
if ( descendant - > get_filename ( ) ! = " " & & instance_roots . has ( descendant - > get_owner ( ) ) ) {
instance_roots . push_back ( descendant ) ;
}
2017-10-13 22:03:33 +00:00
}
2017-09-06 12:21:19 +00:00
}
}
2017-10-13 22:03:33 +00:00
for ( List < const Node * > : : Element * N = node_tree . front ( ) ; N ; N = N - > next ( ) ) {
Node * current_node = node - > get_node ( get_path_to ( N - > get ( ) ) ) ;
2017-11-25 20:13:52 +00:00
ERR_CONTINUE ( ! current_node ) ;
2017-02-20 19:05:01 +00:00
2017-10-13 22:03:33 +00:00
if ( p_flags & DUPLICATE_SCRIPTS ) {
bool is_valid = false ;
Variant script = N - > get ( ) - > get ( script_property_name , & is_valid ) ;
if ( is_valid ) {
current_node - > set ( script_property_name , script ) ;
}
2017-09-11 09:34:36 +00:00
}
2017-10-13 22:03:33 +00:00
List < PropertyInfo > plist ;
N - > get ( ) - > get_property_list ( & plist ) ;
2021-07-24 13:46:25 +00:00
for ( const PropertyInfo & E : plist ) {
2021-07-16 03:45:57 +00:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2017-10-13 22:03:33 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2021-07-16 03:45:57 +00:00
String name = E . name ;
2020-05-14 14:41:43 +00:00
if ( name = = script_property_name ) {
2017-10-13 22:03:33 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2017-10-13 22:03:33 +00:00
2018-03-09 19:16:08 +00:00
Variant value = N - > get ( ) - > get ( name ) . duplicate ( true ) ;
2017-10-13 22:03:33 +00:00
2021-07-16 03:45:57 +00:00
if ( E . usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE ) {
2018-01-11 18:50:33 +00:00
Resource * res = Object : : cast_to < Resource > ( value ) ;
2018-07-02 18:08:35 +00:00
if ( res ) { // Duplicate only if it's a resource
2018-01-11 18:50:33 +00:00
current_node - > set ( name , res - > duplicate ( ) ) ;
2018-07-02 18:08:35 +00:00
}
2018-01-11 18:50:33 +00:00
} else {
current_node - > set ( name , value ) ;
}
2017-10-13 22:03:33 +00:00
}
2014-02-10 01:10:30 +00:00
}
2019-05-28 10:40:39 +00:00
if ( get_name ( ) ! = String ( ) ) {
node - > set_name ( get_name ( ) ) ;
}
2014-02-10 01:10:30 +00:00
2017-11-19 13:32:10 +00:00
# ifdef TOOLS_ENABLED
2020-05-14 14:41:43 +00:00
if ( ( p_flags & DUPLICATE_FROM_EDITOR ) & & r_duplimap ) {
2017-11-19 13:32:10 +00:00
r_duplimap - > insert ( this , node ) ;
2020-05-14 14:41:43 +00:00
}
2017-11-19 13:32:10 +00:00
# endif
2017-02-20 19:05:01 +00:00
if ( p_flags & DUPLICATE_GROUPS ) {
List < GroupInfo > gi ;
get_groups ( & gi ) ;
2021-07-24 13:46:25 +00:00
for ( const GroupInfo & E : gi ) {
2017-11-19 13:32:10 +00:00
# ifdef TOOLS_ENABLED
2021-07-16 03:45:57 +00:00
if ( ( p_flags & DUPLICATE_FROM_EDITOR ) & & ! E . persistent ) {
2017-11-19 13:32:10 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2017-11-19 13:32:10 +00:00
# endif
2021-07-16 03:45:57 +00:00
node - > add_to_group ( E . name , E . persistent ) ;
2017-02-20 19:05:01 +00:00
}
2016-01-19 23:08:04 +00:00
}
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2020-05-14 14:41:43 +00:00
if ( get_child ( i ) - > data . parent_owned ) {
2014-02-10 01:10:30 +00:00
continue ;
2020-05-14 14:41:43 +00:00
}
2021-06-17 22:03:09 +00:00
if ( instantiated & & get_child ( i ) - > data . owner = = this ) {
2015-08-02 15:29:37 +00:00
continue ; //part of instance
2020-05-14 14:41:43 +00:00
}
2015-08-02 15:29:37 +00:00
2017-11-19 13:32:10 +00:00
Node * dup = get_child ( i ) - > _duplicate ( p_flags , r_duplimap ) ;
2014-02-10 01:10:30 +00:00
if ( ! dup ) {
memdelete ( node ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2014-02-10 01:10:30 +00:00
}
node - > add_child ( dup ) ;
2017-12-08 14:05:15 +00:00
if ( i < node - > get_child_count ( ) - 1 ) {
node - > move_child ( dup , i ) ;
}
}
2021-07-16 03:45:57 +00:00
for ( const Node * & E : hidden_roots ) {
Node * parent = node - > get_node ( get_path_to ( E - > data . parent ) ) ;
2017-12-08 14:05:15 +00:00
if ( ! parent ) {
memdelete ( node ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2017-12-08 14:05:15 +00:00
}
2021-07-16 03:45:57 +00:00
Node * dup = E - > _duplicate ( p_flags , r_duplimap ) ;
2017-12-08 14:05:15 +00:00
if ( ! dup ) {
memdelete ( node ) ;
2020-04-01 23:20:12 +00:00
return nullptr ;
2017-12-08 14:05:15 +00:00
}
parent - > add_child ( dup ) ;
2021-07-16 03:45:57 +00:00
int pos = E - > get_index ( ) ;
2017-12-08 14:05:15 +00:00
if ( pos < parent - > get_child_count ( ) - 1 ) {
parent - > move_child ( dup , pos ) ;
}
2014-02-10 01:10:30 +00:00
}
return node ;
}
2017-11-19 12:05:18 +00:00
Node * Node : : duplicate ( int p_flags ) const {
Node * dupe = _duplicate ( p_flags ) ;
if ( dupe & & ( p_flags & DUPLICATE_SIGNALS ) ) {
_duplicate_signals ( this , dupe ) ;
}
return dupe ;
}
2017-11-19 13:32:10 +00:00
# ifdef TOOLS_ENABLED
Node * Node : : duplicate_from_editor ( Map < const Node * , Node * > & r_duplimap ) const {
2021-02-12 16:36:37 +00:00
return duplicate_from_editor ( r_duplimap , Map < RES , RES > ( ) ) ;
}
Node * Node : : duplicate_from_editor ( Map < const Node * , Node * > & r_duplimap , const Map < RES , RES > & p_resource_remap ) const {
2017-11-19 13:32:10 +00:00
Node * dupe = _duplicate ( DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANCING | DUPLICATE_FROM_EDITOR , & r_duplimap ) ;
2021-02-12 16:36:37 +00:00
// This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated.
if ( ! p_resource_remap . is_empty ( ) ) {
remap_node_resources ( dupe , p_resource_remap ) ;
}
2017-11-19 13:32:10 +00:00
// Duplication of signals must happen after all the node descendants have been copied,
// because re-targeting of connections from some descendant to another is not possible
// if the emitter node comes later in tree order than the receiver
_duplicate_signals ( this , dupe ) ;
return dupe ;
}
2021-02-12 16:36:37 +00:00
void Node : : remap_node_resources ( Node * p_node , const Map < RES , RES > & p_resource_remap ) const {
List < PropertyInfo > props ;
p_node - > get_property_list ( & props ) ;
2021-07-24 13:46:25 +00:00
for ( const PropertyInfo & E : props ) {
2021-07-16 03:45:57 +00:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2021-02-12 16:36:37 +00:00
continue ;
}
2021-07-16 03:45:57 +00:00
Variant v = p_node - > get ( E . name ) ;
2021-02-12 16:36:37 +00:00
if ( v . is_ref ( ) ) {
RES res = v ;
if ( res . is_valid ( ) ) {
if ( p_resource_remap . has ( res ) ) {
2021-07-16 03:45:57 +00:00
p_node - > set ( E . name , p_resource_remap [ res ] ) ;
2021-02-12 16:36:37 +00:00
remap_nested_resources ( res , p_resource_remap ) ;
}
}
}
}
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
remap_node_resources ( p_node - > get_child ( i ) , p_resource_remap ) ;
}
}
void Node : : remap_nested_resources ( RES p_resource , const Map < RES , RES > & p_resource_remap ) const {
List < PropertyInfo > props ;
p_resource - > get_property_list ( & props ) ;
2021-07-24 13:46:25 +00:00
for ( const PropertyInfo & E : props ) {
2021-07-16 03:45:57 +00:00
if ( ! ( E . usage & PROPERTY_USAGE_STORAGE ) ) {
2021-02-12 16:36:37 +00:00
continue ;
}
2021-07-16 03:45:57 +00:00
Variant v = p_resource - > get ( E . name ) ;
2021-02-12 16:36:37 +00:00
if ( v . is_ref ( ) ) {
RES res = v ;
if ( res . is_valid ( ) ) {
if ( p_resource_remap . has ( res ) ) {
2021-07-16 03:45:57 +00:00
p_resource - > set ( E . name , p_resource_remap [ res ] ) ;
2021-02-12 16:36:37 +00:00
remap_nested_resources ( res , p_resource_remap ) ;
}
}
}
}
}
2017-11-19 13:32:10 +00:00
# endif
2017-11-19 12:05:18 +00:00
// Duplication of signals must happen after all the node descendants have been copied,
// because re-targeting of connections from some descendant to another is not possible
// if the emitter node comes later in tree order than the receiver
2017-03-05 15:44:50 +00:00
void Node : : _duplicate_signals ( const Node * p_original , Node * p_copy ) const {
2021-06-18 22:02:50 +00:00
if ( ( this ! = p_original ) & & ! ( p_original - > is_ancestor_of ( this ) ) ) {
2015-05-10 18:45:33 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2015-05-10 18:45:33 +00:00
2020-06-08 09:19:50 +00:00
List < const Node * > process_list ;
process_list . push_back ( this ) ;
2020-12-15 12:04:21 +00:00
while ( ! process_list . is_empty ( ) ) {
2020-06-08 09:19:50 +00:00
const Node * n = process_list . front ( ) - > get ( ) ;
process_list . pop_front ( ) ;
2015-05-10 18:45:33 +00:00
2020-06-08 09:19:50 +00:00
List < Connection > conns ;
n - > get_all_signal_connections ( & conns ) ;
2015-05-10 18:45:33 +00:00
2021-07-24 13:46:25 +00:00
for ( const Connection & E : conns ) {
2021-07-16 03:45:57 +00:00
if ( E . flags & CONNECT_PERSIST ) {
2020-06-08 09:19:50 +00:00
//user connected
NodePath p = p_original - > get_path_to ( n ) ;
Node * copy = p_copy - > get_node ( p ) ;
2015-05-10 18:45:33 +00:00
2021-07-16 03:45:57 +00:00
Node * target = Object : : cast_to < Node > ( E . callable . get_object ( ) ) ;
2020-06-08 09:19:50 +00:00
if ( ! target ) {
continue ;
}
NodePath ptarget = p_original - > get_path_to ( target ) ;
2018-10-03 12:59:16 +00:00
2020-06-08 09:19:50 +00:00
Node * copytarget = target ;
2018-10-03 12:59:16 +00:00
2020-06-08 09:19:50 +00:00
// Attempt to find a path to the duplicate target, if it seems it's not part
// of the duplicated and not yet parented hierarchy then at least try to connect
// to the same target as the original
2017-11-19 12:05:18 +00:00
2020-06-08 09:19:50 +00:00
if ( p_copy - > has_node ( ptarget ) ) {
copytarget = p_copy - > get_node ( ptarget ) ;
}
if ( copy & & copytarget ) {
2021-07-16 03:45:57 +00:00
const Callable copy_callable = Callable ( copytarget , E . callable . get_method ( ) ) ;
if ( ! copy - > is_connected ( E . signal . get_name ( ) , copy_callable ) ) {
copy - > connect ( E . signal . get_name ( ) , copy_callable , E . binds , E . flags ) ;
2020-06-08 09:19:50 +00:00
}
2020-02-21 22:26:13 +00:00
}
2015-05-10 18:45:33 +00:00
}
}
2020-06-08 09:19:50 +00:00
for ( int i = 0 ; i < n - > get_child_count ( ) ; i + + ) {
process_list . push_back ( n - > get_child ( i ) ) ;
}
2015-05-10 18:45:33 +00:00
}
}
2017-03-05 15:44:50 +00:00
static void find_owned_by ( Node * p_by , Node * p_node , List < Node * > * p_owned ) {
2020-05-14 14:41:43 +00:00
if ( p_node - > get_owner ( ) = = p_by ) {
2014-02-10 01:10:30 +00:00
p_owned - > push_back ( p_node ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
find_owned_by ( p_by , p_node - > get_child ( i ) , p_owned ) ;
2014-02-10 01:10:30 +00:00
}
}
2021-01-31 12:55:13 +00:00
void Node : : replace_by ( Node * p_node , bool p_keep_groups ) {
2014-02-10 01:10:30 +00:00
ERR_FAIL_NULL ( p_node ) ;
ERR_FAIL_COND ( p_node - > data . parent ) ;
2017-03-05 15:44:50 +00:00
List < Node * > owned = data . owned ;
List < Node * > owned_by_owner ;
Node * owner = ( data . owner = = this ) ? p_node : data . owner ;
2014-02-10 01:10:30 +00:00
2021-01-31 12:55:13 +00:00
if ( p_keep_groups ) {
2016-11-02 23:19:32 +00:00
List < GroupInfo > groups ;
get_groups ( & groups ) ;
2021-07-24 13:46:25 +00:00
for ( const GroupInfo & E : groups ) {
2021-07-16 03:45:57 +00:00
p_node - > add_to_group ( E . name , E . persistent ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2016-06-09 14:24:12 +00:00
_replace_connections_target ( p_node ) ;
2014-02-10 01:10:30 +00:00
if ( data . owner ) {
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < get_child_count ( ) ; i + + ) {
2017-03-05 15:44:50 +00:00
find_owned_by ( data . owner , get_child ( i ) , & owned_by_owner ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
Node * parent = data . parent ;
int pos_in_parent = data . pos ;
if ( data . parent ) {
parent - > remove_child ( this ) ;
parent - > add_child ( p_node ) ;
2017-03-05 15:44:50 +00:00
parent - > move_child ( p_node , pos_in_parent ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
while ( get_child_count ( ) ) {
Node * child = get_child ( 0 ) ;
2014-02-10 01:10:30 +00:00
remove_child ( child ) ;
2018-03-07 00:21:46 +00:00
if ( ! child - > is_owned_by_parent ( ) ) {
// add the custom children to the p_node
p_node - > add_child ( child ) ;
}
2014-02-10 01:10:30 +00:00
}
p_node - > set_owner ( owner ) ;
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < owned . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
owned [ i ] - > set_owner ( p_node ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < owned_by_owner . size ( ) ; i + + ) {
2014-02-10 01:10:30 +00:00
owned_by_owner [ i ] - > set_owner ( owner ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
p_node - > set_filename ( get_filename ( ) ) ;
}
2017-03-05 15:44:50 +00:00
void Node : : _replace_connections_target ( Node * p_new_target ) {
2016-06-09 14:24:12 +00:00
List < Connection > cl ;
get_signals_connected_to_this ( & cl ) ;
2021-07-24 13:46:25 +00:00
for ( const Connection & c : cl ) {
2017-03-11 19:21:04 +00:00
if ( c . flags & CONNECT_PERSIST ) {
2020-02-21 22:26:13 +00:00
c . signal . get_object ( ) - > disconnect ( c . signal . get_name ( ) , Callable ( this , c . callable . get_method ( ) ) ) ;
2020-02-19 19:27:19 +00:00
bool valid = p_new_target - > has_method ( c . callable . get_method ( ) ) | | Ref < Script > ( p_new_target - > get_script ( ) ) . is_null ( ) | | Ref < Script > ( p_new_target - > get_script ( ) ) - > has_method ( c . callable . get_method ( ) ) ;
2021-05-23 14:42:47 +00:00
ERR_CONTINUE_MSG ( ! valid , vformat ( " Attempt to connect signal '%s.%s' to nonexistent method '%s.%s'. " , c . signal . get_object ( ) - > get_class ( ) , c . signal . get_name ( ) , c . callable . get_object ( ) - > get_class ( ) , c . callable . get_method ( ) ) ) ;
2020-02-21 22:26:13 +00:00
c . signal . get_object ( ) - > connect ( c . signal . get_name ( ) , Callable ( p_new_target , c . callable . get_method ( ) ) , c . binds , c . flags ) ;
2017-03-11 19:21:04 +00:00
}
2016-06-09 14:24:12 +00:00
}
}
2014-02-10 01:10:30 +00:00
Vector < Variant > Node : : make_binds ( VARIANT_ARG_DECLARE ) {
Vector < Variant > ret ;
2020-05-14 14:41:43 +00:00
if ( p_arg1 . get_type ( ) = = Variant : : NIL ) {
2014-02-10 01:10:30 +00:00
return ret ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
ret . push_back ( p_arg1 ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( p_arg2 . get_type ( ) = = Variant : : NIL ) {
2014-02-10 01:10:30 +00:00
return ret ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
ret . push_back ( p_arg2 ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( p_arg3 . get_type ( ) = = Variant : : NIL ) {
2014-02-10 01:10:30 +00:00
return ret ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
ret . push_back ( p_arg3 ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( p_arg4 . get_type ( ) = = Variant : : NIL ) {
2014-02-10 01:10:30 +00:00
return ret ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
ret . push_back ( p_arg4 ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( p_arg5 . get_type ( ) = = Variant : : NIL ) {
2014-02-10 01:10:30 +00:00
return ret ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
ret . push_back ( p_arg5 ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
return ret ;
}
2017-03-05 15:44:50 +00:00
bool Node : : has_node_and_resource ( const NodePath & p_path ) const {
2020-05-14 14:41:43 +00:00
if ( ! has_node ( p_path ) ) {
2014-02-10 01:10:30 +00:00
return false ;
2020-05-14 14:41:43 +00:00
}
2019-06-26 13:15:11 +00:00
RES res ;
Vector < StringName > leftover_path ;
Node * node = get_node_and_resource ( p_path , res , leftover_path , false ) ;
2014-02-10 01:10:30 +00:00
2019-07-10 18:03:04 +00:00
return node ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
Array Node : : _get_node_and_resource ( const NodePath & p_path ) {
2014-02-10 01:10:30 +00:00
RES res ;
2017-05-30 20:20:15 +00:00
Vector < StringName > leftover_path ;
2019-06-26 13:15:11 +00:00
Node * node = get_node_and_resource ( p_path , res , leftover_path , false ) ;
2014-02-10 01:10:30 +00:00
Array result ;
2020-05-14 14:41:43 +00:00
if ( node ) {
2014-02-10 01:10:30 +00:00
result . push_back ( node ) ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
result . push_back ( Variant ( ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( res . is_valid ( ) ) {
2014-02-10 01:10:30 +00:00
result . push_back ( res ) ;
2020-05-14 14:41:43 +00:00
} else {
2014-02-10 01:10:30 +00:00
result . push_back ( Variant ( ) ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-05-30 20:20:15 +00:00
result . push_back ( NodePath ( Vector < StringName > ( ) , leftover_path , false ) ) ;
2014-02-10 01:10:30 +00:00
return result ;
}
2017-05-30 20:20:15 +00:00
Node * Node : : get_node_and_resource ( const NodePath & p_path , RES & r_res , Vector < StringName > & r_leftover_subpath , bool p_last_is_property ) const {
2014-02-10 01:10:30 +00:00
Node * node = get_node ( p_path ) ;
r_res = RES ( ) ;
2017-05-30 20:20:15 +00:00
r_leftover_subpath = Vector < StringName > ( ) ;
2020-05-14 14:41:43 +00:00
if ( ! node ) {
2020-04-01 23:20:12 +00:00
return nullptr ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
if ( p_path . get_subname_count ( ) ) {
2017-05-30 20:20:15 +00:00
int j = 0 ;
// If not p_last_is_property, we shouldn't consider the last one as part of the resource
2019-06-26 13:15:11 +00:00
for ( ; j < p_path . get_subname_count ( ) - ( int ) p_last_is_property ; j + + ) {
2019-07-10 18:03:04 +00:00
Variant new_res_v = j = = 0 ? node - > get ( p_path . get_subname ( j ) ) : r_res - > get ( p_path . get_subname ( j ) ) ;
if ( new_res_v . get_type ( ) = = Variant : : NIL ) { // Found nothing on that path
2020-04-01 23:20:12 +00:00
return nullptr ;
2019-07-10 18:03:04 +00:00
}
RES new_res = new_res_v ;
2017-05-30 20:20:15 +00:00
2019-07-10 18:03:04 +00:00
if ( new_res . is_null ( ) ) { // No longer a resource, assume property
2017-05-30 20:20:15 +00:00
break ;
}
r_res = new_res ;
}
for ( ; j < p_path . get_subname_count ( ) ; j + + ) {
// Put the rest of the subpath in the leftover path
r_leftover_subpath . push_back ( p_path . get_subname ( j ) ) ;
2014-02-10 01:10:30 +00:00
}
}
return node ;
}
2014-11-06 00:20:42 +00:00
void Node : : _set_tree ( SceneTree * p_tree ) {
2020-04-01 23:20:12 +00:00
SceneTree * tree_changed_a = nullptr ;
SceneTree * tree_changed_b = nullptr ;
2014-02-10 01:10:30 +00:00
2017-01-14 11:26:56 +00:00
//ERR_FAIL_COND(p_scene && data.parent && !data.parent->data.scene); //nobug if both are null
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree ) {
_propagate_exit_tree ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
tree_changed_a = data . tree ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
data . tree = p_tree ;
2014-02-10 01:10:30 +00:00
2014-11-06 00:20:42 +00:00
if ( data . tree ) {
_propagate_enter_tree ( ) ;
2016-11-29 23:07:29 +00:00
if ( ! data . parent | | data . parent - > data . ready_notified ) { // No parent (root) or parent ready
_propagate_ready ( ) ; //reverse_notification(NOTIFICATION_READY);
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
tree_changed_b = data . tree ;
2014-02-10 01:10:30 +00:00
}
2020-05-14 14:41:43 +00:00
if ( tree_changed_a ) {
2014-02-10 01:10:30 +00:00
tree_changed_a - > tree_changed ( ) ;
2020-05-14 14:41:43 +00:00
}
if ( tree_changed_b ) {
2014-02-10 01:10:30 +00:00
tree_changed_b - > tree_changed ( ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
}
2018-10-03 14:13:34 +00:00
# ifdef DEBUG_ENABLED
2014-02-10 01:10:30 +00:00
static void _Node_debug_sn ( Object * p_obj ) {
2017-08-24 20:58:51 +00:00
Node * n = Object : : cast_to < Node > ( p_obj ) ;
2020-05-14 14:41:43 +00:00
if ( ! n ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2020-05-14 14:41:43 +00:00
if ( n - > is_inside_tree ( ) ) {
2014-02-10 01:10:30 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Node * p = n ;
while ( p - > get_parent ( ) ) {
p = p - > get_parent ( ) ;
2014-02-10 01:10:30 +00:00
}
String path ;
2020-05-14 14:41:43 +00:00
if ( p = = n ) {
2017-03-05 15:44:50 +00:00
path = n - > get_name ( ) ;
2020-05-14 14:41:43 +00:00
} else {
2017-03-05 15:44:50 +00:00
path = String ( p - > get_name ( ) ) + " / " + p - > get_path_to ( n ) ;
2020-05-14 14:41:43 +00:00
}
2018-08-24 07:35:07 +00:00
print_line ( itos ( p_obj - > get_instance_id ( ) ) + " - Stray Node: " + path + " (Type: " + n - > get_class ( ) + " ) " ) ;
2014-02-10 01:10:30 +00:00
}
2018-10-03 14:13:34 +00:00
# endif // DEBUG_ENABLED
2014-02-10 01:10:30 +00:00
void Node : : _print_stray_nodes ( ) {
print_stray_nodes ( ) ;
}
void Node : : print_stray_nodes ( ) {
# ifdef DEBUG_ENABLED
ObjectDB : : debug_objects ( _Node_debug_sn ) ;
# endif
}
void Node : : queue_delete ( ) {
2017-09-20 19:49:46 +00:00
if ( is_inside_tree ( ) ) {
get_tree ( ) - > queue_delete ( this ) ;
} else {
SceneTree : : get_singleton ( ) - > queue_delete ( this ) ;
}
2014-02-10 01:10:30 +00:00
}
2020-04-20 22:06:00 +00:00
TypedArray < Node > Node : : _get_children ( ) const {
TypedArray < Node > arr ;
2014-02-10 01:10:30 +00:00
int cc = get_child_count ( ) ;
arr . resize ( cc ) ;
2020-05-14 14:41:43 +00:00
for ( int i = 0 ; i < cc ; i + + ) {
2017-03-05 15:44:50 +00:00
arr [ i ] = get_child ( i ) ;
2020-05-14 14:41:43 +00:00
}
2014-02-10 01:10:30 +00:00
return arr ;
}
2017-03-05 15:44:50 +00:00
void Node : : set_import_path ( const NodePath & p_import_path ) {
2018-04-29 17:49:26 +00:00
# ifdef TOOLS_ENABLED
2017-03-05 15:44:50 +00:00
data . import_path = p_import_path ;
2018-04-29 17:49:26 +00:00
# endif
2014-06-19 05:23:03 +00:00
}
NodePath Node : : get_import_path ( ) const {
2018-04-29 17:49:26 +00:00
# ifdef TOOLS_ENABLED
2014-06-19 05:23:03 +00:00
return data . import_path ;
2018-04-29 17:49:26 +00:00
# else
return NodePath ( ) ;
2014-06-19 05:23:03 +00:00
# endif
2018-04-29 17:49:26 +00:00
}
2014-06-19 05:23:03 +00:00
2017-03-05 15:44:50 +00:00
static void _add_nodes_to_options ( const Node * p_base , const Node * p_node , List < String > * r_options ) {
2018-12-18 01:53:54 +00:00
# ifdef TOOLS_ENABLED
const String quote_style = EDITOR_DEF ( " text_editor/completion/use_single_quotes " , 0 ) ? " ' " : " \" " ;
# else
const String quote_style = " \" " ;
# endif
2020-05-14 14:41:43 +00:00
if ( p_node ! = p_base & & ! p_node - > get_owner ( ) ) {
2014-12-17 01:31:57 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2014-12-17 01:31:57 +00:00
String n = p_base - > get_path_to ( p_node ) ;
2018-12-18 01:53:54 +00:00
r_options - > push_back ( quote_style + n + quote_style ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < p_node - > get_child_count ( ) ; i + + ) {
_add_nodes_to_options ( p_base , p_node - > get_child ( i ) , r_options ) ;
2014-12-17 01:31:57 +00:00
}
}
2017-03-05 15:44:50 +00:00
void Node : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
String pf = p_function ;
if ( ( pf = = " has_node " | | pf = = " get_node " ) & & p_idx = = 0 ) {
_add_nodes_to_options ( this , this , r_options ) ;
2014-12-17 01:31:57 +00:00
}
2017-03-05 15:44:50 +00:00
Object : : get_argument_options ( p_function , p_idx , r_options ) ;
2014-12-17 01:31:57 +00:00
}
2014-02-10 01:10:30 +00:00
2015-06-22 03:03:19 +00:00
void Node : : clear_internal_tree_resource_paths ( ) {
clear_internal_resource_paths ( ) ;
2017-03-05 15:44:50 +00:00
for ( int i = 0 ; i < data . children . size ( ) ; i + + ) {
2015-06-22 03:03:19 +00:00
data . children [ i ] - > clear_internal_tree_resource_paths ( ) ;
}
}
2020-10-29 10:01:28 +00:00
TypedArray < String > Node : : get_configuration_warnings ( ) const {
2020-01-07 20:28:13 +00:00
if ( get_script_instance ( ) & & get_script_instance ( ) - > get_script ( ) . is_valid ( ) & &
2020-10-29 10:01:28 +00:00
get_script_instance ( ) - > get_script ( ) - > is_tool ( ) & & get_script_instance ( ) - > has_method ( " _get_configuration_warnings " ) ) {
return get_script_instance ( ) - > call ( " _get_configuration_warnings " ) ;
2018-08-14 19:52:40 +00:00
}
2020-10-29 10:01:28 +00:00
return Array ( ) ;
2016-05-17 21:27:15 +00:00
}
2020-10-29 10:01:28 +00:00
String Node : : get_configuration_warnings_as_string ( ) const {
TypedArray < String > warnings = get_configuration_warnings ( ) ;
String all_warnings = String ( ) ;
for ( int i = 0 ; i < warnings . size ( ) ; i + + ) {
if ( i > 0 ) {
all_warnings + = " \n \n " ;
}
2021-07-06 17:36:05 +00:00
// Format as a bullet point list to make multiple warnings easier to distinguish
// from each other.
all_warnings + = String : : utf8 ( " • " ) + String ( warnings [ i ] ) ;
2020-10-29 10:01:28 +00:00
}
return all_warnings ;
}
void Node : : update_configuration_warnings ( ) {
2016-05-17 21:27:15 +00:00
# ifdef TOOLS_ENABLED
2020-05-14 14:41:43 +00:00
if ( ! is_inside_tree ( ) ) {
2016-05-17 21:27:15 +00:00
return ;
2020-05-14 14:41:43 +00:00
}
2021-06-18 22:02:50 +00:00
if ( get_tree ( ) - > get_edited_scene_root ( ) & & ( get_tree ( ) - > get_edited_scene_root ( ) = = this | | get_tree ( ) - > get_edited_scene_root ( ) - > is_ancestor_of ( this ) ) ) {
2017-03-05 15:44:50 +00:00
get_tree ( ) - > emit_signal ( SceneStringNames : : get_singleton ( ) - > node_configuration_warning_changed , this ) ;
2016-05-17 21:27:15 +00:00
}
# endif
}
2016-06-21 01:57:07 +00:00
bool Node : : is_owned_by_parent ( ) const {
2016-06-21 11:40:56 +00:00
return data . parent_owned ;
2016-06-21 01:57:07 +00:00
}
2016-06-28 16:10:15 +00:00
void Node : : set_display_folded ( bool p_folded ) {
2017-03-05 15:44:50 +00:00
data . display_folded = p_folded ;
2016-06-28 16:10:15 +00:00
}
bool Node : : is_displayed_folded ( ) const {
return data . display_folded ;
}
2017-01-10 21:02:19 +00:00
void Node : : request_ready ( ) {
2017-03-05 15:44:50 +00:00
data . ready_first = true ;
2017-01-10 21:02:19 +00:00
}
2014-02-10 01:10:30 +00:00
void Node : : _bind_methods ( ) {
2021-02-17 16:44:49 +00:00
GLOBAL_DEF ( " editor/node_naming/name_num_separator " , 0 ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " editor/node_naming/name_num_separator " , PropertyInfo ( Variant : : INT , " editor/node_naming/name_num_separator " , PROPERTY_HINT_ENUM , " None,Space,Underscore,Dash " ) ) ;
GLOBAL_DEF ( " editor/node_naming/name_casing " , NAME_CASING_PASCAL_CASE ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " editor/node_naming/name_casing " , PropertyInfo ( Variant : : INT , " editor/node_naming/name_casing " , PROPERTY_HINT_ENUM , " PascalCase,camelCase,snake_case " ) ) ;
2016-10-07 18:25:29 +00:00
2020-05-12 06:12:08 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_sibling " , " sibling " , " legible_unique_name " ) , & Node : : add_sibling , DEFVAL ( false ) ) ;
2017-02-13 11:47:24 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_name " , " name " ) , & Node : : set_name ) ;
ClassDB : : bind_method ( D_METHOD ( " get_name " ) , & Node : : get_name ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_child " , " node " , " legible_unique_name " ) , & Node : : add_child , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_child " , " node " ) , & Node : : remove_child ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_child_count " ) , & Node : : get_child_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_children " ) , & Node : : _get_children ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_child " , " idx " ) , & Node : : get_child ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_node " , " path " ) , & Node : : has_node ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_node " , " path " ) , & Node : : get_node ) ;
2019-01-29 16:15:34 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_node_or_null " , " path " ) , & Node : : get_node_or_null ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_parent " ) , & Node : : get_parent ) ;
ClassDB : : bind_method ( D_METHOD ( " find_node " , " mask " , " recursive " , " owned " ) , & Node : : find_node , DEFVAL ( true ) , DEFVAL ( true ) ) ;
2018-09-15 16:22:06 +00:00
ClassDB : : bind_method ( D_METHOD ( " find_parent " , " mask " ) , & Node : : find_parent ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " has_node_and_resource " , " path " ) , & Node : : has_node_and_resource ) ;
ClassDB : : bind_method ( D_METHOD ( " get_node_and_resource " , " path " ) , & Node : : _get_node_and_resource ) ;
ClassDB : : bind_method ( D_METHOD ( " is_inside_tree " ) , & Node : : is_inside_tree ) ;
2021-06-18 22:02:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_ancestor_of " , " node " ) , & Node : : is_ancestor_of ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_greater_than " , " node " ) , & Node : : is_greater_than ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_path " ) , & Node : : get_path ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_path_to " , " node " ) , & Node : : get_path_to ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " add_to_group " , " group " , " persistent " ) , & Node : : add_to_group , DEFVAL ( false ) ) ;
ClassDB : : bind_method ( D_METHOD ( " remove_from_group " , " group " ) , & Node : : remove_from_group ) ;
ClassDB : : bind_method ( D_METHOD ( " is_in_group " , " group " ) , & Node : : is_in_group ) ;
2017-09-10 13:37:49 +00:00
ClassDB : : bind_method ( D_METHOD ( " move_child " , " child_node " , " to_position " ) , & Node : : move_child ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_groups " ) , & Node : : _get_groups ) ;
ClassDB : : bind_method ( D_METHOD ( " raise " ) , & Node : : raise ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_owner " , " owner " ) , & Node : : set_owner ) ;
ClassDB : : bind_method ( D_METHOD ( " get_owner " ) , & Node : : get_owner ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " remove_and_skip " ) , & Node : : remove_and_skip ) ;
ClassDB : : bind_method ( D_METHOD ( " get_index " ) , & Node : : get_index ) ;
ClassDB : : bind_method ( D_METHOD ( " print_tree " ) , & Node : : print_tree ) ;
2018-02-28 09:12:06 +00:00
ClassDB : : bind_method ( D_METHOD ( " print_tree_pretty " ) , & Node : : print_tree_pretty ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_filename " , " filename " ) , & Node : : set_filename ) ;
ClassDB : : bind_method ( D_METHOD ( " get_filename " ) , & Node : : get_filename ) ;
ClassDB : : bind_method ( D_METHOD ( " propagate_notification " , " what " ) , & Node : : propagate_notification ) ;
2017-08-19 13:17:06 +00:00
ClassDB : : bind_method ( D_METHOD ( " propagate_call " , " method " , " args " , " parent_first " ) , & Node : : propagate_call , DEFVAL ( Array ( ) ) , DEFVAL ( false ) ) ;
2017-09-30 14:19:07 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_physics_process " , " enable " ) , & Node : : set_physics_process ) ;
ClassDB : : bind_method ( D_METHOD ( " get_physics_process_delta_time " ) , & Node : : get_physics_process_delta_time ) ;
ClassDB : : bind_method ( D_METHOD ( " is_physics_processing " ) , & Node : : is_physics_processing ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_process_delta_time " ) , & Node : : get_process_delta_time ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process " , " enable " ) , & Node : : set_process ) ;
2018-07-02 05:30:40 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_process_priority " , " priority " ) , & Node : : set_process_priority ) ;
2019-11-16 21:07:02 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_process_priority " ) , & Node : : get_process_priority ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_processing " ) , & Node : : is_processing ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process_input " , " enable " ) , & Node : : set_process_input ) ;
ClassDB : : bind_method ( D_METHOD ( " is_processing_input " ) , & Node : : is_processing_input ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process_unhandled_input " , " enable " ) , & Node : : set_process_unhandled_input ) ;
ClassDB : : bind_method ( D_METHOD ( " is_processing_unhandled_input " ) , & Node : : is_processing_unhandled_input ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process_unhandled_key_input " , " enable " ) , & Node : : set_process_unhandled_key_input ) ;
ClassDB : : bind_method ( D_METHOD ( " is_processing_unhandled_key_input " ) , & Node : : is_processing_unhandled_key_input ) ;
2021-02-18 18:52:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_process_mode " , " mode " ) , & Node : : set_process_mode ) ;
ClassDB : : bind_method ( D_METHOD ( " get_process_mode " ) , & Node : : get_process_mode ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " can_process " ) , & Node : : can_process ) ;
ClassDB : : bind_method ( D_METHOD ( " print_stray_nodes " ) , & Node : : _print_stray_nodes ) ;
2019-04-11 17:35:23 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_display_folded " , " fold " ) , & Node : : set_display_folded ) ;
ClassDB : : bind_method ( D_METHOD ( " is_displayed_folded " ) , & Node : : is_displayed_folded ) ;
ClassDB : : bind_method ( D_METHOD ( " set_process_internal " , " enable " ) , & Node : : set_process_internal ) ;
ClassDB : : bind_method ( D_METHOD ( " is_processing_internal " ) , & Node : : is_processing_internal ) ;
2017-09-30 14:19:07 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_physics_process_internal " , " enable " ) , & Node : : set_physics_process_internal ) ;
ClassDB : : bind_method ( D_METHOD ( " is_physics_processing_internal " ) , & Node : : is_physics_processing_internal ) ;
2017-03-05 15:44:50 +00:00
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_tree " ) , & Node : : get_tree ) ;
2020-09-05 01:05:30 +00:00
ClassDB : : bind_method ( D_METHOD ( " create_tween " ) , & Node : : create_tween ) ;
2017-03-05 15:44:50 +00:00
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " duplicate " , " flags " ) , & Node : : duplicate , DEFVAL ( DUPLICATE_USE_INSTANCING | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS ) ) ;
2021-01-31 12:55:13 +00:00
ClassDB : : bind_method ( D_METHOD ( " replace_by " , " node " , " keep_groups " ) , & Node : : replace_by , DEFVAL ( false ) ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_scene_instance_load_placeholder " , " load_placeholder " ) , & Node : : set_scene_instance_load_placeholder ) ;
ClassDB : : bind_method ( D_METHOD ( " get_scene_instance_load_placeholder " ) , & Node : : get_scene_instance_load_placeholder ) ;
2017-08-09 11:19:41 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_viewport " ) , & Node : : get_viewport ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " queue_free " ) , & Node : : queue_delete ) ;
ClassDB : : bind_method ( D_METHOD ( " request_ready " ) , & Node : : request_ready ) ;
2017-07-03 13:44:45 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_network_master " , " id " , " recursive " ) , & Node : : set_network_master , DEFVAL ( true ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_network_master " ) , & Node : : get_network_master ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " is_network_master " ) , & Node : : is_network_master ) ;
2018-05-08 08:51:04 +00:00
ClassDB : : bind_method ( D_METHOD ( " get_multiplayer " ) , & Node : : get_multiplayer ) ;
ClassDB : : bind_method ( D_METHOD ( " get_custom_multiplayer " ) , & Node : : get_custom_multiplayer ) ;
ClassDB : : bind_method ( D_METHOD ( " set_custom_multiplayer " , " api " ) , & Node : : set_custom_multiplayer ) ;
2021-07-12 14:11:05 +00:00
ClassDB : : bind_method ( D_METHOD ( " rpc_config " , " method " , " rpc_mode " , " transfer_mode " , " channel " ) , & Node : : rpc_config , DEFVAL ( MultiplayerPeer : : TRANSFER_MODE_RELIABLE ) , DEFVAL ( 0 ) ) ;
2016-05-17 21:27:15 +00:00
2021-02-18 18:52:29 +00:00
ClassDB : : bind_method ( D_METHOD ( " set_editor_description " , " editor_description " ) , & Node : : set_editor_description ) ;
ClassDB : : bind_method ( D_METHOD ( " get_editor_description " ) , & Node : : get_editor_description ) ;
2019-08-15 12:50:26 +00:00
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _set_import_path " , " import_path " ) , & Node : : set_import_path ) ;
ClassDB : : bind_method ( D_METHOD ( " _get_import_path " ) , & Node : : get_import_path ) ;
2021-02-18 18:52:29 +00:00
2018-11-08 14:30:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : NODE_PATH , " _import_path " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL ) , " _set_import_path " , " _get_import_path " ) ;
2014-06-19 05:23:03 +00:00
2016-08-14 21:49:50 +00:00
{
MethodInfo mi ;
2016-08-19 19:48:08 +00:00
2020-02-20 21:58:05 +00:00
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " method " ) ) ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
mi . name = " rpc " ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " rpc " , & Node : : _rpc_bind , mi ) ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
mi . arguments . push_front ( PropertyInfo ( Variant : : INT , " peer_id " ) ) ;
2016-08-14 21:49:50 +00:00
2017-03-05 15:44:50 +00:00
mi . name = " rpc_id " ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " rpc_id " , & Node : : _rpc_id_bind , mi ) ;
2016-08-14 21:49:50 +00:00
}
2020-10-29 10:01:28 +00:00
ClassDB : : bind_method ( D_METHOD ( " update_configuration_warnings " ) , & Node : : update_configuration_warnings ) ;
2019-10-17 10:20:35 +00:00
2017-03-05 15:44:50 +00:00
BIND_CONSTANT ( NOTIFICATION_ENTER_TREE ) ;
BIND_CONSTANT ( NOTIFICATION_EXIT_TREE ) ;
BIND_CONSTANT ( NOTIFICATION_MOVED_IN_PARENT ) ;
BIND_CONSTANT ( NOTIFICATION_READY ) ;
2017-10-21 18:58:02 +00:00
BIND_CONSTANT ( NOTIFICATION_PAUSED ) ;
BIND_CONSTANT ( NOTIFICATION_UNPAUSED ) ;
2017-09-30 14:19:07 +00:00
BIND_CONSTANT ( NOTIFICATION_PHYSICS_PROCESS ) ;
2017-03-05 15:44:50 +00:00
BIND_CONSTANT ( NOTIFICATION_PROCESS ) ;
BIND_CONSTANT ( NOTIFICATION_PARENTED ) ;
BIND_CONSTANT ( NOTIFICATION_UNPARENTED ) ;
BIND_CONSTANT ( NOTIFICATION_INSTANCED ) ;
BIND_CONSTANT ( NOTIFICATION_DRAG_BEGIN ) ;
BIND_CONSTANT ( NOTIFICATION_DRAG_END ) ;
BIND_CONSTANT ( NOTIFICATION_PATH_CHANGED ) ;
BIND_CONSTANT ( NOTIFICATION_INTERNAL_PROCESS ) ;
2017-09-30 14:19:07 +00:00
BIND_CONSTANT ( NOTIFICATION_INTERNAL_PHYSICS_PROCESS ) ;
2020-08-12 11:31:32 +00:00
BIND_CONSTANT ( NOTIFICATION_POST_ENTER_TREE ) ;
2021-06-18 01:09:40 +00:00
BIND_CONSTANT ( NOTIFICATION_DISABLED ) ;
BIND_CONSTANT ( NOTIFICATION_ENABLED ) ;
2017-03-05 15:44:50 +00:00
New and improved IK system for Skeleton2D
This PR and commit adds a new IK system for 2D with the Skeleton2D node
that adds several new IK solvers, a way to control bones in a Skeleton2D
node similar to that in Skeleton3D. It also adds additional changes
and functionality.
This work was sponsored by GSoC 2020 and TwistedTwigleg.
Full list of changes:
* Adds a SkeletonModifier2D resource
* This resource is the base where all IK code is written and executed
* Has a function for clamping angles, since it is so commonly used
* Modifiers are unique when duplicated so it works with instancing
* Adds a SkeletonModifierStack2D resource
* This resource manages a series of SkeletonModification2Ds
* This is what the Skeleton2D directly interfaces with to make IK possible
* Adds SkeletonModifier2D resources for LookAt, CCDIK, FABRIK, Jiggle, and TwoBoneIK
* Each modification is in its own file
* There is also a SkeletonModifier2D resource that acts as a stack for using multiple stacks together
* Adds a PhysicalBone2D node
* Works similar to the PhysicalBone3D node, but uses a RigidBody2D node
* Changes to Skeleton2D listed below:
* Skeleton2D now holds a single SkeletonModificationStack2D for IK
* Skeleton2D now has a local_pose_override, which overrides the Bone2D position similar to how the overrides work in Skeleton3D
* Changes to Bone2D listed below:
* The default_length property has been changed to length. Length is the length of the bone to its child bone node
* New bone_angle property, which is the angle the bone has to its first child bone node
* Bone2D caches its transform when not modified by IK for IK interpolation purposes
* Bone2D draws its own editor gizmo, though this is stated to change in the future
* Changes to CanvasItemEditor listed below:
* Bone2D gizmo drawing code removed
* The 2D IK code is removed. Now Bone2D is the only bone system for 2D
* Transform2D now has a looking_at function for rotating to face a position
* Two new node notifications: NOTIFICATION_EDITOR_PRE_SAVE and NOTIFICATION_EDITOR_POST_SAVE
* These notifications only are called in the editor right before and after saving a scene
* Needed for not saving the IK position when executing IK in the editor
* Documentation for all the changes listed above.
2020-08-03 18:02:24 +00:00
BIND_CONSTANT ( NOTIFICATION_EDITOR_PRE_SAVE ) ;
BIND_CONSTANT ( NOTIFICATION_EDITOR_POST_SAVE ) ;
2019-04-04 13:34:03 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_MOUSE_ENTER ) ;
BIND_CONSTANT ( NOTIFICATION_WM_MOUSE_EXIT ) ;
2020-06-29 23:47:18 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_WINDOW_FOCUS_IN ) ;
BIND_CONSTANT ( NOTIFICATION_WM_WINDOW_FOCUS_OUT ) ;
2020-03-04 16:36:09 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_CLOSE_REQUEST ) ;
2019-04-04 13:34:03 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_GO_BACK_REQUEST ) ;
2020-03-06 17:00:16 +00:00
BIND_CONSTANT ( NOTIFICATION_WM_SIZE_CHANGED ) ;
2019-04-04 13:34:03 +00:00
BIND_CONSTANT ( NOTIFICATION_OS_MEMORY_WARNING ) ;
BIND_CONSTANT ( NOTIFICATION_TRANSLATION_CHANGED ) ;
BIND_CONSTANT ( NOTIFICATION_WM_ABOUT ) ;
BIND_CONSTANT ( NOTIFICATION_CRASH ) ;
BIND_CONSTANT ( NOTIFICATION_OS_IME_UPDATE ) ;
2020-06-29 23:47:18 +00:00
BIND_CONSTANT ( NOTIFICATION_APPLICATION_RESUMED ) ;
BIND_CONSTANT ( NOTIFICATION_APPLICATION_PAUSED ) ;
BIND_CONSTANT ( NOTIFICATION_APPLICATION_FOCUS_IN ) ;
BIND_CONSTANT ( NOTIFICATION_APPLICATION_FOCUS_OUT ) ;
2020-09-03 11:22:16 +00:00
BIND_CONSTANT ( NOTIFICATION_TEXT_SERVER_CHANGED ) ;
2019-04-04 13:34:03 +00:00
2021-02-18 18:52:29 +00:00
BIND_ENUM_CONSTANT ( PROCESS_MODE_INHERIT ) ;
BIND_ENUM_CONSTANT ( PROCESS_MODE_PAUSABLE ) ;
BIND_ENUM_CONSTANT ( PROCESS_MODE_WHEN_PAUSED ) ;
BIND_ENUM_CONSTANT ( PROCESS_MODE_ALWAYS ) ;
BIND_ENUM_CONSTANT ( PROCESS_MODE_DISABLED ) ;
2017-08-20 15:45:01 +00:00
BIND_ENUM_CONSTANT ( DUPLICATE_SIGNALS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_GROUPS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_SCRIPTS ) ;
BIND_ENUM_CONSTANT ( DUPLICATE_USE_INSTANCING ) ;
2017-03-05 15:44:50 +00:00
2018-01-20 21:57:59 +00:00
ADD_SIGNAL ( MethodInfo ( " ready " ) ) ;
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " renamed " ) ) ;
ADD_SIGNAL ( MethodInfo ( " tree_entered " ) ) ;
2018-01-12 11:28:39 +00:00
ADD_SIGNAL ( MethodInfo ( " tree_exiting " ) ) ;
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " tree_exited " ) ) ;
2014-02-10 01:10:30 +00:00
2021-06-17 23:10:18 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING_NAME , " name " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " set_name " , " get_name " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " filename " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NONE ) , " set_filename " , " get_filename " ) ;
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 " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " custom_multiplayer " , PROPERTY_HINT_RESOURCE_TYPE , " MultiplayerAPI " , PROPERTY_USAGE_NONE ) , " set_custom_multiplayer " , " get_custom_multiplayer " ) ;
2021-02-18 18:52:29 +00:00
ADD_GROUP ( " Process " , " process_ " ) ;
2021-05-22 02:30:58 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " process_mode " , PROPERTY_HINT_ENUM , " Inherit,Pausable,When Paused,Always,Disabled " ) , " set_process_mode " , " get_process_mode " ) ;
2019-11-16 21:07:02 +00:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " process_priority " ) , " set_process_priority " , " get_process_priority " ) ;
2017-03-05 15:44:50 +00:00
2021-02-18 18:52:29 +00:00
ADD_GROUP ( " Editor Description " , " editor_ " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " editor_description " , PROPERTY_HINT_MULTILINE_TEXT , " " , PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL ) , " set_editor_description " , " get_editor_description " ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 18:20:53 +00:00
BIND_VMETHOD ( MethodInfo ( " _process " , PropertyInfo ( Variant : : FLOAT , " delta " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( " _physics_process " , PropertyInfo ( Variant : : FLOAT , " delta " ) ) ) ;
2017-03-05 15:44:50 +00:00
BIND_VMETHOD ( MethodInfo ( " _enter_tree " ) ) ;
BIND_VMETHOD ( MethodInfo ( " _exit_tree " ) ) ;
BIND_VMETHOD ( MethodInfo ( " _ready " ) ) ;
2017-05-20 15:38:03 +00:00
BIND_VMETHOD ( MethodInfo ( " _input " , PropertyInfo ( Variant : : OBJECT , " event " , PROPERTY_HINT_RESOURCE_TYPE , " InputEvent " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( " _unhandled_input " , PropertyInfo ( Variant : : OBJECT , " event " , PROPERTY_HINT_RESOURCE_TYPE , " InputEvent " ) ) ) ;
BIND_VMETHOD ( MethodInfo ( " _unhandled_key_input " , PropertyInfo ( Variant : : OBJECT , " event " , PROPERTY_HINT_RESOURCE_TYPE , " InputEventKey " ) ) ) ;
2020-10-29 10:01:28 +00:00
BIND_VMETHOD ( MethodInfo ( PropertyInfo ( Variant : : ARRAY , " " , PROPERTY_HINT_ARRAY_TYPE , " String " ) , " _get_configuration_warnings " ) ) ;
2014-02-10 01:10:30 +00:00
}
2016-10-07 18:25:29 +00:00
String Node : : _get_name_num_separator ( ) {
2021-02-17 16:44:49 +00:00
switch ( ProjectSettings : : get_singleton ( ) - > get ( " editor/node_naming/name_num_separator " ) . operator int ( ) ) {
2020-05-10 11:00:47 +00:00
case 0 :
return " " ;
case 1 :
return " " ;
case 2 :
return " _ " ;
case 3 :
return " - " ;
2016-10-07 18:25:29 +00:00
}
return " " ;
}
2014-02-10 01:10:30 +00:00
Node : : Node ( ) {
2019-04-17 20:46:21 +00:00
orphan_node_count + + ;
2014-02-10 01:10:30 +00:00
}
Node : : ~ Node ( ) {
data . grouped . clear ( ) ;
data . owned . clear ( ) ;
data . children . clear ( ) ;
2016-03-08 23:00:52 +00:00
2014-02-10 01:10:30 +00:00
ERR_FAIL_COND ( data . parent ) ;
ERR_FAIL_COND ( data . children . size ( ) ) ;
2019-04-17 20:46:21 +00:00
orphan_node_count - - ;
2014-02-10 01:10:30 +00:00
}
2015-10-16 22:11:23 +00:00
////////////////////////////////