2014-02-10 02:10:30 +01:00
/**************************************************************************/
2017-09-01 16:07:55 +02:00
/* scene_tree.cpp */
2014-02-10 02:10:30 +01:00
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2017-06-27 03:58:03 +02:00
# include "scene_tree.h"
2014-02-10 02:10:30 +01:00
2020-11-07 23:33:38 +01:00
# include "core/config/project_settings.h"
2020-02-27 03:30:20 +01:00
# include "core/debugger/engine_debugger.h"
2020-04-28 15:19:37 +02:00
# include "core/input/input.h"
2021-06-11 14:51:48 +02:00
# include "core/io/dir_access.h"
2022-02-11 12:33:54 +01:00
# include "core/io/image_loader.h"
2018-09-11 18:13:45 +02:00
# include "core/io/marshalls.h"
# include "core/io/resource_loader.h"
2020-11-07 23:33:38 +01:00
# include "core/object/message_queue.h"
2023-04-10 18:45:53 +02:00
# include "core/object/worker_thread_pool.h"
2018-09-11 18:13:45 +02:00
# include "core/os/keyboard.h"
# include "core/os/os.h"
2020-11-07 23:33:38 +01:00
# include "core/string/print_string.h"
2014-02-10 02:10:30 +01:00
# include "node.h"
2020-09-05 03:05:30 +02:00
# include "scene/animation/tween.h"
2020-02-07 02:52:05 +01:00
# include "scene/debugger/scene_debugger.h"
2022-09-24 16:32:53 +02:00
# include "scene/gui/control.h"
2022-07-12 23:12:42 +02:00
# include "scene/main/multiplayer_api.h"
2022-02-12 02:46:22 +01:00
# include "scene/main/viewport.h"
2022-08-01 01:20:24 +02:00
# include "scene/resources/environment.h"
2020-09-03 13:22:16 +02:00
# include "scene/resources/font.h"
2023-07-11 22:29:09 +02:00
# include "scene/resources/image_texture.h"
2015-09-20 18:03:46 +02:00
# include "scene/resources/material.h"
# include "scene/resources/mesh.h"
2015-05-17 21:33:35 +02:00
# include "scene/resources/packed_scene.h"
2022-02-12 02:46:22 +01:00
# include "scene/resources/world_2d.h"
2020-03-03 14:36:29 +01:00
# include "servers/display_server.h"
2020-03-27 19:21:27 +01:00
# include "servers/navigation_server_3d.h"
# include "servers/physics_server_2d.h"
2024-02-22 15:14:29 +01:00
# ifndef _3D_DISABLED
2024-05-26 19:39:28 +02:00
# include "scene/3d/node_3d.h"
2021-08-13 18:42:45 +02:00
# include "scene/resources/3d/world_3d.h"
2020-03-27 19:21:27 +01:00
# include "servers/physics_server_3d.h"
2024-02-22 15:14:29 +01:00
# endif // _3D_DISABLED
2020-03-04 02:51:12 +01:00
# include "window.h"
2017-08-27 21:07:15 +02:00
# include <stdio.h>
2020-05-21 18:08:48 +02:00
# include <stdlib.h>
2017-08-27 21:07:15 +02:00
2016-08-07 02:39:50 +02:00
void SceneTreeTimer : : _bind_methods ( ) {
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_time_left " , " time " ) , & SceneTreeTimer : : set_time_left ) ;
ClassDB : : bind_method ( D_METHOD ( " get_time_left " ) , & SceneTreeTimer : : get_time_left ) ;
2016-08-07 02:39:50 +02:00
2021-12-03 01:09:19 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " time_left " , PROPERTY_HINT_NONE , " suffix:s " ) , " set_time_left " , " get_time_left " ) ;
2018-01-11 23:35:12 +01:00
2016-08-07 02:39:50 +02:00
ADD_SIGNAL ( MethodInfo ( " timeout " ) ) ;
}
2021-05-21 07:23:35 +02:00
void SceneTreeTimer : : set_time_left ( double p_time ) {
2016-08-07 02:39:50 +02:00
time_left = p_time ;
}
2021-05-21 07:23:35 +02:00
double SceneTreeTimer : : get_time_left ( ) const {
2023-02-20 05:09:38 +01:00
return MAX ( time_left , 0.0 ) ;
2016-08-07 02:39:50 +02:00
}
2021-02-19 13:57:41 +01:00
void SceneTreeTimer : : set_process_always ( bool p_process_always ) {
process_always = p_process_always ;
2017-02-14 00:34:33 +01:00
}
2021-02-19 13:57:41 +01:00
bool SceneTreeTimer : : is_process_always ( ) {
return process_always ;
2017-02-14 00:34:33 +01:00
}
2016-08-07 02:39:50 +02:00
2022-07-15 08:21:51 +02:00
void SceneTreeTimer : : set_process_in_physics ( bool p_process_in_physics ) {
process_in_physics = p_process_in_physics ;
}
bool SceneTreeTimer : : is_process_in_physics ( ) {
return process_in_physics ;
}
2021-02-27 00:37:20 +01:00
void SceneTreeTimer : : set_ignore_time_scale ( bool p_ignore ) {
ignore_time_scale = p_ignore ;
}
bool SceneTreeTimer : : is_ignore_time_scale ( ) {
return ignore_time_scale ;
}
2019-10-19 18:45:17 +02:00
void SceneTreeTimer : : release_connections ( ) {
2022-09-29 11:53:28 +02:00
List < Connection > signal_connections ;
get_all_signal_connections ( & signal_connections ) ;
2019-10-19 18:45:17 +02:00
2022-09-29 11:53:28 +02:00
for ( const Connection & connection : signal_connections ) {
2020-02-21 23:26:13 +01:00
disconnect ( connection . signal . get_name ( ) , connection . callable ) ;
2019-10-19 18:45:17 +02:00
}
}
2021-02-09 18:24:36 +01:00
SceneTreeTimer : : SceneTreeTimer ( ) { }
2016-08-07 02:39:50 +02:00
2024-05-26 19:39:28 +02:00
# ifndef _3D_DISABLED
// This should be called once per physics tick, to make sure the transform previous and current
// is kept up to date on the few Node3Ds that are using client side physics interpolation.
void SceneTree : : ClientPhysicsInterpolation : : physics_process ( ) {
for ( SelfList < Node3D > * E = _node_3d_list . first ( ) ; E ; ) {
Node3D * node_3d = E - > self ( ) ;
SelfList < Node3D > * current = E ;
// Get the next element here BEFORE we potentially delete one.
E = E - > next ( ) ;
// This will return false if the Node3D has timed out ..
// i.e. if get_global_transform_interpolated() has not been called
// for a few seconds, we can delete from the list to keep processing
// to a minimum.
if ( ! node_3d - > update_client_physics_interpolation_data ( ) ) {
_node_3d_list . remove ( current ) ;
}
}
}
# endif
2014-11-06 01:20:42 +01:00
void SceneTree : : tree_changed ( ) {
2014-02-10 02:10:30 +01:00
emit_signal ( tree_changed_name ) ;
}
2017-10-19 02:30:27 +02:00
void SceneTree : : node_added ( Node * p_node ) {
emit_signal ( node_added_name , p_node ) ;
}
2014-11-06 01:20:42 +01:00
void SceneTree : : node_removed ( Node * p_node ) {
2023-04-10 18:45:53 +02:00
// Nodes can only be removed from the main thread.
2015-05-17 21:33:35 +02:00
if ( current_scene = = p_node ) {
2020-04-02 01:20:12 +02:00
current_scene = nullptr ;
2015-05-17 21:33:35 +02:00
}
2014-02-10 02:10:30 +01:00
emit_signal ( node_removed_name , p_node ) ;
2023-04-10 18:45:53 +02:00
if ( nodes_removed_on_group_call_lock ) {
nodes_removed_on_group_call . insert ( p_node ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2019-05-24 15:27:22 +02:00
void SceneTree : : node_renamed ( Node * p_node ) {
emit_signal ( node_renamed_name , p_node ) ;
}
2016-06-08 03:08:12 +02:00
SceneTree : : Group * SceneTree : : add_to_group ( const StringName & p_group , Node * p_node ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2022-05-13 15:04:37 +02:00
HashMap < StringName , Group > : : Iterator E = group_map . find ( p_group ) ;
2014-02-10 02:10:30 +01:00
if ( ! E ) {
E = group_map . insert ( p_group , Group ( ) ) ;
}
2022-05-13 15:04:37 +02:00
ERR_FAIL_COND_V_MSG ( E - > value . nodes . has ( p_node ) , & E - > value , " Already in group: " + p_group + " . " ) ;
E - > value . nodes . push_back ( p_node ) ;
E - > value . changed = true ;
return & E - > value ;
2014-02-10 02:10:30 +01:00
}
2014-11-06 01:20:42 +01:00
void SceneTree : : remove_from_group ( const StringName & p_group , Node * p_node ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2022-05-13 15:04:37 +02:00
HashMap < StringName , Group > : : Iterator E = group_map . find ( p_group ) ;
2014-02-10 02:10:30 +01:00
ERR_FAIL_COND ( ! E ) ;
2022-05-13 15:04:37 +02:00
E - > value . nodes . erase ( p_node ) ;
if ( E - > value . nodes . is_empty ( ) ) {
group_map . remove ( E ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2018-07-02 07:30:40 +02:00
void SceneTree : : make_group_changed ( const StringName & p_group ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2022-05-13 15:04:37 +02:00
HashMap < StringName , Group > : : Iterator E = group_map . find ( p_group ) ;
2020-05-14 16:41:43 +02:00
if ( E ) {
2022-05-13 15:04:37 +02:00
E - > value . changed = true ;
2020-05-14 16:41:43 +02:00
}
2018-07-02 07:30:40 +02:00
}
2017-10-30 19:43:19 +01:00
void SceneTree : : flush_transform_notifications ( ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2014-02-10 02:10:30 +01:00
SelfList < Node > * n = xform_change_list . first ( ) ;
while ( n ) {
Node * node = n - > self ( ) ;
SelfList < Node > * nx = n - > next ( ) ;
xform_change_list . remove ( n ) ;
n = nx ;
node - > notification ( NOTIFICATION_TRANSFORM_CHANGED ) ;
}
}
2014-11-06 01:20:42 +01:00
void SceneTree : : _flush_ugc ( ) {
2014-02-10 02:10:30 +01:00
ugc_locked = true ;
while ( unique_group_calls . size ( ) ) {
2022-05-13 15:04:37 +02:00
HashMap < UGCall , Vector < Variant > , UGCall > : : Iterator E = unique_group_calls . begin ( ) ;
2014-02-10 02:10:30 +01:00
2022-05-13 15:04:37 +02:00
const Variant * * argptrs = ( const Variant * * ) alloca ( E - > value . size ( ) * sizeof ( Variant * ) ) ;
2022-03-09 14:58:40 +01:00
2022-05-13 15:04:37 +02:00
for ( int i = 0 ; i < E - > value . size ( ) ; i + + ) {
argptrs [ i ] = & E - > value [ i ] ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-05-13 15:04:37 +02:00
call_group_flagsp ( GROUP_CALL_DEFAULT , E - > key . group , E - > key . call , argptrs , E - > value . size ( ) ) ;
2014-02-10 02:10:30 +01:00
2022-05-13 15:04:37 +02:00
unique_group_calls . remove ( E ) ;
2014-02-10 02:10:30 +01:00
}
ugc_locked = false ;
}
2023-04-10 18:45:53 +02:00
void SceneTree : : _update_group_order ( Group & g ) {
2020-05-14 16:41:43 +02:00
if ( ! g . changed ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2020-12-15 13:04:21 +01:00
if ( g . nodes . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
Node * * gr_nodes = g . nodes . ptrw ( ) ;
int gr_node_count = g . nodes . size ( ) ;
2016-06-08 03:08:12 +02:00
2023-04-10 18:45:53 +02:00
SortArray < Node * , Node : : Comparator > node_sort ;
node_sort . sort ( gr_nodes , gr_node_count ) ;
2016-06-08 03:08:12 +02:00
g . changed = false ;
2014-02-10 02:10:30 +01:00
}
2022-03-09 14:58:40 +01:00
void SceneTree : : call_group_flagsp ( uint32_t p_call_flags , const StringName & p_group , const StringName & p_function , const Variant * * p_args , int p_argcount ) {
2023-04-10 18:45:53 +02:00
Vector < Node * > nodes_copy ;
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
{
_THREAD_SAFE_METHOD_
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
HashMap < StringName , Group > : : Iterator E = group_map . find ( p_group ) ;
if ( ! E ) {
return ;
}
Group & g = E - > value ;
if ( g . nodes . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
if ( p_call_flags & GROUP_CALL_UNIQUE & & p_call_flags & GROUP_CALL_DEFERRED ) {
ERR_FAIL_COND ( ugc_locked ) ;
UGCall ug ;
ug . call = p_function ;
ug . group = p_group ;
if ( unique_group_calls . has ( ug ) ) {
return ;
}
Vector < Variant > args ;
for ( int i = 0 ; i < p_argcount ; i + + ) {
args . push_back ( * p_args [ i ] ) ;
}
unique_group_calls [ ug ] = args ;
return ;
2014-02-10 02:10:30 +01:00
}
2023-04-10 18:45:53 +02:00
_update_group_order ( g ) ;
nodes_copy = g . nodes ;
2014-02-10 02:10:30 +01:00
}
2022-09-29 11:53:28 +02:00
Node * * gr_nodes = nodes_copy . ptrw ( ) ;
int gr_node_count = nodes_copy . size ( ) ;
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
{
_THREAD_SAFE_METHOD_
nodes_removed_on_group_call_lock + + ;
}
2014-02-10 02:10:30 +01:00
if ( p_call_flags & GROUP_CALL_REVERSE ) {
2022-09-29 11:53:28 +02:00
for ( int i = gr_node_count - 1 ; i > = 0 ; i - - ) {
2023-04-10 18:45:53 +02:00
if ( nodes_removed_on_group_call_lock & & nodes_removed_on_group_call . has ( gr_nodes [ i ] ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2024-09-20 17:20:03 +02:00
Node * node = gr_nodes [ i ] ;
2021-08-12 23:40:13 +02:00
if ( ! ( p_call_flags & GROUP_CALL_DEFERRED ) ) {
2022-03-09 14:58:40 +01:00
Callable : : CallError ce ;
2024-09-20 17:20:03 +02:00
node - > callp ( p_function , p_args , p_argcount , ce ) ;
if ( unlikely ( ce . error ! = Callable : : CallError : : CALL_OK & & ce . error ! = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ) ) {
ERR_PRINT ( vformat ( " Error calling group method on node \" %s \" : %s. " , node - > get_name ( ) , Variant : : get_callable_error_text ( Callable ( node , p_function ) , p_args , p_argcount , ce ) ) ) ;
}
2020-05-14 16:41:43 +02:00
} else {
2024-09-20 17:20:03 +02:00
MessageQueue : : get_singleton ( ) - > push_callp ( node , p_function , p_args , p_argcount ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
} else {
2022-09-29 11:53:28 +02:00
for ( int i = 0 ; i < gr_node_count ; i + + ) {
2023-04-10 18:45:53 +02:00
if ( nodes_removed_on_group_call_lock & & nodes_removed_on_group_call . has ( gr_nodes [ i ] ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2024-09-20 17:20:03 +02:00
Node * node = gr_nodes [ i ] ;
2021-08-12 23:40:13 +02:00
if ( ! ( p_call_flags & GROUP_CALL_DEFERRED ) ) {
2022-03-09 14:58:40 +01:00
Callable : : CallError ce ;
2024-09-20 17:20:03 +02:00
node - > callp ( p_function , p_args , p_argcount , ce ) ;
if ( unlikely ( ce . error ! = Callable : : CallError : : CALL_OK & & ce . error ! = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ) ) {
ERR_PRINT ( vformat ( " Error calling group method on node \" %s \" : %s. " , node - > get_name ( ) , Variant : : get_callable_error_text ( Callable ( node , p_function ) , p_args , p_argcount , ce ) ) ) ;
}
2020-05-14 16:41:43 +02:00
} else {
2024-09-20 17:20:03 +02:00
MessageQueue : : get_singleton ( ) - > push_callp ( node , p_function , p_args , p_argcount ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-04-10 18:45:53 +02:00
{
_THREAD_SAFE_METHOD_
nodes_removed_on_group_call_lock - - ;
if ( nodes_removed_on_group_call_lock = = 0 ) {
nodes_removed_on_group_call . clear ( ) ;
}
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2017-01-14 14:03:53 +01:00
void SceneTree : : notify_group_flags ( uint32_t p_call_flags , const StringName & p_group , int p_notification ) {
2023-04-10 18:45:53 +02:00
Vector < Node * > nodes_copy ;
{
_THREAD_SAFE_METHOD_
HashMap < StringName , Group > : : Iterator E = group_map . find ( p_group ) ;
if ( ! E ) {
return ;
}
Group & g = E - > value ;
if ( g . nodes . is_empty ( ) ) {
return ;
}
_update_group_order ( g ) ;
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
nodes_copy = g . nodes ;
}
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
Node * * gr_nodes = nodes_copy . ptrw ( ) ;
int gr_node_count = nodes_copy . size ( ) ;
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
{
_THREAD_SAFE_METHOD_
nodes_removed_on_group_call_lock + + ;
}
2014-02-10 02:10:30 +01:00
if ( p_call_flags & GROUP_CALL_REVERSE ) {
2022-09-29 11:53:28 +02:00
for ( int i = gr_node_count - 1 ; i > = 0 ; i - - ) {
2023-04-10 18:45:53 +02:00
if ( nodes_removed_on_group_call . has ( gr_nodes [ i ] ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-08-12 23:40:13 +02:00
if ( ! ( p_call_flags & GROUP_CALL_DEFERRED ) ) {
2023-06-24 03:07:22 +02:00
gr_nodes [ i ] - > notification ( p_notification , true ) ;
2020-05-14 16:41:43 +02:00
} else {
2022-09-29 11:53:28 +02:00
MessageQueue : : get_singleton ( ) - > push_notification ( gr_nodes [ i ] , p_notification ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
} else {
2022-09-29 11:53:28 +02:00
for ( int i = 0 ; i < gr_node_count ; i + + ) {
2023-04-10 18:45:53 +02:00
if ( nodes_removed_on_group_call . has ( gr_nodes [ i ] ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-08-12 23:40:13 +02:00
if ( ! ( p_call_flags & GROUP_CALL_DEFERRED ) ) {
2022-09-29 11:53:28 +02:00
gr_nodes [ i ] - > notification ( p_notification ) ;
2020-05-14 16:41:43 +02:00
} else {
2022-09-29 11:53:28 +02:00
MessageQueue : : get_singleton ( ) - > push_notification ( gr_nodes [ i ] , p_notification ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-04-10 18:45:53 +02:00
{
_THREAD_SAFE_METHOD_
nodes_removed_on_group_call_lock - - ;
if ( nodes_removed_on_group_call_lock = = 0 ) {
nodes_removed_on_group_call . clear ( ) ;
}
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2017-01-14 14:03:53 +01:00
void SceneTree : : set_group_flags ( uint32_t p_call_flags , const StringName & p_group , const String & p_name , const Variant & p_value ) {
2023-04-10 18:45:53 +02:00
Vector < Node * > nodes_copy ;
{
_THREAD_SAFE_METHOD_
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
HashMap < StringName , Group > : : Iterator E = group_map . find ( p_group ) ;
if ( ! E ) {
return ;
}
Group & g = E - > value ;
if ( g . nodes . is_empty ( ) ) {
return ;
}
_update_group_order ( g ) ;
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
nodes_copy = g . nodes ;
}
2022-09-29 11:53:28 +02:00
Node * * gr_nodes = nodes_copy . ptrw ( ) ;
int gr_node_count = nodes_copy . size ( ) ;
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
{
_THREAD_SAFE_METHOD_
nodes_removed_on_group_call_lock + + ;
}
2014-02-10 02:10:30 +01:00
if ( p_call_flags & GROUP_CALL_REVERSE ) {
2022-09-29 11:53:28 +02:00
for ( int i = gr_node_count - 1 ; i > = 0 ; i - - ) {
2023-04-10 18:45:53 +02:00
if ( nodes_removed_on_group_call . has ( gr_nodes [ i ] ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-08-12 23:40:13 +02:00
if ( ! ( p_call_flags & GROUP_CALL_DEFERRED ) ) {
2022-09-29 11:53:28 +02:00
gr_nodes [ i ] - > set ( p_name , p_value ) ;
2020-05-14 16:41:43 +02:00
} else {
2022-09-29 11:53:28 +02:00
MessageQueue : : get_singleton ( ) - > push_set ( gr_nodes [ i ] , p_name , p_value ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
} else {
2022-09-29 11:53:28 +02:00
for ( int i = 0 ; i < gr_node_count ; i + + ) {
2023-04-10 18:45:53 +02:00
if ( nodes_removed_on_group_call . has ( gr_nodes [ i ] ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-08-12 23:40:13 +02:00
if ( ! ( p_call_flags & GROUP_CALL_DEFERRED ) ) {
2022-09-29 11:53:28 +02:00
gr_nodes [ i ] - > set ( p_name , p_value ) ;
2020-05-14 16:41:43 +02:00
} else {
2022-09-29 11:53:28 +02:00
MessageQueue : : get_singleton ( ) - > push_set ( gr_nodes [ i ] , p_name , p_value ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2023-04-10 18:45:53 +02:00
{
_THREAD_SAFE_METHOD_
nodes_removed_on_group_call_lock - - ;
if ( nodes_removed_on_group_call_lock = = 0 ) {
nodes_removed_on_group_call . clear ( ) ;
}
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2017-01-14 14:03:53 +01:00
void SceneTree : : notify_group ( const StringName & p_group , int p_notification ) {
2022-06-19 16:04:53 +02:00
notify_group_flags ( GROUP_CALL_DEFAULT , p_group , p_notification ) ;
2017-01-14 14:03:53 +01:00
}
void SceneTree : : set_group ( const StringName & p_group , const String & p_name , const Variant & p_value ) {
2021-08-12 23:40:13 +02:00
set_group_flags ( GROUP_CALL_DEFAULT , p_group , p_name , p_value ) ;
2017-01-14 14:03:53 +01:00
}
2020-12-22 10:50:29 +01:00
void SceneTree : : initialize ( ) {
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL ( root ) ;
2020-12-22 10:50:29 +01:00
MainLoop : : initialize ( ) ;
2023-01-28 13:25:03 +01:00
root - > _set_tree ( this ) ;
2014-02-10 02:10:30 +01:00
}
2024-02-17 00:57:32 +01:00
void SceneTree : : set_physics_interpolation_enabled ( bool p_enabled ) {
// We never want interpolation in the editor.
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
p_enabled = false ;
}
if ( p_enabled = = _physics_interpolation_enabled ) {
return ;
}
_physics_interpolation_enabled = p_enabled ;
RenderingServer : : get_singleton ( ) - > set_physics_interpolation_enabled ( p_enabled ) ;
}
bool SceneTree : : is_physics_interpolation_enabled ( ) const {
return _physics_interpolation_enabled ;
}
2024-05-26 19:39:28 +02:00
# ifndef _3D_DISABLED
void SceneTree : : client_physics_interpolation_add_node_3d ( SelfList < Node3D > * p_elem ) {
// This ensures that _update_physics_interpolation_data() will be called at least once every
// physics tick, to ensure the previous and current transforms are kept up to date.
_client_physics_interpolation . _node_3d_list . add ( p_elem ) ;
}
void SceneTree : : client_physics_interpolation_remove_node_3d ( SelfList < Node3D > * p_elem ) {
_client_physics_interpolation . _node_3d_list . remove ( p_elem ) ;
}
# endif
2024-02-17 00:57:32 +01:00
void SceneTree : : iteration_prepare ( ) {
if ( _physics_interpolation_enabled ) {
2024-05-26 19:39:28 +02:00
// Make sure any pending transforms from the last tick / frame
// are flushed before pumping the interpolation prev and currents.
flush_transform_notifications ( ) ;
2024-02-17 00:57:32 +01:00
RenderingServer : : get_singleton ( ) - > tick ( ) ;
2024-05-26 19:39:28 +02:00
# ifndef _3D_DISABLED
// Any objects performing client physics interpolation
// should be given an opportunity to keep their previous transforms
// up to date before each new physics tick.
_client_physics_interpolation . physics_process ( ) ;
# endif
2024-02-17 00:57:32 +01:00
}
}
2021-05-21 07:23:35 +02:00
bool SceneTree : : physics_process ( double p_time ) {
2014-02-10 02:10:30 +01:00
current_frame + + ;
2017-10-30 19:43:19 +01:00
flush_transform_notifications ( ) ;
2014-02-10 02:10:30 +01:00
2023-06-18 20:44:22 +02:00
if ( MainLoop : : physics_process ( p_time ) ) {
_quit = true ;
}
2017-09-30 16:19:07 +02:00
physics_process_time = p_time ;
2014-09-15 16:33:30 +02:00
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " physics_frame " ) ) ;
2014-09-15 16:33:30 +02:00
2021-08-12 23:40:13 +02:00
call_group ( SNAME ( " _picking_viewports " ) , SNAME ( " _process_picking " ) ) ;
2023-04-10 18:45:53 +02:00
_process ( true ) ;
2014-02-10 02:10:30 +01:00
_flush_ugc ( ) ;
2017-08-08 03:18:12 +02:00
MessageQueue : : get_singleton ( ) - > flush ( ) ; //small little hack
2020-09-05 03:05:30 +02:00
2022-07-15 08:21:51 +02:00
process_timers ( p_time , true ) ; //go through timers
2020-09-05 03:05:30 +02:00
process_tweens ( p_time , true ) ;
2017-10-30 19:43:19 +01:00
flush_transform_notifications ( ) ;
2014-02-10 02:10:30 +01:00
_flush_delete_queue ( ) ;
2016-10-27 16:50:26 +02:00
_call_idle_callbacks ( ) ;
2014-02-10 02:10:30 +01:00
return _quit ;
}
2024-05-26 19:39:28 +02:00
void SceneTree : : iteration_end ( ) {
// When physics interpolation is active, we want all pending transforms
// to be flushed to the RenderingServer before finishing a physics tick.
if ( _physics_interpolation_enabled ) {
flush_transform_notifications ( ) ;
}
}
2021-05-21 07:23:35 +02:00
bool SceneTree : : process ( double p_time ) {
2023-06-18 20:44:22 +02:00
if ( MainLoop : : process ( p_time ) ) {
_quit = true ;
}
2014-02-10 02:10:30 +01:00
2020-12-22 10:50:29 +01:00
process_time = p_time ;
2014-02-10 02:10:30 +01:00
2018-06-02 14:32:30 +02:00
if ( multiplayer_poll ) {
multiplayer - > poll ( ) ;
2022-05-08 10:09:19 +02:00
for ( KeyValue < NodePath , Ref < MultiplayerAPI > > & E : custom_multiplayers ) {
E . value - > poll ( ) ;
2022-02-05 01:43:47 +01:00
}
2018-06-02 14:32:30 +02:00
}
2016-08-14 23:49:50 +02:00
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " process_frame " ) ) ;
2014-09-15 16:33:30 +02:00
2017-08-08 03:18:12 +02:00
MessageQueue : : get_singleton ( ) - > flush ( ) ; //small little hack
2017-10-30 19:43:19 +01:00
flush_transform_notifications ( ) ;
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
_process ( false ) ;
2014-02-10 02:10:30 +01:00
_flush_ugc ( ) ;
2017-08-08 03:18:12 +02:00
MessageQueue : : get_singleton ( ) - > flush ( ) ; //small little hack
2017-10-30 19:43:19 +01:00
flush_transform_notifications ( ) ; //transforms after world update, to avoid unnecessary enter/exit notifications
2014-02-10 02:10:30 +01:00
_flush_delete_queue ( ) ;
2023-11-21 18:32:49 +01:00
if ( unlikely ( pending_new_scene ) ) {
_flush_scene_change ( ) ;
}
2022-07-15 08:21:51 +02:00
process_timers ( p_time , false ) ; //go through timers
2016-08-07 02:39:50 +02:00
2020-09-05 03:05:30 +02:00
process_tweens ( p_time , false ) ;
2019-07-29 12:33:38 +02:00
flush_transform_notifications ( ) ; //additional transforms after timers update
2016-10-27 16:50:26 +02:00
_call_idle_callbacks ( ) ;
2017-05-29 02:46:48 +02:00
# ifdef TOOLS_ENABLED
2021-07-04 03:43:23 +02:00
# ifndef _3D_DISABLED
2017-08-19 01:02:56 +02:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2017-05-29 02:46:48 +02:00
//simple hack to reload fallback environment if it changed from editor
2022-10-18 16:43:37 +02:00
String env_path = GLOBAL_GET ( SNAME ( " rendering/environment/defaults/default_environment " ) ) ;
2017-05-29 02:46:48 +02:00
env_path = env_path . strip_edges ( ) ; //user may have added a space or two
String cpath ;
2020-04-18 11:00:51 +02:00
Ref < Environment > fallback = get_root ( ) - > get_world_3d ( ) - > get_fallback_environment ( ) ;
2017-05-29 02:46:48 +02:00
if ( fallback . is_valid ( ) ) {
cpath = fallback - > get_path ( ) ;
}
if ( cpath ! = env_path ) {
2021-12-09 10:42:46 +01:00
if ( ! env_path . is_empty ( ) ) {
2017-05-29 02:46:48 +02:00
fallback = ResourceLoader : : load ( env_path ) ;
2017-08-31 13:55:20 +02:00
if ( fallback . is_null ( ) ) {
//could not load fallback, set as empty
2021-02-17 17:44:49 +01:00
ProjectSettings : : get_singleton ( ) - > set ( " rendering/environment/defaults/default_environment " , " " ) ;
2017-08-31 13:55:20 +02:00
}
2017-05-29 02:46:48 +02:00
} else {
fallback . unref ( ) ;
}
2020-04-18 11:00:51 +02:00
get_root ( ) - > get_world_3d ( ) - > set_fallback_environment ( fallback ) ;
2017-05-29 02:46:48 +02:00
}
}
2021-07-04 03:43:23 +02:00
# endif // _3D_DISABLED
# endif // TOOLS_ENABLED
2017-05-29 02:46:48 +02:00
2024-05-26 19:39:28 +02:00
if ( _physics_interpolation_enabled ) {
RenderingServer : : get_singleton ( ) - > pre_draw ( true ) ;
}
2014-02-10 02:10:30 +01:00
return _quit ;
}
2022-09-22 15:54:15 +02:00
void SceneTree : : process_timers ( double p_delta , bool p_physics_frame ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2022-07-15 08:21:51 +02:00
List < Ref < SceneTreeTimer > > : : Element * L = timers . back ( ) ; //last element
for ( List < Ref < SceneTreeTimer > > : : Element * E = timers . front ( ) ; E ; ) {
List < Ref < SceneTreeTimer > > : : Element * N = E - > next ( ) ;
if ( ( paused & & ! E - > get ( ) - > is_process_always ( ) ) | | ( E - > get ( ) - > is_process_in_physics ( ) ! = p_physics_frame ) ) {
if ( E = = L ) {
break ; //break on last, so if new timers were added during list traversal, ignore them.
}
E = N ;
continue ;
}
double time_left = E - > get ( ) - > get_time_left ( ) ;
if ( E - > get ( ) - > is_ignore_time_scale ( ) ) {
time_left - = Engine : : get_singleton ( ) - > get_process_step ( ) ;
} else {
time_left - = p_delta ;
}
E - > get ( ) - > set_time_left ( time_left ) ;
if ( time_left < = 0 ) {
E - > get ( ) - > emit_signal ( SNAME ( " timeout " ) ) ;
timers . erase ( E ) ;
}
if ( E = = L ) {
break ; //break on last, so if new timers were added during list traversal, ignore them.
}
E = N ;
}
}
2022-09-22 15:54:15 +02:00
void SceneTree : : process_tweens ( double p_delta , bool p_physics ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2020-09-05 03:05:30 +02:00
// This methods works similarly to how SceneTreeTimers are handled.
List < Ref < Tween > > : : Element * L = tweens . back ( ) ;
for ( List < Ref < Tween > > : : Element * E = tweens . front ( ) ; E ; ) {
List < Ref < Tween > > : : Element * N = E - > next ( ) ;
// Don't process if paused or process mode doesn't match.
2022-01-09 18:23:53 +01:00
if ( ! E - > get ( ) - > can_process ( paused ) | | ( p_physics = = ( E - > get ( ) - > get_process_mode ( ) = = Tween : : TWEEN_PROCESS_IDLE ) ) ) {
2020-09-05 03:05:30 +02:00
if ( E = = L ) {
break ;
}
E = N ;
continue ;
}
if ( ! E - > get ( ) - > step ( p_delta ) ) {
2021-08-05 13:05:14 +02:00
E - > get ( ) - > clear ( ) ;
2020-09-05 03:05:30 +02:00
tweens . erase ( E ) ;
}
if ( E = = L ) {
break ;
}
E = N ;
}
}
2020-12-22 10:50:29 +01:00
void SceneTree : : finalize ( ) {
2014-02-10 02:10:30 +01:00
_flush_delete_queue ( ) ;
_flush_ugc ( ) ;
if ( root ) {
2020-04-02 01:20:12 +02:00
root - > _set_tree ( nullptr ) ;
2018-09-07 20:31:19 +02:00
root - > _propagate_after_exit_tree ( ) ;
2014-02-10 02:10:30 +01:00
memdelete ( root ) ; //delete root
2020-04-02 01:20:12 +02:00
root = nullptr ;
2023-01-28 13:25:03 +01:00
// In case deletion of some objects was queued when destructing the `root`.
// E.g. if `queue_free()` was called for some node outside the tree when handling NOTIFICATION_PREDELETE for some node in the tree.
_flush_delete_queue ( ) ;
2014-02-10 02:10:30 +01:00
}
2019-10-19 18:45:17 +02:00
2023-01-28 13:25:03 +01:00
MainLoop : : finalize ( ) ;
2021-10-08 16:37:03 +02:00
// Cleanup timers.
2021-07-26 17:50:35 +02:00
for ( Ref < SceneTreeTimer > & timer : timers ) {
timer - > release_connections ( ) ;
2019-10-19 18:45:17 +02:00
}
timers . clear ( ) ;
2022-12-15 12:09:09 +01:00
// Cleanup tweens.
for ( Ref < Tween > & tween : tweens ) {
tween - > clear ( ) ;
}
tweens . clear ( ) ;
2014-02-10 02:10:30 +01:00
}
2019-12-29 16:39:24 +01:00
void SceneTree : : quit ( int p_exit_code ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2020-06-04 22:03:45 +02:00
OS : : get_singleton ( ) - > set_exit_code ( p_exit_code ) ;
2014-02-10 02:10:30 +01:00
_quit = true ;
}
2020-03-04 17:36:09 +01:00
void SceneTree : : _main_window_close ( ) {
if ( accept_quit ) {
_quit = true ;
}
}
2020-05-14 14:29:06 +02:00
2020-03-04 17:36:09 +01:00
void SceneTree : : _main_window_go_back ( ) {
if ( quit_on_go_back ) {
_quit = true ;
}
}
2014-02-10 02:10:30 +01:00
2020-03-04 17:36:09 +01:00
void SceneTree : : _main_window_focus_in ( ) {
2020-04-28 15:19:37 +02:00
Input * id = Input : : get_singleton ( ) ;
2020-03-04 17:36:09 +01:00
if ( id ) {
id - > ensure_touch_mouse_raised ( ) ;
}
}
2019-09-09 23:42:17 +02:00
2020-03-04 17:36:09 +01:00
void SceneTree : : _notification ( int p_notification ) {
switch ( p_notification ) {
2017-01-09 20:43:44 +01:00
case NOTIFICATION_TRANSLATION_CHANGED : {
2017-08-19 01:02:56 +02:00
if ( ! Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2019-04-04 15:34:03 +02:00
get_root ( ) - > propagate_notification ( p_notification ) ;
2017-06-28 22:00:18 +02:00
}
2017-01-09 20:43:44 +01:00
} break ;
2022-02-15 18:06:48 +01:00
2019-09-09 23:42:17 +02:00
case NOTIFICATION_OS_MEMORY_WARNING :
case NOTIFICATION_OS_IME_UPDATE :
case NOTIFICATION_WM_ABOUT :
case NOTIFICATION_CRASH :
2020-06-30 01:47:18 +02:00
case NOTIFICATION_APPLICATION_RESUMED :
case NOTIFICATION_APPLICATION_PAUSED :
case NOTIFICATION_APPLICATION_FOCUS_IN :
case NOTIFICATION_APPLICATION_FOCUS_OUT : {
2022-02-15 18:06:48 +01:00
// Pass these to nodes, since they are mirrored.
get_root ( ) - > propagate_notification ( p_notification ) ;
2018-07-02 21:18:58 +02:00
} break ;
2022-02-15 18:06:48 +01:00
}
}
2014-02-10 02:10:30 +01:00
2022-05-14 12:18:26 +02:00
bool SceneTree : : is_auto_accept_quit ( ) const {
return accept_quit ;
}
2014-11-06 01:20:42 +01:00
void SceneTree : : set_auto_accept_quit ( bool p_enable ) {
2014-02-10 02:10:30 +01:00
accept_quit = p_enable ;
}
2022-05-14 12:18:26 +02:00
bool SceneTree : : is_quit_on_go_back ( ) const {
return quit_on_go_back ;
}
2017-01-11 20:34:32 +01:00
void SceneTree : : set_quit_on_go_back ( bool p_enable ) {
quit_on_go_back = p_enable ;
}
2017-04-07 16:17:16 +02:00
# ifdef DEBUG_ENABLED
2015-09-19 04:10:58 +02:00
void SceneTree : : set_debug_collisions_hint ( bool p_enabled ) {
debug_collisions_hint = p_enabled ;
}
bool SceneTree : : is_debugging_collisions_hint ( ) const {
return debug_collisions_hint ;
}
2022-06-15 23:24:06 +02:00
void SceneTree : : set_debug_paths_hint ( bool p_enabled ) {
debug_paths_hint = p_enabled ;
}
bool SceneTree : : is_debugging_paths_hint ( ) const {
return debug_paths_hint ;
}
2015-09-20 18:03:46 +02:00
void SceneTree : : set_debug_navigation_hint ( bool p_enabled ) {
debug_navigation_hint = p_enabled ;
}
bool SceneTree : : is_debugging_navigation_hint ( ) const {
return debug_navigation_hint ;
}
2017-04-07 16:17:16 +02:00
# endif
2015-09-20 18:03:46 +02:00
void SceneTree : : set_debug_collisions_color ( const Color & p_color ) {
debug_collisions_color = p_color ;
}
Color SceneTree : : get_debug_collisions_color ( ) const {
return debug_collisions_color ;
}
void SceneTree : : set_debug_collision_contact_color ( const Color & p_color ) {
debug_collision_contact_color = p_color ;
}
Color SceneTree : : get_debug_collision_contact_color ( ) const {
return debug_collision_contact_color ;
}
2022-06-15 23:24:06 +02:00
void SceneTree : : set_debug_paths_color ( const Color & p_color ) {
debug_paths_color = p_color ;
}
Color SceneTree : : get_debug_paths_color ( ) const {
return debug_paths_color ;
}
void SceneTree : : set_debug_paths_width ( float p_width ) {
debug_paths_width = p_width ;
}
float SceneTree : : get_debug_paths_width ( ) const {
return debug_paths_width ;
}
Ref < Material > SceneTree : : get_debug_paths_material ( ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2022-06-15 23:24:06 +02:00
if ( debug_paths_material . is_valid ( ) ) {
return debug_paths_material ;
}
Ref < StandardMaterial3D > _debug_material = Ref < StandardMaterial3D > ( memnew ( StandardMaterial3D ) ) ;
_debug_material - > set_shading_mode ( StandardMaterial3D : : SHADING_MODE_UNSHADED ) ;
_debug_material - > set_transparency ( StandardMaterial3D : : TRANSPARENCY_ALPHA ) ;
_debug_material - > set_flag ( StandardMaterial3D : : FLAG_SRGB_VERTEX_COLOR , true ) ;
_debug_material - > set_flag ( StandardMaterial3D : : FLAG_ALBEDO_FROM_VERTEX_COLOR , true ) ;
2023-09-27 00:45:57 +02:00
_debug_material - > set_flag ( StandardMaterial3D : : FLAG_DISABLE_FOG , true ) ;
2022-06-15 23:24:06 +02:00
_debug_material - > set_albedo ( get_debug_paths_color ( ) ) ;
debug_paths_material = _debug_material ;
return debug_paths_material ;
}
2015-09-20 18:03:46 +02:00
Ref < Material > SceneTree : : get_debug_collision_material ( ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2020-05-14 16:41:43 +02:00
if ( collision_material . is_valid ( ) ) {
2015-09-20 18:03:46 +02:00
return collision_material ;
2020-05-14 16:41:43 +02:00
}
2015-09-20 18:03:46 +02:00
2019-09-15 06:01:52 +02:00
Ref < StandardMaterial3D > line_material = Ref < StandardMaterial3D > ( memnew ( StandardMaterial3D ) ) ;
line_material - > set_shading_mode ( StandardMaterial3D : : SHADING_MODE_UNSHADED ) ;
line_material - > set_transparency ( StandardMaterial3D : : TRANSPARENCY_ALPHA ) ;
line_material - > set_flag ( StandardMaterial3D : : FLAG_SRGB_VERTEX_COLOR , true ) ;
line_material - > set_flag ( StandardMaterial3D : : FLAG_ALBEDO_FROM_VERTEX_COLOR , true ) ;
2023-09-27 00:45:57 +02:00
line_material - > set_flag ( StandardMaterial3D : : FLAG_DISABLE_FOG , true ) ;
2017-08-15 22:21:05 +02:00
line_material - > set_albedo ( get_debug_collisions_color ( ) ) ;
2015-09-20 18:03:46 +02:00
collision_material = line_material ;
return collision_material ;
}
2017-06-07 23:18:55 +02:00
Ref < ArrayMesh > SceneTree : : get_debug_contact_mesh ( ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2020-05-14 16:41:43 +02:00
if ( debug_contact_mesh . is_valid ( ) ) {
2015-09-20 18:03:46 +02:00
return debug_contact_mesh ;
2020-05-14 16:41:43 +02:00
}
2015-09-20 18:03:46 +02:00
2017-06-07 23:18:55 +02:00
debug_contact_mesh = Ref < ArrayMesh > ( memnew ( ArrayMesh ) ) ;
2015-09-20 18:03:46 +02:00
2019-09-15 06:01:52 +02:00
Ref < StandardMaterial3D > mat = Ref < StandardMaterial3D > ( memnew ( StandardMaterial3D ) ) ;
mat - > set_shading_mode ( StandardMaterial3D : : SHADING_MODE_UNSHADED ) ;
mat - > set_transparency ( StandardMaterial3D : : TRANSPARENCY_ALPHA ) ;
mat - > set_flag ( StandardMaterial3D : : FLAG_SRGB_VERTEX_COLOR , true ) ;
mat - > set_flag ( StandardMaterial3D : : FLAG_ALBEDO_FROM_VERTEX_COLOR , true ) ;
2023-09-27 00:45:57 +02:00
mat - > set_flag ( StandardMaterial3D : : FLAG_DISABLE_FOG , true ) ;
2017-08-15 22:21:05 +02:00
mat - > set_albedo ( get_debug_collision_contact_color ( ) ) ;
2015-09-20 18:03:46 +02:00
Vector3 diamond [ 6 ] = {
Vector3 ( - 1 , 0 , 0 ) ,
Vector3 ( 1 , 0 , 0 ) ,
Vector3 ( 0 , - 1 , 0 ) ,
Vector3 ( 0 , 1 , 0 ) ,
Vector3 ( 0 , 0 , - 1 ) ,
Vector3 ( 0 , 0 , 1 )
} ;
2017-12-06 21:36:34 +01:00
/* clang-format off */
2015-09-20 18:03:46 +02:00
int diamond_faces [ 8 * 3 ] = {
0 , 2 , 4 ,
0 , 3 , 4 ,
1 , 2 , 4 ,
1 , 3 , 4 ,
0 , 2 , 5 ,
0 , 3 , 5 ,
1 , 2 , 5 ,
1 , 3 , 5 ,
} ;
2017-12-06 21:36:34 +01:00
/* clang-format on */
2015-09-20 18:03:46 +02:00
2020-02-17 22:06:54 +01:00
Vector < int > indices ;
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < 8 * 3 ; i + + ) {
2015-09-20 18:03:46 +02:00
indices . push_back ( diamond_faces [ i ] ) ;
2020-05-14 16:41:43 +02:00
}
2015-09-20 18:03:46 +02:00
2020-02-17 22:06:54 +01:00
Vector < Vector3 > vertices ;
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < 6 ; i + + ) {
2015-09-20 18:03:46 +02:00
vertices . push_back ( diamond [ i ] * 0.1 ) ;
2020-05-14 16:41:43 +02:00
}
2015-09-20 18:03:46 +02:00
Array arr ;
arr . resize ( Mesh : : ARRAY_MAX ) ;
arr [ Mesh : : ARRAY_VERTEX ] = vertices ;
arr [ Mesh : : ARRAY_INDEX ] = indices ;
2016-11-10 03:55:06 +01:00
debug_contact_mesh - > add_surface_from_arrays ( Mesh : : PRIMITIVE_TRIANGLES , arr ) ;
2015-09-20 18:03:46 +02:00
debug_contact_mesh - > surface_set_material ( 0 , mat ) ;
return debug_contact_mesh ;
}
2014-11-06 01:20:42 +01:00
void SceneTree : : set_pause ( bool p_enabled ) {
2023-04-10 18:45:53 +02:00
ERR_FAIL_COND_MSG ( ! Thread : : is_main_thread ( ) , " Pause can only be set from the main thread. " ) ;
2021-02-19 13:57:41 +01:00
if ( p_enabled = = paused ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2021-02-19 13:57:41 +01:00
paused = p_enabled ;
2024-02-22 15:14:29 +01:00
# ifndef _3D_DISABLED
2020-03-27 19:21:27 +01:00
PhysicsServer3D : : get_singleton ( ) - > set_active ( ! p_enabled ) ;
2024-02-22 15:14:29 +01:00
# endif // _3D_DISABLED
2020-03-27 19:21:27 +01:00
PhysicsServer2D : : get_singleton ( ) - > set_active ( ! p_enabled ) ;
2020-05-14 16:41:43 +02:00
if ( get_root ( ) ) {
2021-02-18 19:52:29 +01:00
get_root ( ) - > _propagate_pause_notification ( p_enabled ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2014-11-06 01:20:42 +01:00
bool SceneTree : : is_paused ( ) const {
2021-02-19 13:57:41 +01:00
return paused ;
2014-02-10 02:10:30 +01:00
}
2023-04-10 18:45:53 +02:00
void SceneTree : : _process_group ( ProcessGroup * p_group , bool p_physics ) {
// When reading this function, keep in mind that this code must work in a way where
// if any node is removed, this needs to continue working.
p_group - > call_queue . flush ( ) ; // Flush messages before processing.
Vector < Node * > & nodes = p_physics ? p_group - > physics_nodes : p_group - > nodes ;
if ( nodes . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-06-09 13:05:07 +02:00
if ( p_physics ) {
if ( p_group - > physics_node_order_dirty ) {
nodes . sort_custom < Node : : ComparatorWithPhysicsPriority > ( ) ;
p_group - > physics_node_order_dirty = false ;
}
} else {
if ( p_group - > node_order_dirty ) {
nodes . sort_custom < Node : : ComparatorWithPriority > ( ) ;
p_group - > node_order_dirty = false ;
}
2023-04-10 18:45:53 +02:00
}
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
// Make a copy, so if nodes are added/removed from process, this does not break
Vector < Node * > nodes_copy = nodes ;
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
uint32_t node_count = nodes_copy . size ( ) ;
Node * * nodes_ptr = ( Node * * ) nodes_copy . ptr ( ) ; // Force cast, pointer will not change.
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
for ( uint32_t i = 0 ; i < node_count ; i + + ) {
Node * n = nodes_ptr [ i ] ;
if ( nodes_removed_on_group_call . has ( n ) ) {
// Node may have been removed during process, skip it.
// Keep in mind removals can only happen on the main thread.
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
if ( ! n - > can_process ( ) | | ! n - > is_inside_tree ( ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2023-04-10 18:45:53 +02:00
if ( p_physics ) {
if ( n - > is_physics_processing_internal ( ) ) {
n - > notification ( Node : : NOTIFICATION_INTERNAL_PHYSICS_PROCESS ) ;
}
2023-06-27 12:48:14 +02:00
if ( n - > is_physics_processing ( ) ) {
n - > notification ( Node : : NOTIFICATION_PHYSICS_PROCESS ) ;
2023-04-10 18:45:53 +02:00
}
2023-06-27 12:48:14 +02:00
} else {
2023-04-10 18:45:53 +02:00
if ( n - > is_processing_internal ( ) ) {
n - > notification ( Node : : NOTIFICATION_INTERNAL_PROCESS ) ;
}
2023-06-27 12:48:14 +02:00
if ( n - > is_processing ( ) ) {
n - > notification ( Node : : NOTIFICATION_PROCESS ) ;
}
2023-04-10 18:45:53 +02:00
}
}
p_group - > call_queue . flush ( ) ; // Flush messages also after processing (for potential deferred calls).
}
void SceneTree : : _process_groups_thread ( uint32_t p_index , bool p_physics ) {
Node : : current_process_thread_group = local_process_group_cache [ p_index ] - > owner ;
_process_group ( local_process_group_cache [ p_index ] , p_physics ) ;
Node : : current_process_thread_group = nullptr ;
}
void SceneTree : : _process ( bool p_physics ) {
if ( process_groups_dirty ) {
{
// First, remove dirty groups.
// This needs to be done when not processing to avoid problems.
ProcessGroup * * pg_ptr = ( ProcessGroup * * ) process_groups . ptr ( ) ; // discard constness.
uint32_t pg_count = process_groups . size ( ) ;
for ( uint32_t i = 0 ; i < pg_count ; i + + ) {
if ( pg_ptr [ i ] - > removed ) {
// Replace removed with last.
pg_ptr [ i ] = pg_ptr [ pg_count - 1 ] ;
// Retry
i - - ;
pg_count - - ;
}
}
if ( pg_count ! = process_groups . size ( ) ) {
process_groups . resize ( pg_count ) ;
}
}
{
// Then, re-sort groups.
process_groups . sort_custom < ProcessGroupSort > ( ) ;
}
process_groups_dirty = false ;
}
// Cache the group count, because during processing new groups may be added.
// They will be added at the end, hence for consistency they will be ignored by this process loop.
// No group will be removed from the array during processing (this is done earlier in this function by marking the groups dirty).
uint32_t group_count = process_groups . size ( ) ;
if ( group_count = = 0 ) {
return ;
}
process_last_pass + + ; // Increment pass
uint32_t from = 0 ;
uint32_t process_count = 0 ;
nodes_removed_on_group_call_lock + + ;
int current_order = process_groups [ 0 ] - > owner ? process_groups [ 0 ] - > owner - > data . process_thread_group_order : 0 ;
bool current_threaded = process_groups [ 0 ] - > owner ? process_groups [ 0 ] - > owner - > data . process_thread_group = = Node : : PROCESS_THREAD_GROUP_SUB_THREAD : false ;
for ( uint32_t i = 0 ; i < = group_count ; i + + ) {
int order = i < group_count & & process_groups [ i ] - > owner ? process_groups [ i ] - > owner - > data . process_thread_group_order : 0 ;
bool threaded = i < group_count & & process_groups [ i ] - > owner ? process_groups [ i ] - > owner - > data . process_thread_group = = Node : : PROCESS_THREAD_GROUP_SUB_THREAD : false ;
if ( i = = group_count | | current_order ! = order | | current_threaded ! = threaded ) {
if ( process_count > 0 ) {
// Proceed to process the group.
bool using_threads = process_groups [ from ] - > owner & & process_groups [ from ] - > owner - > data . process_thread_group = = Node : : PROCESS_THREAD_GROUP_SUB_THREAD & & ! node_threading_disabled ;
if ( using_threads ) {
local_process_group_cache . clear ( ) ;
}
for ( uint32_t j = from ; j < i ; j + + ) {
if ( process_groups [ j ] - > last_pass = = process_last_pass ) {
if ( using_threads ) {
local_process_group_cache . push_back ( process_groups [ j ] ) ;
} else {
_process_group ( process_groups [ j ] , p_physics ) ;
}
}
}
if ( using_threads ) {
WorkerThreadPool : : GroupID id = WorkerThreadPool : : get_singleton ( ) - > add_template_group_task ( this , & SceneTree : : _process_groups_thread , p_physics , local_process_group_cache . size ( ) , - 1 , true ) ;
WorkerThreadPool : : get_singleton ( ) - > wait_for_group_task_completion ( id ) ;
}
}
if ( i = = group_count ) {
// This one is invalid, no longer process
break ;
}
from = i ;
current_threaded = threaded ;
current_order = order ;
}
if ( process_groups [ i ] - > removed ) {
2020-03-04 17:36:09 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
ProcessGroup * pg = process_groups [ i ] ;
// Validate group for processing
bool process_valid = false ;
if ( p_physics ) {
if ( ! pg - > physics_nodes . is_empty ( ) ) {
process_valid = true ;
2023-06-26 19:20:34 +02:00
} else if ( ( pg = = & default_process_group | | ( pg - > owner ! = nullptr & & pg - > owner - > data . process_thread_messages . has_flag ( Node : : FLAG_PROCESS_THREAD_MESSAGES_PHYSICS ) ) ) & & pg - > call_queue . has_messages ( ) ) {
2023-04-10 18:45:53 +02:00
process_valid = true ;
}
} else {
if ( ! pg - > nodes . is_empty ( ) ) {
process_valid = true ;
2023-06-26 19:20:34 +02:00
} else if ( ( pg = = & default_process_group | | ( pg - > owner ! = nullptr & & pg - > owner - > data . process_thread_messages . has_flag ( Node : : FLAG_PROCESS_THREAD_MESSAGES ) ) ) & & pg - > call_queue . has_messages ( ) ) {
2023-04-10 18:45:53 +02:00
process_valid = true ;
}
}
if ( process_valid ) {
pg - > last_pass = process_last_pass ; // Enable for processing
process_count + + ;
}
2014-02-10 02:10:30 +01:00
}
2023-04-10 18:45:53 +02:00
nodes_removed_on_group_call_lock - - ;
if ( nodes_removed_on_group_call_lock = = 0 ) {
nodes_removed_on_group_call . clear ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2023-04-10 18:45:53 +02:00
bool SceneTree : : ProcessGroupSort : : operator ( ) ( const ProcessGroup * p_left , const ProcessGroup * p_right ) const {
int left_order = p_left - > owner ? p_left - > owner - > data . process_thread_group_order : 0 ;
int right_order = p_right - > owner ? p_right - > owner - > data . process_thread_group_order : 0 ;
if ( left_order = = right_order ) {
int left_threaded = p_left - > owner ! = nullptr & & p_left - > owner - > data . process_thread_group = = Node : : PROCESS_THREAD_GROUP_SUB_THREAD ? 0 : 1 ;
int right_threaded = p_right - > owner ! = nullptr & & p_right - > owner - > data . process_thread_group = = Node : : PROCESS_THREAD_GROUP_SUB_THREAD ? 0 : 1 ;
return left_threaded < right_threaded ;
} else {
return left_order < right_order ;
2020-05-14 16:41:43 +02:00
}
2023-04-10 18:45:53 +02:00
}
void SceneTree : : _remove_process_group ( Node * p_node ) {
_THREAD_SAFE_METHOD_
ProcessGroup * pg = ( ProcessGroup * ) p_node - > data . process_group ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL ( pg ) ;
2023-04-10 18:45:53 +02:00
ERR_FAIL_COND ( pg - > removed ) ;
pg - > removed = true ;
pg - > owner = nullptr ;
p_node - > data . process_group = nullptr ;
process_groups_dirty = true ;
}
void SceneTree : : _add_process_group ( Node * p_node ) {
_THREAD_SAFE_METHOD_
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL ( p_node ) ;
2023-04-10 18:45:53 +02:00
ProcessGroup * pg = memnew ( ProcessGroup ) ;
pg - > owner = p_node ;
p_node - > data . process_group = pg ;
process_groups . push_back ( pg ) ;
process_groups_dirty = true ;
}
void SceneTree : : _remove_node_from_process_group ( Node * p_node , Node * p_owner ) {
_THREAD_SAFE_METHOD_
ProcessGroup * pg = p_owner ? ( ProcessGroup * ) p_owner - > data . process_group : & default_process_group ;
if ( p_node - > is_processing ( ) | | p_node - > is_processing_internal ( ) ) {
bool found = pg - > nodes . erase ( p_node ) ;
ERR_FAIL_COND ( ! found ) ;
}
if ( p_node - > is_physics_processing ( ) | | p_node - > is_physics_processing_internal ( ) ) {
bool found = pg - > physics_nodes . erase ( p_node ) ;
ERR_FAIL_COND ( ! found ) ;
}
}
void SceneTree : : _add_node_to_process_group ( Node * p_node , Node * p_owner ) {
_THREAD_SAFE_METHOD_
ProcessGroup * pg = p_owner ? ( ProcessGroup * ) p_owner - > data . process_group : & default_process_group ;
if ( p_node - > is_processing ( ) | | p_node - > is_processing_internal ( ) ) {
pg - > nodes . push_back ( p_node ) ;
pg - > node_order_dirty = true ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
if ( p_node - > is_physics_processing ( ) | | p_node - > is_physics_processing_internal ( ) ) {
pg - > physics_nodes . push_back ( p_node ) ;
pg - > physics_node_order_dirty = true ;
}
}
void SceneTree : : _call_input_pause ( const StringName & p_group , CallInputType p_call_type , const Ref < InputEvent > & p_input , Viewport * p_viewport ) {
Vector < Node * > nodes_copy ;
{
_THREAD_SAFE_METHOD_
HashMap < StringName , Group > : : Iterator E = group_map . find ( p_group ) ;
if ( ! E ) {
return ;
}
Group & g = E - > value ;
if ( g . nodes . is_empty ( ) ) {
return ;
}
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
_update_group_order ( g ) ;
//copy, so copy on write happens in case something is removed from process while being called
//performance is not lost because only if something is added/removed the vector is copied.
nodes_copy = g . nodes ;
}
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
int gr_node_count = nodes_copy . size ( ) ;
Node * * gr_nodes = nodes_copy . ptrw ( ) ;
2014-02-10 02:10:30 +01:00
2023-04-10 18:45:53 +02:00
{
_THREAD_SAFE_METHOD_
nodes_removed_on_group_call_lock + + ;
}
2014-02-10 02:10:30 +01:00
2022-10-27 04:37:55 +02:00
Vector < ObjectID > no_context_node_ids ; // Nodes may be deleted due to this shortcut input.
2022-09-24 16:32:53 +02:00
2022-09-29 11:53:28 +02:00
for ( int i = gr_node_count - 1 ; i > = 0 ; i - - ) {
2020-05-14 16:41:43 +02:00
if ( p_viewport - > is_input_handled ( ) ) {
2020-03-04 17:36:09 +01:00
break ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
Node * n = gr_nodes [ i ] ;
2023-04-10 18:45:53 +02:00
if ( nodes_removed_on_group_call . has ( n ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( ! n - > can_process ( ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-08-22 17:37:22 +02:00
switch ( p_call_type ) {
case CALL_INPUT_TYPE_INPUT :
n - > _call_input ( p_input ) ;
break ;
2022-09-24 16:32:53 +02:00
case CALL_INPUT_TYPE_SHORTCUT_INPUT : {
const Control * c = Object : : cast_to < Control > ( n ) ;
if ( c ) {
// If calling shortcut input on a control, ensure it respects the shortcut context.
// Shortcut context (based on focus) only makes sense for controls (UI), so don't need to worry about it for nodes
if ( c - > get_shortcut_context ( ) = = nullptr ) {
2022-10-27 04:37:55 +02:00
no_context_node_ids . append ( n - > get_instance_id ( ) ) ;
2022-09-24 16:32:53 +02:00
continue ;
}
if ( ! c - > is_focus_owner_in_shortcut_context ( ) ) {
continue ;
}
}
2022-01-11 14:59:52 +01:00
n - > _call_shortcut_input ( p_input ) ;
break ;
2022-09-24 16:32:53 +02:00
}
2021-08-22 17:37:22 +02:00
case CALL_INPUT_TYPE_UNHANDLED_INPUT :
n - > _call_unhandled_input ( p_input ) ;
break ;
case CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT :
n - > _call_unhandled_key_input ( p_input ) ;
break ;
2020-08-03 13:39:04 +02:00
}
2014-02-10 02:10:30 +01:00
}
2022-10-27 04:37:55 +02:00
for ( const ObjectID & id : no_context_node_ids ) {
2022-12-14 22:20:23 +01:00
if ( p_viewport - > is_input_handled ( ) ) {
break ;
}
2022-10-27 04:37:55 +02:00
Node * n = Object : : cast_to < Node > ( ObjectDB : : get_instance ( id ) ) ;
if ( n ) {
n - > _call_shortcut_input ( p_input ) ;
}
2022-09-24 16:32:53 +02:00
}
2023-04-10 18:45:53 +02:00
{
_THREAD_SAFE_METHOD_
nodes_removed_on_group_call_lock - - ;
if ( nodes_removed_on_group_call_lock = = 0 ) {
nodes_removed_on_group_call . clear ( ) ;
}
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2020-05-14 14:29:06 +02:00
2022-02-22 12:15:43 +01:00
void SceneTree : : _call_group_flags ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2020-02-19 20:27:19 +01:00
r_error . error = Callable : : CallError : : CALL_OK ;
2014-02-10 02:10:30 +01:00
2022-02-22 12:15:43 +01:00
ERR_FAIL_COND ( p_argcount < 3 ) ;
ERR_FAIL_COND ( ! p_args [ 0 ] - > is_num ( ) ) ;
2023-12-28 23:44:23 +01:00
ERR_FAIL_COND ( ! p_args [ 1 ] - > is_string ( ) ) ;
ERR_FAIL_COND ( ! p_args [ 2 ] - > is_string ( ) ) ;
2014-02-10 02:10:30 +01:00
int flags = * p_args [ 0 ] ;
StringName group = * p_args [ 1 ] ;
StringName method = * p_args [ 2 ] ;
2022-03-09 14:58:40 +01:00
call_group_flagsp ( flags , group , method , p_args + 3 , p_argcount - 3 ) ;
2014-02-10 02:10:30 +01:00
}
2022-02-22 12:15:43 +01:00
void SceneTree : : _call_group ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2020-02-19 20:27:19 +01:00
r_error . error = Callable : : CallError : : CALL_OK ;
2017-01-14 14:03:53 +01:00
2022-02-22 12:15:43 +01:00
ERR_FAIL_COND ( p_argcount < 2 ) ;
2023-12-28 23:44:23 +01:00
ERR_FAIL_COND ( ! p_args [ 0 ] - > is_string ( ) ) ;
ERR_FAIL_COND ( ! p_args [ 1 ] - > is_string ( ) ) ;
2017-01-14 14:03:53 +01:00
StringName group = * p_args [ 0 ] ;
StringName method = * p_args [ 1 ] ;
2021-08-12 23:40:13 +02:00
call_group_flagsp ( GROUP_CALL_DEFAULT , group , method , p_args + 2 , p_argcount - 2 ) ;
2017-01-14 14:03:53 +01:00
}
2014-11-06 01:20:42 +01:00
int64_t SceneTree : : get_frame ( ) const {
2014-02-10 02:10:30 +01:00
return current_frame ;
}
2020-05-14 14:29:06 +02:00
2022-08-05 20:35:08 +02:00
TypedArray < Node > SceneTree : : _get_nodes_in_group ( const StringName & p_group ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2022-08-05 20:35:08 +02:00
TypedArray < Node > ret ;
2022-05-13 15:04:37 +02:00
HashMap < StringName , Group > : : Iterator E = group_map . find ( p_group ) ;
2020-05-14 16:41:43 +02:00
if ( ! E ) {
2014-02-10 02:10:30 +01:00
return ret ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-05-13 15:04:37 +02:00
_update_group_order ( E - > value ) ; //update order just in case
int nc = E - > value . nodes . size ( ) ;
2020-05-14 16:41:43 +02:00
if ( nc = = 0 ) {
2014-02-10 02:10:30 +01:00
return ret ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
ret . resize ( nc ) ;
2022-05-13 15:04:37 +02:00
Node * * ptr = E - > value . nodes . ptrw ( ) ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < nc ; i + + ) {
ret [ i ] = ptr [ i ] ;
}
return ret ;
}
2016-01-02 21:18:45 +01:00
bool SceneTree : : has_group ( const StringName & p_identifier ) const {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2016-01-02 21:18:45 +01:00
return group_map . has ( p_identifier ) ;
}
2020-05-14 14:29:06 +02:00
2023-06-14 00:36:10 +02:00
int SceneTree : : get_node_count_in_group ( const StringName & p_group ) const {
_THREAD_SAFE_METHOD_
HashMap < StringName , Group > : : ConstIterator E = group_map . find ( p_group ) ;
if ( ! E ) {
return 0 ;
}
return E - > value . nodes . size ( ) ;
}
2021-02-22 14:54:12 +01:00
Node * SceneTree : : get_first_node_in_group ( const StringName & p_group ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2022-05-13 15:04:37 +02:00
HashMap < StringName , Group > : : Iterator E = group_map . find ( p_group ) ;
2021-02-22 14:54:12 +01:00
if ( ! E ) {
2022-04-29 16:14:48 +02:00
return nullptr ; // No group.
2021-02-22 14:54:12 +01:00
}
2022-05-13 15:04:37 +02:00
_update_group_order ( E - > value ) ; // Update order just in case.
2021-02-22 14:54:12 +01:00
2022-05-13 15:04:37 +02:00
if ( E - > value . nodes . is_empty ( ) ) {
2021-02-22 14:54:12 +01:00
return nullptr ;
}
2022-05-13 15:04:37 +02:00
return E - > value . nodes [ 0 ] ;
2021-02-22 14:54:12 +01:00
}
2014-11-06 01:20:42 +01:00
void SceneTree : : get_nodes_in_group ( const StringName & p_group , List < Node * > * p_list ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2022-05-13 15:04:37 +02:00
HashMap < StringName , Group > : : Iterator E = group_map . find ( p_group ) ;
2020-05-14 16:41:43 +02:00
if ( ! E ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2022-05-13 15:04:37 +02:00
_update_group_order ( E - > value ) ; //update order just in case
int nc = E - > value . nodes . size ( ) ;
2020-05-14 16:41:43 +02:00
if ( nc = = 0 ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2022-05-13 15:04:37 +02:00
Node * * ptr = E - > value . nodes . ptrw ( ) ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < nc ; i + + ) {
p_list - > push_back ( ptr [ i ] ) ;
}
}
2014-11-06 01:20:42 +01:00
void SceneTree : : _flush_delete_queue ( ) {
2014-02-10 02:10:30 +01:00
_THREAD_SAFE_METHOD_
while ( delete_queue . size ( ) ) {
Object * obj = ObjectDB : : get_instance ( delete_queue . front ( ) - > get ( ) ) ;
if ( obj ) {
memdelete ( obj ) ;
}
delete_queue . pop_front ( ) ;
}
}
2014-11-06 01:20:42 +01:00
void SceneTree : : queue_delete ( Object * p_object ) {
2014-02-10 02:10:30 +01:00
_THREAD_SAFE_METHOD_
ERR_FAIL_NULL ( p_object ) ;
2015-03-28 18:34:28 +01:00
p_object - > _is_queued_for_deletion = true ;
2017-08-07 12:17:31 +02:00
delete_queue . push_back ( p_object - > get_instance_id ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2014-11-06 01:20:42 +01:00
int SceneTree : : get_node_count ( ) const {
2023-04-10 18:45:53 +02:00
return nodes_in_tree_count ;
2014-02-10 02:10:30 +01:00
}
2014-11-06 01:20:42 +01:00
void SceneTree : : set_edited_scene_root ( Node * p_node ) {
2018-04-29 19:49:26 +02:00
# ifdef TOOLS_ENABLED
2014-10-12 07:13:22 +02:00
edited_scene_root = p_node ;
2018-04-29 19:49:26 +02:00
# endif
2014-10-12 07:13:22 +02:00
}
2014-11-06 01:20:42 +01:00
Node * SceneTree : : get_edited_scene_root ( ) const {
2018-04-29 19:49:26 +02:00
# ifdef TOOLS_ENABLED
2014-10-12 07:13:22 +02:00
return edited_scene_root ;
2018-04-29 19:49:26 +02:00
# else
2020-04-02 01:20:12 +02:00
return nullptr ;
2014-10-12 07:13:22 +02:00
# endif
2018-04-29 19:49:26 +02:00
}
2014-10-12 07:13:22 +02:00
2015-05-17 21:33:35 +02:00
void SceneTree : : set_current_scene ( Node * p_scene ) {
2023-04-10 18:45:53 +02:00
ERR_FAIL_COND_MSG ( ! Thread : : is_main_thread ( ) , " Changing scene can only be done from the main thread. " ) ;
2015-05-17 21:33:35 +02:00
ERR_FAIL_COND ( p_scene & & p_scene - > get_parent ( ) ! = root ) ;
current_scene = p_scene ;
}
Node * SceneTree : : get_current_scene ( ) const {
return current_scene ;
}
2023-07-04 13:28:43 +02:00
void SceneTree : : _flush_scene_change ( ) {
if ( prev_scene ) {
memdelete ( prev_scene ) ;
prev_scene = nullptr ;
2015-05-17 21:33:35 +02:00
}
2023-07-04 13:28:43 +02:00
current_scene = pending_new_scene ;
root - > add_child ( pending_new_scene ) ;
pending_new_scene = nullptr ;
// Update display for cursor instantly.
root - > update_mouse_cursor_state ( ) ;
2015-05-17 21:33:35 +02:00
}
2022-07-28 23:25:57 +02:00
Error SceneTree : : change_scene_to_file ( const String & p_path ) {
2023-04-10 18:45:53 +02:00
ERR_FAIL_COND_V_MSG ( ! Thread : : is_main_thread ( ) , ERR_INVALID_PARAMETER , " Changing scene can only be done from the main thread. " ) ;
2015-05-17 21:33:35 +02:00
Ref < PackedScene > new_scene = ResourceLoader : : load ( p_path ) ;
2020-05-14 16:41:43 +02:00
if ( new_scene . is_null ( ) ) {
2015-05-17 21:33:35 +02:00
return ERR_CANT_OPEN ;
2020-05-14 16:41:43 +02:00
}
2015-05-17 21:33:35 +02:00
2022-07-28 23:25:57 +02:00
return change_scene_to_packed ( new_scene ) ;
2015-05-17 21:33:35 +02:00
}
2022-07-28 23:25:57 +02:00
Error SceneTree : : change_scene_to_packed ( const Ref < PackedScene > & p_scene ) {
2023-01-06 16:08:36 +01:00
ERR_FAIL_COND_V_MSG ( p_scene . is_null ( ) , ERR_INVALID_PARAMETER , " Can't change to a null scene. Use unload_current_scene() if you wish to unload it. " ) ;
Node * new_scene = p_scene - > instantiate ( ) ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V ( new_scene , ERR_CANT_CREATE ) ;
2015-05-17 21:33:35 +02:00
2023-07-04 13:28:43 +02:00
// If called again while a change is pending.
if ( pending_new_scene ) {
queue_delete ( pending_new_scene ) ;
pending_new_scene = nullptr ;
}
prev_scene = current_scene ;
if ( current_scene ) {
// Let as many side effects as possible happen or be queued now,
// so they are run before the scene is actually deleted.
root - > remove_child ( current_scene ) ;
}
DEV_ASSERT ( ! current_scene ) ;
pending_new_scene = new_scene ;
2015-05-17 21:33:35 +02:00
return OK ;
}
2020-01-19 22:06:26 +01:00
Error SceneTree : : reload_current_scene ( ) {
2023-04-10 18:45:53 +02:00
ERR_FAIL_COND_V_MSG ( ! Thread : : is_main_thread ( ) , ERR_INVALID_PARAMETER , " Reloading scene can only be done from the main thread. " ) ;
2023-06-06 14:59:54 +02:00
ERR_FAIL_NULL_V ( current_scene , ERR_UNCONFIGURED ) ;
2021-09-30 16:30:55 +02:00
String fname = current_scene - > get_scene_file_path ( ) ;
2022-07-28 23:25:57 +02:00
return change_scene_to_file ( fname ) ;
2015-05-17 21:33:35 +02:00
}
2023-01-06 16:08:36 +01:00
void SceneTree : : unload_current_scene ( ) {
2023-04-10 18:45:53 +02:00
ERR_FAIL_COND_MSG ( ! Thread : : is_main_thread ( ) , " Unloading the current scene can only be done from the main thread. " ) ;
2023-01-06 16:08:36 +01:00
if ( current_scene ) {
memdelete ( current_scene ) ;
current_scene = nullptr ;
}
}
2015-05-17 21:33:35 +02:00
void SceneTree : : add_current_scene ( Node * p_current ) {
2023-04-10 18:45:53 +02:00
ERR_FAIL_COND_MSG ( ! Thread : : is_main_thread ( ) , " Adding a current scene can only be done from the main thread. " ) ;
2015-05-17 21:33:35 +02:00
current_scene = p_current ;
root - > add_child ( p_current ) ;
}
2020-01-19 22:06:26 +01:00
2022-07-15 08:21:51 +02:00
Ref < SceneTreeTimer > SceneTree : : create_timer ( double p_delay_sec , bool p_process_always , bool p_process_in_physics , bool p_ignore_time_scale ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2016-08-07 02:39:50 +02:00
Ref < SceneTreeTimer > stt ;
2021-06-18 00:03:09 +02:00
stt . instantiate ( ) ;
2021-02-19 13:57:41 +01:00
stt - > set_process_always ( p_process_always ) ;
2016-08-07 02:39:50 +02:00
stt - > set_time_left ( p_delay_sec ) ;
2022-07-15 08:21:51 +02:00
stt - > set_process_in_physics ( p_process_in_physics ) ;
stt - > set_ignore_time_scale ( p_ignore_time_scale ) ;
2016-08-07 02:39:50 +02:00
timers . push_back ( stt ) ;
return stt ;
}
2020-09-05 03:05:30 +02:00
Ref < Tween > SceneTree : : create_tween ( ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2022-04-17 23:13:39 +02:00
Ref < Tween > tween = memnew ( Tween ( true ) ) ;
2020-09-05 03:05:30 +02:00
tweens . push_back ( tween ) ;
return tween ;
}
2022-08-05 20:35:08 +02:00
TypedArray < Tween > SceneTree : : get_processed_tweens ( ) {
2023-04-10 18:45:53 +02:00
_THREAD_SAFE_METHOD_
2022-08-05 20:35:08 +02:00
TypedArray < Tween > ret ;
2020-09-05 03:05:30 +02:00
ret . resize ( tweens . size ( ) ) ;
int i = 0 ;
2021-07-26 17:50:35 +02:00
for ( const Ref < Tween > & tween : tweens ) {
ret [ i ] = tween ;
2020-09-05 03:05:30 +02:00
i + + ;
}
return ret ;
}
2022-02-05 01:43:47 +01:00
Ref < MultiplayerAPI > SceneTree : : get_multiplayer ( const NodePath & p_for_path ) const {
2023-04-10 18:45:53 +02:00
ERR_FAIL_COND_V_MSG ( ! Thread : : is_main_thread ( ) , Ref < MultiplayerAPI > ( ) , " Multiplayer can only be manipulated from the main thread. " ) ;
2023-08-16 14:00:29 +02:00
if ( p_for_path . is_empty ( ) ) {
return multiplayer ;
}
const Vector < StringName > tnames = p_for_path . get_names ( ) ;
const StringName * nptr = tnames . ptr ( ) ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < NodePath , Ref < MultiplayerAPI > > & E : custom_multiplayers ) {
const Vector < StringName > snames = E . key . get_names ( ) ;
2022-02-05 01:43:47 +01:00
if ( tnames . size ( ) < snames . size ( ) ) {
continue ;
}
const StringName * sptr = snames . ptr ( ) ;
bool valid = true ;
for ( int i = 0 ; i < snames . size ( ) ; i + + ) {
if ( sptr [ i ] ! = nptr [ i ] ) {
valid = false ;
break ;
}
}
if ( valid ) {
2023-08-16 14:00:29 +02:00
return E . value ;
2022-02-05 01:43:47 +01:00
}
}
2023-08-16 14:00:29 +02:00
return multiplayer ;
2022-02-05 01:43:47 +01:00
}
void SceneTree : : set_multiplayer ( Ref < MultiplayerAPI > p_multiplayer , const NodePath & p_root_path ) {
2023-04-10 18:45:53 +02:00
ERR_FAIL_COND_MSG ( ! Thread : : is_main_thread ( ) , " Multiplayer can only be manipulated from the main thread. " ) ;
2022-02-05 01:43:47 +01:00
if ( p_root_path . is_empty ( ) ) {
ERR_FAIL_COND ( ! p_multiplayer . is_valid ( ) ) ;
if ( multiplayer . is_valid ( ) ) {
2022-07-12 23:12:42 +02:00
multiplayer - > object_configuration_remove ( nullptr , NodePath ( " / " + root - > get_name ( ) ) ) ;
2022-02-05 01:43:47 +01:00
}
multiplayer = p_multiplayer ;
2022-07-12 23:12:42 +02:00
multiplayer - > object_configuration_add ( nullptr , NodePath ( " / " + root - > get_name ( ) ) ) ;
2022-02-05 01:43:47 +01:00
} else {
2022-07-12 23:12:42 +02:00
if ( custom_multiplayers . has ( p_root_path ) ) {
custom_multiplayers [ p_root_path ] - > object_configuration_remove ( nullptr , p_root_path ) ;
2023-08-16 14:00:29 +02:00
} else if ( p_multiplayer . is_valid ( ) ) {
const Vector < StringName > tnames = p_root_path . get_names ( ) ;
const StringName * nptr = tnames . ptr ( ) ;
for ( const KeyValue < NodePath , Ref < MultiplayerAPI > > & E : custom_multiplayers ) {
const Vector < StringName > snames = E . key . get_names ( ) ;
if ( tnames . size ( ) < snames . size ( ) ) {
continue ;
}
const StringName * sptr = snames . ptr ( ) ;
bool valid = true ;
for ( int i = 0 ; i < snames . size ( ) ; i + + ) {
if ( sptr [ i ] ! = nptr [ i ] ) {
valid = false ;
break ;
}
}
ERR_FAIL_COND_MSG ( valid , " Multiplayer is already configured for a parent of this path: ' " + p_root_path + " ' in ' " + E . key + " '. " ) ;
}
2022-07-12 23:12:42 +02:00
}
2022-02-05 01:43:47 +01:00
if ( p_multiplayer . is_valid ( ) ) {
custom_multiplayers [ p_root_path ] = p_multiplayer ;
2022-07-12 23:12:42 +02:00
p_multiplayer - > object_configuration_add ( nullptr , p_root_path ) ;
2023-08-16 14:00:29 +02:00
} else {
custom_multiplayers . erase ( p_root_path ) ;
2022-02-05 01:43:47 +01:00
}
}
2018-03-03 18:30:11 +01:00
}
2018-06-02 14:32:30 +02:00
void SceneTree : : set_multiplayer_poll_enabled ( bool p_enabled ) {
2023-04-10 18:45:53 +02:00
ERR_FAIL_COND_MSG ( ! Thread : : is_main_thread ( ) , " Multiplayer can only be manipulated from the main thread. " ) ;
2018-06-02 14:32:30 +02:00
multiplayer_poll = p_enabled ;
}
bool SceneTree : : is_multiplayer_poll_enabled ( ) const {
return multiplayer_poll ;
}
2014-11-06 01:20:42 +01:00
void SceneTree : : _bind_methods ( ) {
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_root " ) , & SceneTree : : get_root ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " has_group " , " name " ) , & SceneTree : : has_group ) ;
2014-02-10 02:10:30 +01:00
2022-05-14 12:18:26 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_auto_accept_quit " ) , & SceneTree : : is_auto_accept_quit ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_auto_accept_quit " , " enabled " ) , & SceneTree : : set_auto_accept_quit ) ;
2022-05-14 12:18:26 +02:00
ClassDB : : bind_method ( D_METHOD ( " is_quit_on_go_back " ) , & SceneTree : : is_quit_on_go_back ) ;
2017-12-30 13:15:17 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_quit_on_go_back " , " enabled " ) , & SceneTree : : set_quit_on_go_back ) ;
2014-02-10 02:10:30 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_debug_collisions_hint " , " enable " ) , & SceneTree : : set_debug_collisions_hint ) ;
ClassDB : : bind_method ( D_METHOD ( " is_debugging_collisions_hint " ) , & SceneTree : : is_debugging_collisions_hint ) ;
2022-06-15 23:24:06 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_debug_paths_hint " , " enable " ) , & SceneTree : : set_debug_paths_hint ) ;
ClassDB : : bind_method ( D_METHOD ( " is_debugging_paths_hint " ) , & SceneTree : : is_debugging_paths_hint ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_debug_navigation_hint " , " enable " ) , & SceneTree : : set_debug_navigation_hint ) ;
ClassDB : : bind_method ( D_METHOD ( " is_debugging_navigation_hint " ) , & SceneTree : : is_debugging_navigation_hint ) ;
2015-09-20 18:03:46 +02:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_edited_scene_root " , " scene " ) , & SceneTree : : set_edited_scene_root ) ;
ClassDB : : bind_method ( D_METHOD ( " get_edited_scene_root " ) , & SceneTree : : get_edited_scene_root ) ;
2014-02-10 02:10:30 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_pause " , " enable " ) , & SceneTree : : set_pause ) ;
ClassDB : : bind_method ( D_METHOD ( " is_paused " ) , & SceneTree : : is_paused ) ;
2014-02-10 02:10:30 +01:00
2022-07-15 08:21:51 +02:00
ClassDB : : bind_method ( D_METHOD ( " create_timer " , " time_sec " , " process_always " , " process_in_physics " , " ignore_time_scale " ) , & SceneTree : : create_timer , DEFVAL ( true ) , DEFVAL ( false ) , DEFVAL ( false ) ) ;
2020-09-05 03:05:30 +02:00
ClassDB : : bind_method ( D_METHOD ( " create_tween " ) , & SceneTree : : create_tween ) ;
ClassDB : : bind_method ( D_METHOD ( " get_processed_tweens " ) , & SceneTree : : get_processed_tweens ) ;
2014-02-10 02:10:30 +01:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_node_count " ) , & SceneTree : : get_node_count ) ;
ClassDB : : bind_method ( D_METHOD ( " get_frame " ) , & SceneTree : : get_frame ) ;
2020-06-04 22:03:45 +02:00
ClassDB : : bind_method ( D_METHOD ( " quit " , " exit_code " ) , & SceneTree : : quit , DEFVAL ( EXIT_SUCCESS ) ) ;
2014-02-10 02:10:30 +01:00
2024-02-17 00:57:32 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_physics_interpolation_enabled " , " enabled " ) , & SceneTree : : set_physics_interpolation_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_physics_interpolation_enabled " ) , & SceneTree : : is_physics_interpolation_enabled ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " queue_delete " , " obj " ) , & SceneTree : : queue_delete ) ;
2015-05-17 21:33:35 +02:00
2014-02-10 02:10:30 +01:00
MethodInfo mi ;
2017-01-14 14:03:53 +01:00
mi . name = " call_group_flags " ;
2014-02-10 02:10:30 +01:00
mi . arguments . push_back ( PropertyInfo ( Variant : : INT , " flags " ) ) ;
2020-02-20 22:58:05 +01:00
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " group " ) ) ;
mi . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " method " ) ) ;
2016-09-08 00:39:02 +02:00
2017-01-14 14:03:53 +01:00
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " call_group_flags " , & SceneTree : : _call_group_flags , mi ) ;
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " notify_group_flags " , " call_flags " , " group " , " notification " ) , & SceneTree : : notify_group_flags ) ;
ClassDB : : bind_method ( D_METHOD ( " set_group_flags " , " call_flags " , " group " , " property " , " value " ) , & SceneTree : : set_group_flags ) ;
2017-01-14 14:03:53 +01:00
MethodInfo mi2 ;
mi2 . name = " call_group " ;
2020-02-20 22:58:05 +01:00
mi2 . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " group " ) ) ;
mi2 . arguments . push_back ( PropertyInfo ( Variant : : STRING_NAME , " method " ) ) ;
2017-01-14 14:03:53 +01:00
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " call_group " , & SceneTree : : _call_group , mi2 ) ;
2014-02-10 02:10:30 +01:00
2017-08-09 13:54:55 +02:00
ClassDB : : bind_method ( D_METHOD ( " notify_group " , " group " , " notification " ) , & SceneTree : : notify_group ) ;
ClassDB : : bind_method ( D_METHOD ( " set_group " , " group " , " property " , " value " ) , & SceneTree : : set_group ) ;
2015-05-17 21:33:35 +02:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_nodes_in_group " , " group " ) , & SceneTree : : _get_nodes_in_group ) ;
2021-02-22 14:54:12 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_first_node_in_group " , " group " ) , & SceneTree : : get_first_node_in_group ) ;
2023-06-14 00:36:10 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_node_count_in_group " , " group " ) , & SceneTree : : get_node_count_in_group ) ;
2015-05-17 21:33:35 +02:00
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_current_scene " , " child_node " ) , & SceneTree : : set_current_scene ) ;
ClassDB : : bind_method ( D_METHOD ( " get_current_scene " ) , & SceneTree : : get_current_scene ) ;
2015-05-17 21:33:35 +02:00
2022-07-28 23:25:57 +02:00
ClassDB : : bind_method ( D_METHOD ( " change_scene_to_file " , " path " ) , & SceneTree : : change_scene_to_file ) ;
ClassDB : : bind_method ( D_METHOD ( " change_scene_to_packed " , " packed_scene " ) , & SceneTree : : change_scene_to_packed ) ;
2015-05-17 21:33:35 +02:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " reload_current_scene " ) , & SceneTree : : reload_current_scene ) ;
2023-01-06 16:08:36 +01:00
ClassDB : : bind_method ( D_METHOD ( " unload_current_scene " ) , & SceneTree : : unload_current_scene ) ;
2016-08-14 23:49:50 +02:00
2022-02-05 01:43:47 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_multiplayer " , " multiplayer " , " root_path " ) , & SceneTree : : set_multiplayer , DEFVAL ( NodePath ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " get_multiplayer " , " for_path " ) , & SceneTree : : get_multiplayer , DEFVAL ( NodePath ( ) ) ) ;
2018-06-02 14:32:30 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_multiplayer_poll_enabled " , " enabled " ) , & SceneTree : : set_multiplayer_poll_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_multiplayer_poll_enabled " ) , & SceneTree : : is_multiplayer_poll_enabled ) ;
2014-02-10 02:10:30 +01:00
2022-05-14 12:18:26 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " auto_accept_quit " ) , " set_auto_accept_quit " , " is_auto_accept_quit " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " quit_on_go_back " ) , " set_quit_on_go_back " , " is_quit_on_go_back " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " debug_collisions_hint " ) , " set_debug_collisions_hint " , " is_debugging_collisions_hint " ) ;
2022-06-15 23:24:06 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " debug_paths_hint " ) , " set_debug_paths_hint " , " is_debugging_paths_hint " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " debug_navigation_hint " ) , " set_debug_navigation_hint " , " is_debugging_navigation_hint " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " paused " ) , " set_pause " , " is_paused " ) ;
2021-06-18 01:10:18 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " edited_scene_root " , PROPERTY_HINT_RESOURCE_TYPE , " Node " , PROPERTY_USAGE_NONE ) , " set_edited_scene_root " , " get_edited_scene_root " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " current_scene " , PROPERTY_HINT_RESOURCE_TYPE , " Node " , PROPERTY_USAGE_NONE ) , " set_current_scene " , " get_current_scene " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : OBJECT , " root " , PROPERTY_HINT_RESOURCE_TYPE , " Node " , PROPERTY_USAGE_NONE ) , " " , " get_root " ) ;
2018-06-02 14:32:30 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " multiplayer_poll " ) , " set_multiplayer_poll_enabled " , " is_multiplayer_poll_enabled " ) ;
2024-02-17 00:57:32 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " physics_interpolation " ) , " set_physics_interpolation_enabled " , " is_physics_interpolation_enabled " ) ;
2018-01-11 23:35:12 +01:00
2015-06-12 18:53:18 +02:00
ADD_SIGNAL ( MethodInfo ( " tree_changed " ) ) ;
2021-05-20 12:07:26 +02:00
ADD_SIGNAL ( MethodInfo ( " tree_process_mode_changed " ) ) ; //editor only signal, but due to API hash it can't be removed in run-time
2018-09-01 12:05:51 +02:00
ADD_SIGNAL ( MethodInfo ( " node_added " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_RESOURCE_TYPE , " Node " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " node_removed " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_RESOURCE_TYPE , " Node " ) ) ) ;
2019-05-24 15:27:22 +02:00
ADD_SIGNAL ( MethodInfo ( " node_renamed " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_RESOURCE_TYPE , " Node " ) ) ) ;
2018-09-01 12:05:51 +02:00
ADD_SIGNAL ( MethodInfo ( " node_configuration_warning_changed " , PropertyInfo ( Variant : : OBJECT , " node " , PROPERTY_HINT_RESOURCE_TYPE , " Node " ) ) ) ;
2015-06-12 18:53:18 +02:00
2020-12-22 10:50:29 +01:00
ADD_SIGNAL ( MethodInfo ( " process_frame " ) ) ;
2017-09-30 16:19:07 +02:00
ADD_SIGNAL ( MethodInfo ( " physics_frame " ) ) ;
2016-05-27 19:18:40 +02:00
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( GROUP_CALL_DEFAULT ) ;
BIND_ENUM_CONSTANT ( GROUP_CALL_REVERSE ) ;
2021-08-12 23:40:13 +02:00
BIND_ENUM_CONSTANT ( GROUP_CALL_DEFERRED ) ;
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( GROUP_CALL_UNIQUE ) ;
2014-02-10 02:10:30 +01:00
}
2020-04-02 01:20:12 +02:00
SceneTree * SceneTree : : singleton = nullptr ;
2016-10-27 16:50:26 +02:00
SceneTree : : IdleCallback SceneTree : : idle_callbacks [ SceneTree : : MAX_IDLE_CALLBACKS ] ;
int SceneTree : : idle_callback_count = 0 ;
void SceneTree : : _call_idle_callbacks ( ) {
for ( int i = 0 ; i < idle_callback_count ; i + + ) {
idle_callbacks [ i ] ( ) ;
}
}
void SceneTree : : add_idle_callback ( IdleCallback p_callback ) {
ERR_FAIL_COND ( idle_callback_count > = MAX_IDLE_CALLBACKS ) ;
idle_callbacks [ idle_callback_count + + ] = p_callback ;
}
2024-01-03 12:10:11 +01:00
# ifdef TOOLS_ENABLED
2019-03-09 03:05:59 +01:00
void SceneTree : : get_argument_options ( const StringName & p_function , int p_idx , List < String > * r_options ) const {
2024-01-03 12:10:11 +01:00
const String pf = p_function ;
2024-01-15 00:48:06 +01:00
bool add_options = false ;
if ( p_idx = = 0 ) {
add_options = pf = = " get_nodes_in_group " | | pf = = " has_group " | | pf = = " get_first_node_in_group " | | pf = = " set_group " | | pf = = " notify_group " | | pf = = " call_group " | | pf = = " add_to_group " ;
} else if ( p_idx = = 1 ) {
add_options = pf = = " set_group_flags " | | pf = = " call_group_flags " | | pf = = " notify_group_flags " ;
}
if ( add_options ) {
HashMap < StringName , String > global_groups = ProjectSettings : : get_singleton ( ) - > get_global_groups_list ( ) ;
for ( const KeyValue < StringName , String > & E : global_groups ) {
r_options - > push_back ( E . key . operator String ( ) . quote ( ) ) ;
2022-05-12 10:20:12 +02:00
}
2019-03-09 03:05:59 +01:00
}
2024-01-03 00:13:04 +01:00
MainLoop : : get_argument_options ( p_function , p_idx , r_options ) ;
2019-03-09 03:05:59 +01:00
}
2024-01-03 12:10:11 +01:00
# endif
2019-03-09 03:05:59 +01:00
2023-04-10 18:45:53 +02:00
void SceneTree : : set_disable_node_threading ( bool p_disable ) {
node_threading_disabled = p_disable ;
}
2014-11-06 01:20:42 +01:00
SceneTree : : SceneTree ( ) {
2020-05-14 16:41:43 +02:00
if ( singleton = = nullptr ) {
2020-04-02 01:20:12 +02:00
singleton = this ;
2020-05-14 16:41:43 +02:00
}
2021-01-20 15:42:11 +01:00
debug_collisions_color = GLOBAL_DEF ( " debug/shapes/collision/shape_color " , Color ( 0.0 , 0.6 , 0.7 , 0.42 ) ) ;
2017-07-18 02:05:38 +02:00
debug_collision_contact_color = GLOBAL_DEF ( " debug/shapes/collision/contact_color " , Color ( 1.0 , 0.2 , 0.1 , 0.8 ) ) ;
2022-06-15 23:24:06 +02:00
debug_paths_color = GLOBAL_DEF ( " debug/shapes/paths/geometry_color " , Color ( 0.1 , 1.0 , 0.7 , 0.4 ) ) ;
debug_paths_width = GLOBAL_DEF ( " debug/shapes/paths/geometry_width " , 2.0 ) ;
2022-11-08 19:53:22 +01:00
collision_debug_contacts = GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " debug/shapes/collision/max_contacts_displayed " , PROPERTY_HINT_RANGE , " 0,20000,1 " ) , 10000 ) ;
2017-03-05 16:44:50 +01:00
2021-02-25 14:56:47 +01:00
GLOBAL_DEF ( " debug/shapes/collision/draw_2d_outlines " , true ) ;
2023-04-10 18:45:53 +02:00
process_group_call_queue_allocator = memnew ( CallQueue : : Allocator ( 64 ) ) ;
2020-11-05 11:04:25 +01:00
Math : : randomize ( ) ;
2020-12-11 15:54:03 +01:00
// Create with mainloop.
2014-02-10 02:10:30 +01:00
2020-03-04 02:51:12 +01:00
root = memnew ( Window ) ;
2023-01-03 08:25:45 +01:00
root - > set_min_size ( Size2i ( 64 , 64 ) ) ; // Define a very small minimum window size to prevent bugs such as GH-37242.
2021-06-22 02:49:34 +02:00
root - > set_process_mode ( Node : : PROCESS_MODE_PAUSABLE ) ;
2024-04-16 04:34:14 +02:00
root - > set_auto_translate_mode ( GLOBAL_GET ( " internationalization/rendering/root_node_auto_translate " ) ? Node : : AUTO_TRANSLATE_MODE_ALWAYS : Node : : AUTO_TRANSLATE_MODE_DISABLED ) ;
2014-02-10 02:10:30 +01:00
root - > set_name ( " root " ) ;
2022-10-18 16:43:37 +02:00
root - > set_title ( GLOBAL_GET ( " application/config/name " ) ) ;
2022-01-21 10:08:07 +01:00
2023-02-20 20:25:39 +01:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
root - > set_wrap_controls ( true ) ;
}
2021-07-04 03:43:23 +02:00
# ifndef _3D_DISABLED
2020-05-14 16:41:43 +02:00
if ( ! root - > get_world_3d ( ) . is_valid ( ) ) {
2020-04-18 11:00:51 +02:00
root - > set_world_3d ( Ref < World3D > ( memnew ( World3D ) ) ) ;
2020-05-14 16:41:43 +02:00
}
2021-07-04 03:43:23 +02:00
root - > set_as_audio_listener_3d ( true ) ;
# endif // _3D_DISABLED
2017-05-29 02:46:48 +02:00
2024-02-17 00:57:32 +01:00
set_physics_interpolation_enabled ( GLOBAL_DEF ( " physics/common/physics_interpolation " , false ) ) ;
2024-05-26 19:39:28 +02:00
// Always disable jitter fix if physics interpolation is enabled -
// Jitter fix will interfere with interpolation, and is not necessary
// when interpolation is active.
if ( is_physics_interpolation_enabled ( ) ) {
Engine : : get_singleton ( ) - > set_physics_jitter_fix ( 0 ) ;
}
2020-12-11 15:54:03 +01:00
// Initialize network state.
2022-07-12 23:12:42 +02:00
set_multiplayer ( MultiplayerAPI : : create_default_interface ( ) ) ;
2018-03-03 18:30:11 +01:00
2014-02-10 02:10:30 +01:00
root - > set_as_audio_listener_2d ( true ) ;
2020-04-02 01:20:12 +02:00
current_scene = nullptr ;
2014-02-10 02:10:30 +01:00
2022-11-08 19:53:22 +01:00
const int msaa_mode_2d = GLOBAL_DEF_BASIC ( PropertyInfo ( Variant : : INT , " rendering/anti_aliasing/quality/msaa_2d " , PROPERTY_HINT_ENUM , String : : utf8 ( " Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest) " ) ) , 0 ) ;
2022-08-13 01:02:32 +02:00
root - > set_msaa_2d ( Viewport : : MSAA ( msaa_mode_2d ) ) ;
2022-11-08 19:53:22 +01:00
const int msaa_mode_3d = GLOBAL_DEF_BASIC ( PropertyInfo ( Variant : : INT , " rendering/anti_aliasing/quality/msaa_3d " , PROPERTY_HINT_ENUM , String : : utf8 ( " Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest) " ) ) , 0 ) ;
2022-08-13 01:02:32 +02:00
root - > set_msaa_3d ( Viewport : : MSAA ( msaa_mode_3d ) ) ;
2017-07-19 22:00:46 +02:00
2022-12-17 18:45:21 +01:00
const bool transparent_background = GLOBAL_DEF ( " rendering/viewport/transparent_background " , false ) ;
2022-10-09 00:05:56 +02:00
root - > set_transparent_background ( transparent_background ) ;
2023-08-03 14:10:01 +02:00
const bool use_hdr_2d = GLOBAL_DEF_RST_BASIC ( " rendering/viewport/hdr_2d " , false ) ;
root - > set_use_hdr_2d ( use_hdr_2d ) ;
2022-11-08 19:53:22 +01:00
const int ssaa_mode = GLOBAL_DEF_BASIC ( PropertyInfo ( Variant : : INT , " rendering/anti_aliasing/quality/screen_space_aa " , PROPERTY_HINT_ENUM , " Disabled (Fastest),FXAA (Fast) " ) , 0 ) ;
2020-04-12 06:49:10 +02:00
root - > set_screen_space_aa ( Viewport : : ScreenSpaceAA ( ssaa_mode ) ) ;
2022-06-12 19:50:14 +02:00
const bool use_taa = GLOBAL_DEF_BASIC ( " rendering/anti_aliasing/quality/use_taa " , false ) ;
2022-04-04 16:10:22 +02:00
root - > set_use_taa ( use_taa ) ;
2021-02-17 17:44:49 +01:00
const bool use_debanding = GLOBAL_DEF ( " rendering/anti_aliasing/quality/use_debanding " , false ) ;
2020-04-20 23:34:47 +02:00
root - > set_use_debanding ( use_debanding ) ;
2021-04-20 18:40:24 +02:00
const bool use_occlusion_culling = GLOBAL_DEF ( " rendering/occlusion_culling/use_occlusion_culling " , false ) ;
root - > set_use_occlusion_culling ( use_occlusion_culling ) ;
2022-11-08 19:53:22 +01:00
float mesh_lod_threshold = GLOBAL_DEF ( PropertyInfo ( Variant : : FLOAT , " rendering/mesh_lod/lod_change/threshold_pixels " , PROPERTY_HINT_RANGE , " 0,1024,0.1 " ) , 1.0 ) ;
2021-12-29 00:10:41 +01:00
root - > set_mesh_lod_threshold ( mesh_lod_threshold ) ;
2020-12-17 19:56:59 +01:00
2024-02-17 18:59:22 +01:00
bool snap_2d_transforms = GLOBAL_DEF_BASIC ( " rendering/2d/snap/snap_2d_transforms_to_pixel " , false ) ;
2020-10-29 22:09:16 +01:00
root - > set_snap_2d_transforms_to_pixel ( snap_2d_transforms ) ;
2024-02-28 15:20:47 +01:00
bool snap_2d_vertices = GLOBAL_DEF ( " rendering/2d/snap/snap_2d_vertices_to_pixel " , false ) ;
2020-10-29 22:09:16 +01:00
root - > set_snap_2d_vertices_to_pixel ( snap_2d_vertices ) ;
2022-02-11 12:33:54 +01:00
// We setup VRS for the main viewport here, in the editor this will have little effect.
2022-11-08 19:53:22 +01:00
const int vrs_mode = GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " rendering/vrs/mode " , PROPERTY_HINT_ENUM , String : : utf8 ( " Disabled,Texture,XR " ) ) , 0 ) ;
2022-02-11 12:33:54 +01:00
root - > set_vrs_mode ( Viewport : : VRSMode ( vrs_mode ) ) ;
2022-11-08 19:53:22 +01:00
const String vrs_texture_path = String ( GLOBAL_DEF ( PropertyInfo ( Variant : : STRING , " rendering/vrs/texture " , PROPERTY_HINT_FILE , " *.bmp,*.png,*.tga,*.webp " ) , String ( ) ) ) . strip_edges ( ) ;
2022-02-11 12:33:54 +01:00
if ( vrs_mode = = 1 & & ! vrs_texture_path . is_empty ( ) ) {
Ref < Image > vrs_image ;
vrs_image . instantiate ( ) ;
Error load_err = ImageLoader : : load_image ( vrs_texture_path , vrs_image ) ;
if ( load_err ) {
ERR_PRINT ( " Non-existing or invalid VRS texture at ' " + vrs_texture_path + " '. " ) ;
} else {
Ref < ImageTexture > vrs_texture ;
vrs_texture . instantiate ( ) ;
vrs_texture - > create_from_image ( vrs_image ) ;
root - > set_vrs_texture ( vrs_texture ) ;
}
}
2022-11-08 19:53:22 +01:00
int shadowmap_size = GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " rendering/lights_and_shadows/positional_shadow/atlas_size " , PROPERTY_HINT_RANGE , " 256,16384 " ) , 4096 ) ;
2022-08-01 01:20:24 +02:00
GLOBAL_DEF ( " rendering/lights_and_shadows/positional_shadow/atlas_size.mobile " , 2048 ) ;
bool shadowmap_16_bits = GLOBAL_DEF ( " rendering/lights_and_shadows/positional_shadow/atlas_16_bits " , true ) ;
2022-11-08 19:53:22 +01:00
int atlas_q0 = GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv " , PROPERTY_HINT_ENUM , " Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows " ) , 2 ) ;
int atlas_q1 = GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv " , PROPERTY_HINT_ENUM , " Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows " ) , 2 ) ;
int atlas_q2 = GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv " , PROPERTY_HINT_ENUM , " Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows " ) , 3 ) ;
int atlas_q3 = GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv " , PROPERTY_HINT_ENUM , " Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows " ) , 4 ) ;
2022-05-01 01:40:30 +02:00
root - > set_positional_shadow_atlas_size ( shadowmap_size ) ;
root - > set_positional_shadow_atlas_16_bits ( shadowmap_16_bits ) ;
root - > set_positional_shadow_atlas_quadrant_subdiv ( 0 , Viewport : : PositionalShadowAtlasQuadrantSubdiv ( atlas_q0 ) ) ;
root - > set_positional_shadow_atlas_quadrant_subdiv ( 1 , Viewport : : PositionalShadowAtlasQuadrantSubdiv ( atlas_q1 ) ) ;
root - > set_positional_shadow_atlas_quadrant_subdiv ( 2 , Viewport : : PositionalShadowAtlasQuadrantSubdiv ( atlas_q2 ) ) ;
root - > set_positional_shadow_atlas_quadrant_subdiv ( 3 , Viewport : : PositionalShadowAtlasQuadrantSubdiv ( atlas_q3 ) ) ;
2021-01-24 20:00:20 +01:00
2022-11-08 19:53:22 +01:00
Viewport : : SDFOversize sdf_oversize = Viewport : : SDFOversize ( int ( GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " rendering/2d/sdf/oversize " , PROPERTY_HINT_ENUM , " 100%,120%,150%,200% " ) , 1 ) ) ) ;
2020-11-26 13:50:21 +01:00
root - > set_sdf_oversize ( sdf_oversize ) ;
2022-11-08 19:53:22 +01:00
Viewport : : SDFScale sdf_scale = Viewport : : SDFScale ( int ( GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " rendering/2d/sdf/scale " , PROPERTY_HINT_ENUM , " 100%,50%,25% " ) , 1 ) ) ) ;
2020-11-26 13:50:21 +01:00
root - > set_sdf_scale ( sdf_scale ) ;
2021-07-04 03:43:23 +02:00
# ifndef _3D_DISABLED
2020-12-11 15:54:03 +01:00
{ // Load default fallback environment.
// Get possible extensions.
2017-05-29 02:46:48 +02:00
List < String > exts ;
ResourceLoader : : get_recognized_extensions_for_type ( " Environment " , & exts ) ;
String ext_hint ;
2021-07-24 15:46:25 +02:00
for ( const String & E : exts ) {
2021-12-09 10:42:46 +01:00
if ( ! ext_hint . is_empty ( ) ) {
2017-05-29 02:46:48 +02:00
ext_hint + = " , " ;
2020-05-14 16:41:43 +02:00
}
2021-07-16 05:45:57 +02:00
ext_hint + = " *. " + E ;
2017-05-29 02:46:48 +02:00
}
2020-12-11 15:54:03 +01:00
// Get path.
2022-11-08 19:53:22 +01:00
String env_path = GLOBAL_DEF ( PropertyInfo ( Variant : : STRING , " rendering/environment/defaults/default_environment " , PROPERTY_HINT_FILE , ext_hint ) , " " ) ;
2020-12-11 15:54:03 +01:00
// Setup property.
2017-05-29 02:46:48 +02:00
env_path = env_path . strip_edges ( ) ;
2021-12-09 10:42:46 +01:00
if ( ! env_path . is_empty ( ) ) {
2017-05-29 02:46:48 +02:00
Ref < Environment > env = ResourceLoader : : load ( env_path ) ;
if ( env . is_valid ( ) ) {
2020-04-18 11:00:51 +02:00
root - > get_world_3d ( ) - > set_fallback_environment ( env ) ;
2017-05-29 02:46:48 +02:00
} else {
2017-08-19 01:02:56 +02:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
2020-12-11 15:54:03 +01:00
// File was erased, clear the field.
2021-02-17 17:44:49 +01:00
ProjectSettings : : get_singleton ( ) - > set ( " rendering/environment/defaults/default_environment " , " " ) ;
2017-05-29 02:46:48 +02:00
} else {
2020-12-11 15:54:03 +01:00
// File was erased, notify user.
2023-11-11 22:59:05 +01:00
ERR_PRINT ( " Default Environment as specified in the project setting \" rendering/environment/defaults/default_environment \" could not be loaded. " ) ;
2017-05-29 02:46:48 +02:00
}
}
}
}
2021-07-04 03:43:23 +02:00
# endif // _3D_DISABLED
2017-05-29 02:46:48 +02:00
2017-01-05 13:16:00 +01:00
root - > set_physics_object_picking ( GLOBAL_DEF ( " physics/common/enable_object_picking " , true ) ) ;
2014-09-15 16:33:30 +02:00
2020-03-04 17:36:09 +01:00
root - > connect ( " close_requested " , callable_mp ( this , & SceneTree : : _main_window_close ) ) ;
root - > connect ( " go_back_requested " , callable_mp ( this , & SceneTree : : _main_window_go_back ) ) ;
2024-05-13 16:56:03 +02:00
root - > connect ( SceneStringName ( focus_entered ) , callable_mp ( this , & SceneTree : : _main_window_focus_in ) ) ;
2020-03-04 17:36:09 +01:00
2014-10-14 06:01:25 +02:00
# ifdef TOOLS_ENABLED
2020-04-02 01:20:12 +02:00
edited_scene_root = nullptr ;
2014-10-14 06:01:25 +02:00
# endif
2023-04-10 18:45:53 +02:00
process_groups . push_back ( & default_process_group ) ;
2014-02-10 02:10:30 +01:00
}
2014-11-06 01:20:42 +01:00
SceneTree : : ~ SceneTree ( ) {
2023-07-04 13:28:43 +02:00
if ( prev_scene ) {
memdelete ( prev_scene ) ;
prev_scene = nullptr ;
}
if ( pending_new_scene ) {
memdelete ( pending_new_scene ) ;
pending_new_scene = nullptr ;
}
2019-06-01 15:42:22 +02:00
if ( root ) {
2020-04-02 01:20:12 +02:00
root - > _set_tree ( nullptr ) ;
2019-06-01 15:42:22 +02:00
root - > _propagate_after_exit_tree ( ) ;
memdelete ( root ) ;
}
2023-04-10 18:45:53 +02:00
// Process groups are not deleted immediately, they may remain around. Delete them now.
for ( uint32_t i = 0 ; i < process_groups . size ( ) ; i + + ) {
if ( process_groups [ i ] ! = & default_process_group ) {
memdelete ( process_groups [ i ] ) ;
}
}
memdelete ( process_group_call_queue_allocator ) ;
2020-05-14 16:41:43 +02:00
if ( singleton = = this ) {
2020-04-02 01:20:12 +02:00
singleton = nullptr ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}