Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/main/scene_tree.cpp
9896 views
1
/**************************************************************************/
2
/* scene_tree.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "scene_tree.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/input/input.h"
35
#include "core/io/image_loader.h"
36
#include "core/io/resource_loader.h"
37
#include "core/object/message_queue.h"
38
#include "core/object/worker_thread_pool.h"
39
#include "core/os/os.h"
40
#include "node.h"
41
#include "scene/animation/tween.h"
42
#include "scene/debugger/scene_debugger.h"
43
#include "scene/gui/control.h"
44
#include "scene/main/multiplayer_api.h"
45
#include "scene/main/viewport.h"
46
#include "scene/main/window.h"
47
#include "scene/resources/environment.h"
48
#include "scene/resources/image_texture.h"
49
#include "scene/resources/material.h"
50
#include "scene/resources/mesh.h"
51
#include "scene/resources/packed_scene.h"
52
#include "scene/resources/world_2d.h"
53
54
#ifndef _3D_DISABLED
55
#include "scene/3d/node_3d.h"
56
#include "scene/resources/3d/world_3d.h"
57
#endif // _3D_DISABLED
58
59
#ifndef PHYSICS_2D_DISABLED
60
#include "servers/physics_server_2d.h"
61
#endif // PHYSICS_2D_DISABLED
62
63
#ifndef PHYSICS_3D_DISABLED
64
#include "servers/physics_server_3d.h"
65
#endif // PHYSICS_3D_DISABLED
66
67
void SceneTreeTimer::_bind_methods() {
68
ClassDB::bind_method(D_METHOD("set_time_left", "time"), &SceneTreeTimer::set_time_left);
69
ClassDB::bind_method(D_METHOD("get_time_left"), &SceneTreeTimer::get_time_left);
70
71
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_left", PROPERTY_HINT_NONE, "suffix:s"), "set_time_left", "get_time_left");
72
73
ADD_SIGNAL(MethodInfo("timeout"));
74
}
75
76
void SceneTreeTimer::set_time_left(double p_time) {
77
time_left = p_time;
78
}
79
80
double SceneTreeTimer::get_time_left() const {
81
return MAX(time_left, 0.0);
82
}
83
84
void SceneTreeTimer::set_process_always(bool p_process_always) {
85
process_always = p_process_always;
86
}
87
88
bool SceneTreeTimer::is_process_always() {
89
return process_always;
90
}
91
92
void SceneTreeTimer::set_process_in_physics(bool p_process_in_physics) {
93
process_in_physics = p_process_in_physics;
94
}
95
96
bool SceneTreeTimer::is_process_in_physics() {
97
return process_in_physics;
98
}
99
100
void SceneTreeTimer::set_ignore_time_scale(bool p_ignore) {
101
ignore_time_scale = p_ignore;
102
}
103
104
bool SceneTreeTimer::is_ignoring_time_scale() {
105
return ignore_time_scale;
106
}
107
108
void SceneTreeTimer::release_connections() {
109
List<Connection> signal_connections;
110
get_all_signal_connections(&signal_connections);
111
112
for (const Connection &connection : signal_connections) {
113
disconnect(connection.signal.get_name(), connection.callable);
114
}
115
}
116
117
#ifndef _3D_DISABLED
118
// This should be called once per physics tick, to make sure the transform previous and current
119
// is kept up to date on the few Node3Ds that are using client side physics interpolation.
120
void SceneTree::ClientPhysicsInterpolation::physics_process() {
121
for (SelfList<Node3D> *E = _node_3d_list.first(); E;) {
122
Node3D *node_3d = E->self();
123
124
SelfList<Node3D> *current = E;
125
126
// Get the next element here BEFORE we potentially delete one.
127
E = E->next();
128
129
// This will return false if the Node3D has timed out ..
130
// i.e. if get_global_transform_interpolated() has not been called
131
// for a few seconds, we can delete from the list to keep processing
132
// to a minimum.
133
if (!node_3d->update_client_physics_interpolation_data()) {
134
_node_3d_list.remove(current);
135
}
136
}
137
}
138
#endif // _3D_DISABLED
139
140
bool SceneTree::_physics_interpolation_enabled = false;
141
bool SceneTree::_physics_interpolation_enabled_in_project = false;
142
143
void SceneTree::tree_changed() {
144
emit_signal(tree_changed_name);
145
}
146
147
void SceneTree::node_added(Node *p_node) {
148
emit_signal(node_added_name, p_node);
149
}
150
151
void SceneTree::node_removed(Node *p_node) {
152
// Nodes can only be removed from the main thread.
153
if (current_scene == p_node) {
154
current_scene = nullptr;
155
}
156
emit_signal(node_removed_name, p_node);
157
if (nodes_removed_on_group_call_lock) {
158
nodes_removed_on_group_call.insert(p_node);
159
}
160
}
161
162
void SceneTree::node_renamed(Node *p_node) {
163
emit_signal(node_renamed_name, p_node);
164
}
165
166
SceneTree::Group *SceneTree::add_to_group(const StringName &p_group, Node *p_node) {
167
_THREAD_SAFE_METHOD_
168
169
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
170
if (!E) {
171
E = group_map.insert(p_group, Group());
172
}
173
174
ERR_FAIL_COND_V_MSG(E->value.nodes.has(p_node), &E->value, "Already in group: " + p_group + ".");
175
E->value.nodes.push_back(p_node);
176
E->value.changed = true;
177
return &E->value;
178
}
179
180
void SceneTree::remove_from_group(const StringName &p_group, Node *p_node) {
181
_THREAD_SAFE_METHOD_
182
183
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
184
ERR_FAIL_COND(!E);
185
186
E->value.nodes.erase(p_node);
187
if (E->value.nodes.is_empty()) {
188
group_map.remove(E);
189
}
190
}
191
192
void SceneTree::flush_transform_notifications() {
193
_THREAD_SAFE_METHOD_
194
195
SelfList<Node> *n = xform_change_list.first();
196
while (n) {
197
Node *node = n->self();
198
SelfList<Node> *nx = n->next();
199
xform_change_list.remove(n);
200
n = nx;
201
node->notification(NOTIFICATION_TRANSFORM_CHANGED);
202
}
203
}
204
205
bool SceneTree::is_accessibility_enabled() const {
206
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_ACCESSIBILITY_SCREEN_READER)) {
207
return false;
208
}
209
210
DisplayServer::AccessibilityMode accessibility_mode = DisplayServer::accessibility_get_mode();
211
int screen_reader_active = DisplayServer::get_singleton()->accessibility_screen_reader_active();
212
if ((accessibility_mode == DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED) || ((accessibility_mode == DisplayServer::AccessibilityMode::ACCESSIBILITY_AUTO) && (screen_reader_active != 1))) {
213
return false;
214
}
215
return true;
216
}
217
218
bool SceneTree::is_accessibility_supported() const {
219
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_ACCESSIBILITY_SCREEN_READER)) {
220
return false;
221
}
222
223
DisplayServer::AccessibilityMode accessibility_mode = DisplayServer::accessibility_get_mode();
224
if (accessibility_mode == DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED) {
225
return false;
226
}
227
return true;
228
}
229
230
void SceneTree::_accessibility_force_update() {
231
accessibility_force_update = true;
232
}
233
234
void SceneTree::_accessibility_notify_change(const Node *p_node, bool p_remove) {
235
if (p_node) {
236
if (p_remove) {
237
accessibility_change_queue.erase(p_node->get_instance_id());
238
} else {
239
accessibility_change_queue.insert(p_node->get_instance_id());
240
}
241
}
242
}
243
244
void SceneTree::_process_accessibility_changes(DisplayServer::WindowID p_window_id) {
245
// Process NOTIFICATION_ACCESSIBILITY_UPDATE.
246
Vector<ObjectID> processed;
247
for (const ObjectID &id : accessibility_change_queue) {
248
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(id));
249
if (!node || !node->get_non_popup_window() || !node->get_window()->is_visible()) {
250
processed.push_back(id);
251
continue; // Invalid node, remove from list and skip.
252
} else if (node->get_non_popup_window()->get_window_id() != p_window_id) {
253
continue; // Another window, skip.
254
}
255
node->notification(Node::NOTIFICATION_ACCESSIBILITY_UPDATE);
256
processed.push_back(id);
257
}
258
259
// Track focus change.
260
// Note: Do not use `Window::get_focused_window()`, it returns both native and embedded windows, and we only care about focused element in the currently processed native window.
261
// Native window focus is handled in the DisplayServer, or AccessKit subclassing adapter.
262
ObjectID oid = DisplayServer::get_singleton()->window_get_attached_instance_id(p_window_id);
263
Window *w_this = (Window *)ObjectDB::get_instance(oid);
264
if (w_this) {
265
Window *w_focus = w_this->get_focused_subwindow();
266
if (w_focus && !w_focus->is_part_of_edited_scene()) {
267
w_this = w_focus;
268
}
269
270
// Popups have no native window focus, but have focused element.
271
DisplayServer::WindowID popup_id = DisplayServer::get_singleton()->window_get_active_popup();
272
if (popup_id != DisplayServer::INVALID_WINDOW_ID) {
273
Window *popup_w = Window::get_from_id(popup_id);
274
if (popup_w && w_this->is_ancestor_of(popup_w)) {
275
w_this = popup_w;
276
}
277
}
278
279
RID new_focus_element;
280
Control *n_focus = w_this->gui_get_focus_owner();
281
if (n_focus && !n_focus->is_part_of_edited_scene()) {
282
new_focus_element = n_focus->get_focused_accessibility_element();
283
} else {
284
new_focus_element = w_this->get_focused_accessibility_element();
285
}
286
287
DisplayServer::get_singleton()->accessibility_update_set_focus(new_focus_element);
288
}
289
290
// Cleanup.
291
for (const ObjectID &id : processed) {
292
accessibility_change_queue.erase(id);
293
}
294
}
295
296
void SceneTree::_flush_accessibility_changes() {
297
if (is_accessibility_enabled()) {
298
uint64_t time = OS::get_singleton()->get_ticks_msec();
299
if (!accessibility_force_update) {
300
if (time - accessibility_last_update < 1000 / accessibility_upd_per_sec) {
301
return;
302
}
303
}
304
accessibility_force_update = false;
305
accessibility_last_update = time;
306
307
// Push update to the accessibility driver.
308
DisplayServer::get_singleton()->accessibility_update_if_active(callable_mp(this, &SceneTree::_process_accessibility_changes));
309
}
310
}
311
312
void SceneTree::_flush_ugc() {
313
ugc_locked = true;
314
315
while (unique_group_calls.size()) {
316
HashMap<UGCall, Vector<Variant>, UGCall>::Iterator E = unique_group_calls.begin();
317
318
const Variant **argptrs = (const Variant **)alloca(E->value.size() * sizeof(Variant *));
319
320
for (int i = 0; i < E->value.size(); i++) {
321
argptrs[i] = &E->value[i];
322
}
323
324
call_group_flagsp(GROUP_CALL_DEFAULT, E->key.group, E->key.call, argptrs, E->value.size());
325
326
unique_group_calls.remove(E);
327
}
328
329
ugc_locked = false;
330
}
331
332
void SceneTree::_update_group_order(Group &g) {
333
if (!g.changed) {
334
return;
335
}
336
if (g.nodes.is_empty()) {
337
return;
338
}
339
340
Node **gr_nodes = g.nodes.ptrw();
341
int gr_node_count = g.nodes.size();
342
343
SortArray<Node *, Node::Comparator> node_sort;
344
node_sort.sort(gr_nodes, gr_node_count);
345
346
g.changed = false;
347
}
348
349
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) {
350
Vector<Node *> nodes_copy;
351
352
{
353
_THREAD_SAFE_METHOD_
354
355
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
356
if (!E) {
357
return;
358
}
359
Group &g = E->value;
360
if (g.nodes.is_empty()) {
361
return;
362
}
363
364
if (p_call_flags & GROUP_CALL_UNIQUE && p_call_flags & GROUP_CALL_DEFERRED) {
365
ERR_FAIL_COND(ugc_locked);
366
367
UGCall ug;
368
ug.call = p_function;
369
ug.group = p_group;
370
371
if (unique_group_calls.has(ug)) {
372
return;
373
}
374
375
Vector<Variant> args;
376
for (int i = 0; i < p_argcount; i++) {
377
args.push_back(*p_args[i]);
378
}
379
380
unique_group_calls[ug] = args;
381
return;
382
}
383
384
_update_group_order(g);
385
nodes_copy = g.nodes;
386
}
387
388
Node **gr_nodes = nodes_copy.ptrw();
389
int gr_node_count = nodes_copy.size();
390
391
{
392
_THREAD_SAFE_METHOD_
393
nodes_removed_on_group_call_lock++;
394
}
395
396
if (p_call_flags & GROUP_CALL_REVERSE) {
397
for (int i = gr_node_count - 1; i >= 0; i--) {
398
if (nodes_removed_on_group_call_lock && nodes_removed_on_group_call.has(gr_nodes[i])) {
399
continue;
400
}
401
402
Node *node = gr_nodes[i];
403
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
404
Callable::CallError ce;
405
node->callp(p_function, p_args, p_argcount, ce);
406
if (unlikely(ce.error != Callable::CallError::CALL_OK && ce.error != Callable::CallError::CALL_ERROR_INVALID_METHOD)) {
407
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)));
408
}
409
} else {
410
MessageQueue::get_singleton()->push_callp(node, p_function, p_args, p_argcount);
411
}
412
}
413
414
} else {
415
for (int i = 0; i < gr_node_count; i++) {
416
if (nodes_removed_on_group_call_lock && nodes_removed_on_group_call.has(gr_nodes[i])) {
417
continue;
418
}
419
420
Node *node = gr_nodes[i];
421
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
422
Callable::CallError ce;
423
node->callp(p_function, p_args, p_argcount, ce);
424
if (unlikely(ce.error != Callable::CallError::CALL_OK && ce.error != Callable::CallError::CALL_ERROR_INVALID_METHOD)) {
425
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)));
426
}
427
} else {
428
MessageQueue::get_singleton()->push_callp(node, p_function, p_args, p_argcount);
429
}
430
}
431
}
432
433
{
434
_THREAD_SAFE_METHOD_
435
nodes_removed_on_group_call_lock--;
436
if (nodes_removed_on_group_call_lock == 0) {
437
nodes_removed_on_group_call.clear();
438
}
439
}
440
}
441
442
void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification) {
443
Vector<Node *> nodes_copy;
444
{
445
_THREAD_SAFE_METHOD_
446
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
447
if (!E) {
448
return;
449
}
450
Group &g = E->value;
451
if (g.nodes.is_empty()) {
452
return;
453
}
454
455
_update_group_order(g);
456
457
nodes_copy = g.nodes;
458
}
459
460
Node **gr_nodes = nodes_copy.ptrw();
461
int gr_node_count = nodes_copy.size();
462
463
{
464
_THREAD_SAFE_METHOD_
465
nodes_removed_on_group_call_lock++;
466
}
467
468
if (p_call_flags & GROUP_CALL_REVERSE) {
469
for (int i = gr_node_count - 1; i >= 0; i--) {
470
if (nodes_removed_on_group_call.has(gr_nodes[i])) {
471
continue;
472
}
473
474
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
475
gr_nodes[i]->notification(p_notification, true);
476
} else {
477
MessageQueue::get_singleton()->push_notification(gr_nodes[i], p_notification);
478
}
479
}
480
481
} else {
482
for (int i = 0; i < gr_node_count; i++) {
483
if (nodes_removed_on_group_call.has(gr_nodes[i])) {
484
continue;
485
}
486
487
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
488
gr_nodes[i]->notification(p_notification);
489
} else {
490
MessageQueue::get_singleton()->push_notification(gr_nodes[i], p_notification);
491
}
492
}
493
}
494
495
{
496
_THREAD_SAFE_METHOD_
497
nodes_removed_on_group_call_lock--;
498
if (nodes_removed_on_group_call_lock == 0) {
499
nodes_removed_on_group_call.clear();
500
}
501
}
502
}
503
504
void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value) {
505
Vector<Node *> nodes_copy;
506
{
507
_THREAD_SAFE_METHOD_
508
509
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
510
if (!E) {
511
return;
512
}
513
Group &g = E->value;
514
if (g.nodes.is_empty()) {
515
return;
516
}
517
518
_update_group_order(g);
519
520
nodes_copy = g.nodes;
521
}
522
Node **gr_nodes = nodes_copy.ptrw();
523
int gr_node_count = nodes_copy.size();
524
525
{
526
_THREAD_SAFE_METHOD_
527
nodes_removed_on_group_call_lock++;
528
}
529
530
if (p_call_flags & GROUP_CALL_REVERSE) {
531
for (int i = gr_node_count - 1; i >= 0; i--) {
532
if (nodes_removed_on_group_call.has(gr_nodes[i])) {
533
continue;
534
}
535
536
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
537
gr_nodes[i]->set(p_name, p_value);
538
} else {
539
MessageQueue::get_singleton()->push_set(gr_nodes[i], p_name, p_value);
540
}
541
}
542
543
} else {
544
for (int i = 0; i < gr_node_count; i++) {
545
if (nodes_removed_on_group_call.has(gr_nodes[i])) {
546
continue;
547
}
548
549
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
550
gr_nodes[i]->set(p_name, p_value);
551
} else {
552
MessageQueue::get_singleton()->push_set(gr_nodes[i], p_name, p_value);
553
}
554
}
555
}
556
557
{
558
_THREAD_SAFE_METHOD_
559
nodes_removed_on_group_call_lock--;
560
if (nodes_removed_on_group_call_lock == 0) {
561
nodes_removed_on_group_call.clear();
562
}
563
}
564
}
565
566
void SceneTree::notify_group(const StringName &p_group, int p_notification) {
567
notify_group_flags(GROUP_CALL_DEFAULT, p_group, p_notification);
568
}
569
570
void SceneTree::set_group(const StringName &p_group, const String &p_name, const Variant &p_value) {
571
set_group_flags(GROUP_CALL_DEFAULT, p_group, p_name, p_value);
572
}
573
574
void SceneTree::initialize() {
575
ERR_FAIL_NULL(root);
576
MainLoop::initialize();
577
root->_set_tree(this);
578
}
579
580
void SceneTree::set_physics_interpolation_enabled(bool p_enabled) {
581
// This version is for use in editor.
582
_physics_interpolation_enabled_in_project = p_enabled;
583
584
// We never want interpolation in the editor.
585
if (Engine::get_singleton()->is_editor_hint()) {
586
p_enabled = false;
587
}
588
589
if (p_enabled == _physics_interpolation_enabled) {
590
return;
591
}
592
593
_physics_interpolation_enabled = p_enabled;
594
RenderingServer::get_singleton()->set_physics_interpolation_enabled(p_enabled);
595
596
get_scene_tree_fti().set_enabled(get_root(), p_enabled);
597
598
// Perform an auto reset on the root node for convenience for the user.
599
if (root) {
600
root->reset_physics_interpolation();
601
}
602
}
603
604
#ifndef _3D_DISABLED
605
void SceneTree::client_physics_interpolation_add_node_3d(SelfList<Node3D> *p_elem) {
606
// This ensures that _update_physics_interpolation_data() will be called at least once every
607
// physics tick, to ensure the previous and current transforms are kept up to date.
608
_client_physics_interpolation._node_3d_list.add(p_elem);
609
}
610
611
void SceneTree::client_physics_interpolation_remove_node_3d(SelfList<Node3D> *p_elem) {
612
_client_physics_interpolation._node_3d_list.remove(p_elem);
613
}
614
#endif
615
616
void SceneTree::iteration_prepare() {
617
if (_physics_interpolation_enabled) {
618
// Make sure any pending transforms from the last tick / frame
619
// are flushed before pumping the interpolation prev and currents.
620
flush_transform_notifications();
621
get_scene_tree_fti().tick_update();
622
RenderingServer::get_singleton()->tick();
623
}
624
}
625
626
bool SceneTree::physics_process(double p_time) {
627
current_frame++;
628
629
flush_transform_notifications();
630
631
if (MainLoop::physics_process(p_time)) {
632
_quit = true;
633
}
634
physics_process_time = p_time;
635
636
emit_signal(SNAME("physics_frame"));
637
638
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
639
call_group(SNAME("_picking_viewports"), SNAME("_process_picking"));
640
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
641
642
_process(true);
643
644
_flush_ugc();
645
MessageQueue::get_singleton()->flush(); //small little hack
646
647
process_timers(p_time, true); //go through timers
648
process_tweens(p_time, true);
649
650
flush_transform_notifications();
651
652
// This should happen last because any processing that deletes something beforehand might expect the object to be removed in the same frame.
653
_flush_delete_queue();
654
655
_call_idle_callbacks();
656
657
return _quit;
658
}
659
660
void SceneTree::iteration_end() {
661
// When physics interpolation is active, we want all pending transforms
662
// to be flushed to the RenderingServer before finishing a physics tick.
663
if (_physics_interpolation_enabled) {
664
flush_transform_notifications();
665
666
#ifndef _3D_DISABLED
667
// Any objects performing client physics interpolation
668
// should be given an opportunity to keep their previous transforms
669
// up to date.
670
_client_physics_interpolation.physics_process();
671
#endif
672
}
673
}
674
675
bool SceneTree::process(double p_time) {
676
// First pass of scene tree fixed timestep interpolation.
677
if (get_scene_tree_fti().is_enabled()) {
678
// Special, we need to ensure RenderingServer is up to date
679
// with *all* the pending xforms *before* updating it during
680
// the FTI update.
681
// If this is not done, we can end up with a deferred `set_transform()`
682
// overwriting the interpolated xform in the server.
683
flush_transform_notifications();
684
get_scene_tree_fti().frame_update(get_root(), true);
685
}
686
687
if (MainLoop::process(p_time)) {
688
_quit = true;
689
}
690
691
process_time = p_time;
692
693
if (multiplayer_poll) {
694
multiplayer->poll();
695
for (KeyValue<NodePath, Ref<MultiplayerAPI>> &E : custom_multiplayers) {
696
E.value->poll();
697
}
698
}
699
700
emit_signal(SNAME("process_frame"));
701
702
MessageQueue::get_singleton()->flush(); //small little hack
703
704
flush_transform_notifications();
705
706
_process(false);
707
708
_flush_ugc();
709
MessageQueue::get_singleton()->flush(); //small little hack
710
flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications
711
712
if (unlikely(pending_new_scene_id.is_valid())) {
713
_flush_scene_change();
714
}
715
716
process_timers(p_time, false); //go through timers
717
process_tweens(p_time, false);
718
719
flush_transform_notifications(); // Additional transforms after timers update.
720
721
// This should happen last because any processing that deletes something beforehand might expect the object to be removed in the same frame.
722
_flush_delete_queue();
723
724
_flush_accessibility_changes();
725
726
_call_idle_callbacks();
727
728
#ifdef TOOLS_ENABLED
729
#ifndef _3D_DISABLED
730
if (Engine::get_singleton()->is_editor_hint()) {
731
String env_path = GLOBAL_GET("rendering/environment/defaults/default_environment");
732
env_path = env_path.strip_edges(); // User may have added a space or two.
733
734
bool can_load = true;
735
if (env_path.begins_with("uid://")) {
736
// If an uid path, ensure it is mapped to a resource which could not be
737
// the case if the editor is still scanning the filesystem.
738
ResourceUID::ID id = ResourceUID::get_singleton()->text_to_id(env_path);
739
can_load = ResourceUID::get_singleton()->has_id(id);
740
if (can_load) {
741
env_path = ResourceUID::get_singleton()->get_id_path(id);
742
}
743
}
744
745
if (can_load) {
746
String cpath;
747
Ref<Environment> fallback = get_root()->get_world_3d()->get_fallback_environment();
748
if (fallback.is_valid()) {
749
cpath = fallback->get_path();
750
}
751
if (cpath != env_path) {
752
if (!env_path.is_empty()) {
753
fallback = ResourceLoader::load(env_path);
754
if (fallback.is_null()) {
755
//could not load fallback, set as empty
756
ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
757
}
758
} else {
759
fallback.unref();
760
}
761
get_root()->get_world_3d()->set_fallback_environment(fallback);
762
}
763
}
764
}
765
#endif // _3D_DISABLED
766
#endif // TOOLS_ENABLED
767
768
// Second pass of scene tree fixed timestep interpolation.
769
// ToDo: Possibly needs another flush_transform_notifications here
770
// depending on whether there are side effects to _call_idle_callbacks().
771
get_scene_tree_fti().frame_update(get_root(), false);
772
773
if (_physics_interpolation_enabled) {
774
RenderingServer::get_singleton()->pre_draw(true);
775
}
776
777
return _quit;
778
}
779
780
void SceneTree::process_timers(double p_delta, bool p_physics_frame) {
781
_THREAD_SAFE_METHOD_
782
const List<Ref<SceneTreeTimer>>::Element *L = timers.back(); // Last element.
783
const double unscaled_delta = Engine::get_singleton()->get_process_step();
784
785
for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) {
786
List<Ref<SceneTreeTimer>>::Element *N = E->next();
787
Ref<SceneTreeTimer> timer = E->get();
788
789
if ((paused && !timer->is_process_always()) || (timer->is_process_in_physics() != p_physics_frame)) {
790
if (E == L) {
791
break; // Break on last, so if new timers were added during list traversal, ignore them.
792
}
793
E = N;
794
continue;
795
}
796
797
double time_left = timer->get_time_left();
798
time_left -= timer->is_ignoring_time_scale() ? unscaled_delta : p_delta;
799
timer->set_time_left(time_left);
800
801
if (time_left <= 0) {
802
E->get()->emit_signal(SNAME("timeout"));
803
timers.erase(E);
804
}
805
if (E == L) {
806
break; // Break on last, so if new timers were added during list traversal, ignore them.
807
}
808
E = N;
809
}
810
}
811
812
void SceneTree::process_tweens(double p_delta, bool p_physics) {
813
_THREAD_SAFE_METHOD_
814
// This methods works similarly to how SceneTreeTimers are handled.
815
const List<Ref<Tween>>::Element *L = tweens.back();
816
const double unscaled_delta = Engine::get_singleton()->get_process_step();
817
818
for (List<Ref<Tween>>::Element *E = tweens.front(); E;) {
819
List<Ref<Tween>>::Element *N = E->next();
820
Ref<Tween> &tween = E->get();
821
822
// Don't process if paused or process mode doesn't match.
823
if (!tween->can_process(paused) || (p_physics == (tween->get_process_mode() == Tween::TWEEN_PROCESS_IDLE))) {
824
if (E == L) {
825
break;
826
}
827
E = N;
828
continue;
829
}
830
831
if (!tween->step(tween->is_ignoring_time_scale() ? unscaled_delta : p_delta)) {
832
tween->clear();
833
tweens.erase(E);
834
}
835
if (E == L) {
836
break;
837
}
838
E = N;
839
}
840
}
841
842
void SceneTree::finalize() {
843
_flush_delete_queue();
844
845
_flush_ugc();
846
847
if (root) {
848
root->_set_tree(nullptr);
849
root->_propagate_after_exit_tree();
850
memdelete(root); //delete root
851
root = nullptr;
852
853
// In case deletion of some objects was queued when destructing the `root`.
854
// E.g. if `queue_free()` was called for some node outside the tree when handling NOTIFICATION_PREDELETE for some node in the tree.
855
_flush_delete_queue();
856
}
857
858
MainLoop::finalize();
859
860
// Cleanup timers.
861
for (Ref<SceneTreeTimer> &timer : timers) {
862
timer->release_connections();
863
}
864
timers.clear();
865
866
// Cleanup tweens.
867
for (Ref<Tween> &tween : tweens) {
868
tween->clear();
869
}
870
tweens.clear();
871
}
872
873
void SceneTree::quit(int p_exit_code) {
874
_THREAD_SAFE_METHOD_
875
876
OS::get_singleton()->set_exit_code(p_exit_code);
877
_quit = true;
878
}
879
880
void SceneTree::_main_window_close() {
881
if (accept_quit) {
882
_quit = true;
883
}
884
}
885
886
void SceneTree::_main_window_go_back() {
887
if (quit_on_go_back) {
888
_quit = true;
889
}
890
}
891
892
void SceneTree::_main_window_focus_in() {
893
Input *id = Input::get_singleton();
894
if (id) {
895
id->ensure_touch_mouse_raised();
896
}
897
}
898
899
void SceneTree::_notification(int p_notification) {
900
if (!get_root()) {
901
return;
902
}
903
904
switch (p_notification) {
905
case NOTIFICATION_TRANSLATION_CHANGED: {
906
get_root()->propagate_notification(p_notification);
907
} break;
908
909
case NOTIFICATION_OS_MEMORY_WARNING:
910
case NOTIFICATION_OS_IME_UPDATE:
911
case NOTIFICATION_WM_ABOUT:
912
case NOTIFICATION_CRASH:
913
case NOTIFICATION_APPLICATION_RESUMED:
914
case NOTIFICATION_APPLICATION_PAUSED:
915
case NOTIFICATION_APPLICATION_FOCUS_IN:
916
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
917
// Pass these to nodes, since they are mirrored.
918
get_root()->propagate_notification(p_notification);
919
} break;
920
}
921
}
922
923
bool SceneTree::is_auto_accept_quit() const {
924
return accept_quit;
925
}
926
927
void SceneTree::set_auto_accept_quit(bool p_enable) {
928
accept_quit = p_enable;
929
}
930
931
bool SceneTree::is_quit_on_go_back() const {
932
return quit_on_go_back;
933
}
934
935
void SceneTree::set_quit_on_go_back(bool p_enable) {
936
quit_on_go_back = p_enable;
937
}
938
939
#ifdef DEBUG_ENABLED
940
void SceneTree::set_debug_collisions_hint(bool p_enabled) {
941
debug_collisions_hint = p_enabled;
942
}
943
944
bool SceneTree::is_debugging_collisions_hint() const {
945
return debug_collisions_hint;
946
}
947
948
void SceneTree::set_debug_paths_hint(bool p_enabled) {
949
debug_paths_hint = p_enabled;
950
}
951
952
bool SceneTree::is_debugging_paths_hint() const {
953
return debug_paths_hint;
954
}
955
956
void SceneTree::set_debug_navigation_hint(bool p_enabled) {
957
debug_navigation_hint = p_enabled;
958
}
959
960
bool SceneTree::is_debugging_navigation_hint() const {
961
return debug_navigation_hint;
962
}
963
#endif
964
965
void SceneTree::set_debug_collisions_color(const Color &p_color) {
966
debug_collisions_color = p_color;
967
}
968
969
Color SceneTree::get_debug_collisions_color() const {
970
return debug_collisions_color;
971
}
972
973
void SceneTree::set_debug_collision_contact_color(const Color &p_color) {
974
debug_collision_contact_color = p_color;
975
}
976
977
Color SceneTree::get_debug_collision_contact_color() const {
978
return debug_collision_contact_color;
979
}
980
981
void SceneTree::set_debug_paths_color(const Color &p_color) {
982
debug_paths_color = p_color;
983
}
984
985
Color SceneTree::get_debug_paths_color() const {
986
return debug_paths_color;
987
}
988
989
void SceneTree::set_debug_paths_width(float p_width) {
990
debug_paths_width = p_width;
991
}
992
993
float SceneTree::get_debug_paths_width() const {
994
return debug_paths_width;
995
}
996
997
Ref<Material> SceneTree::get_debug_paths_material() {
998
_THREAD_SAFE_METHOD_
999
1000
if (debug_paths_material.is_valid()) {
1001
return debug_paths_material;
1002
}
1003
1004
Ref<StandardMaterial3D> _debug_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
1005
_debug_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
1006
_debug_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
1007
_debug_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
1008
_debug_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
1009
_debug_material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
1010
_debug_material->set_albedo(get_debug_paths_color());
1011
1012
debug_paths_material = _debug_material;
1013
1014
return debug_paths_material;
1015
}
1016
1017
Ref<Material> SceneTree::get_debug_collision_material() {
1018
_THREAD_SAFE_METHOD_
1019
1020
if (collision_material.is_valid()) {
1021
return collision_material;
1022
}
1023
1024
Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
1025
material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
1026
material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
1027
material->set_render_priority(StandardMaterial3D::RENDER_PRIORITY_MIN + 1);
1028
material->set_cull_mode(StandardMaterial3D::CULL_BACK);
1029
material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
1030
material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
1031
material->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
1032
1033
collision_material = material;
1034
1035
return collision_material;
1036
}
1037
1038
Ref<ArrayMesh> SceneTree::get_debug_contact_mesh() {
1039
_THREAD_SAFE_METHOD_
1040
1041
if (debug_contact_mesh.is_valid()) {
1042
return debug_contact_mesh;
1043
}
1044
1045
debug_contact_mesh.instantiate();
1046
1047
Ref<StandardMaterial3D> mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
1048
mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
1049
mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
1050
mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
1051
mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
1052
mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
1053
mat->set_albedo(get_debug_collision_contact_color());
1054
1055
Vector3 diamond[6] = {
1056
Vector3(-1, 0, 0),
1057
Vector3(1, 0, 0),
1058
Vector3(0, -1, 0),
1059
Vector3(0, 1, 0),
1060
Vector3(0, 0, -1),
1061
Vector3(0, 0, 1)
1062
};
1063
1064
/* clang-format off */
1065
int diamond_faces[8 * 3] = {
1066
0, 2, 4,
1067
0, 3, 4,
1068
1, 2, 4,
1069
1, 3, 4,
1070
0, 2, 5,
1071
0, 3, 5,
1072
1, 2, 5,
1073
1, 3, 5,
1074
};
1075
/* clang-format on */
1076
1077
Vector<int> indices;
1078
for (int i = 0; i < 8 * 3; i++) {
1079
indices.push_back(diamond_faces[i]);
1080
}
1081
1082
Vector<Vector3> vertices;
1083
for (int i = 0; i < 6; i++) {
1084
vertices.push_back(diamond[i] * 0.1);
1085
}
1086
1087
Array arr;
1088
arr.resize(Mesh::ARRAY_MAX);
1089
arr[Mesh::ARRAY_VERTEX] = vertices;
1090
arr[Mesh::ARRAY_INDEX] = indices;
1091
1092
debug_contact_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr);
1093
debug_contact_mesh->surface_set_material(0, mat);
1094
1095
return debug_contact_mesh;
1096
}
1097
1098
void SceneTree::set_pause(bool p_enabled) {
1099
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Pause can only be set from the main thread.");
1100
ERR_FAIL_COND_MSG(suspended, "Pause state cannot be modified while suspended.");
1101
1102
if (p_enabled == paused) {
1103
return;
1104
}
1105
1106
paused = p_enabled;
1107
1108
#ifndef PHYSICS_3D_DISABLED
1109
PhysicsServer3D::get_singleton()->set_active(!p_enabled);
1110
#endif // PHYSICS_3D_DISABLED
1111
#ifndef PHYSICS_2D_DISABLED
1112
PhysicsServer2D::get_singleton()->set_active(!p_enabled);
1113
#endif // PHYSICS_2D_DISABLED
1114
if (get_root()) {
1115
get_root()->_propagate_pause_notification(p_enabled);
1116
}
1117
}
1118
1119
bool SceneTree::is_paused() const {
1120
return paused;
1121
}
1122
1123
void SceneTree::set_suspend(bool p_enabled) {
1124
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Suspend can only be set from the main thread.");
1125
1126
if (p_enabled == suspended) {
1127
return;
1128
}
1129
1130
suspended = p_enabled;
1131
1132
Engine::get_singleton()->set_freeze_time_scale(p_enabled);
1133
1134
#ifndef PHYSICS_3D_DISABLED
1135
PhysicsServer3D::get_singleton()->set_active(!p_enabled && !paused);
1136
#endif // PHYSICS_3D_DISABLED
1137
#ifndef PHYSICS_2D_DISABLED
1138
PhysicsServer2D::get_singleton()->set_active(!p_enabled && !paused);
1139
#endif // PHYSICS_2D_DISABLED
1140
if (get_root()) {
1141
get_root()->_propagate_suspend_notification(p_enabled);
1142
}
1143
}
1144
1145
bool SceneTree::is_suspended() const {
1146
return suspended;
1147
}
1148
1149
void SceneTree::_process_group(ProcessGroup *p_group, bool p_physics) {
1150
// When reading this function, keep in mind that this code must work in a way where
1151
// if any node is removed, this needs to continue working.
1152
1153
p_group->call_queue.flush(); // Flush messages before processing.
1154
1155
Vector<Node *> &nodes = p_physics ? p_group->physics_nodes : p_group->nodes;
1156
if (nodes.is_empty()) {
1157
return;
1158
}
1159
1160
if (p_physics) {
1161
if (p_group->physics_node_order_dirty) {
1162
nodes.sort_custom<Node::ComparatorWithPhysicsPriority>();
1163
p_group->physics_node_order_dirty = false;
1164
}
1165
} else {
1166
if (p_group->node_order_dirty) {
1167
nodes.sort_custom<Node::ComparatorWithPriority>();
1168
p_group->node_order_dirty = false;
1169
}
1170
}
1171
1172
// Make a copy, so if nodes are added/removed from process, this does not break
1173
Vector<Node *> nodes_copy = nodes;
1174
1175
uint32_t node_count = nodes_copy.size();
1176
Node **nodes_ptr = (Node **)nodes_copy.ptr(); // Force cast, pointer will not change.
1177
1178
for (uint32_t i = 0; i < node_count; i++) {
1179
Node *n = nodes_ptr[i];
1180
if (nodes_removed_on_group_call.has(n)) {
1181
// Node may have been removed during process, skip it.
1182
// Keep in mind removals can only happen on the main thread.
1183
continue;
1184
}
1185
1186
if (!n->can_process() || !n->is_inside_tree()) {
1187
continue;
1188
}
1189
1190
if (p_physics) {
1191
if (n->is_physics_processing_internal()) {
1192
n->notification(Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
1193
}
1194
if (n->is_physics_processing()) {
1195
n->notification(Node::NOTIFICATION_PHYSICS_PROCESS);
1196
}
1197
} else {
1198
if (n->is_processing_internal()) {
1199
n->notification(Node::NOTIFICATION_INTERNAL_PROCESS);
1200
}
1201
if (n->is_processing()) {
1202
n->notification(Node::NOTIFICATION_PROCESS);
1203
}
1204
}
1205
}
1206
1207
p_group->call_queue.flush(); // Flush messages also after processing (for potential deferred calls).
1208
}
1209
1210
void SceneTree::_process_groups_thread(uint32_t p_index, bool p_physics) {
1211
Node::current_process_thread_group = local_process_group_cache[p_index]->owner;
1212
_process_group(local_process_group_cache[p_index], p_physics);
1213
Node::current_process_thread_group = nullptr;
1214
}
1215
1216
void SceneTree::_process(bool p_physics) {
1217
if (process_groups_dirty) {
1218
{
1219
// First, remove dirty groups.
1220
// This needs to be done when not processing to avoid problems.
1221
ProcessGroup **pg_ptr = (ProcessGroup **)process_groups.ptr(); // discard constness.
1222
uint32_t pg_count = process_groups.size();
1223
1224
for (uint32_t i = 0; i < pg_count; i++) {
1225
if (pg_ptr[i]->removed) {
1226
// Replace removed with last.
1227
pg_ptr[i] = pg_ptr[pg_count - 1];
1228
// Retry
1229
i--;
1230
pg_count--;
1231
}
1232
}
1233
if (pg_count != process_groups.size()) {
1234
process_groups.resize(pg_count);
1235
}
1236
}
1237
{
1238
// Then, re-sort groups.
1239
process_groups.sort_custom<ProcessGroupSort>();
1240
}
1241
1242
process_groups_dirty = false;
1243
}
1244
1245
// Cache the group count, because during processing new groups may be added.
1246
// They will be added at the end, hence for consistency they will be ignored by this process loop.
1247
// No group will be removed from the array during processing (this is done earlier in this function by marking the groups dirty).
1248
uint32_t group_count = process_groups.size();
1249
1250
if (group_count == 0) {
1251
return;
1252
}
1253
1254
process_last_pass++; // Increment pass
1255
uint32_t from = 0;
1256
uint32_t process_count = 0;
1257
nodes_removed_on_group_call_lock++;
1258
1259
int current_order = process_groups[0]->owner ? process_groups[0]->owner->data.process_thread_group_order : 0;
1260
bool current_threaded = process_groups[0]->owner ? process_groups[0]->owner->data.process_thread_group == Node::PROCESS_THREAD_GROUP_SUB_THREAD : false;
1261
1262
for (uint32_t i = 0; i <= group_count; i++) {
1263
int order = i < group_count && process_groups[i]->owner ? process_groups[i]->owner->data.process_thread_group_order : 0;
1264
bool threaded = i < group_count && process_groups[i]->owner ? process_groups[i]->owner->data.process_thread_group == Node::PROCESS_THREAD_GROUP_SUB_THREAD : false;
1265
1266
if (i == group_count || current_order != order || current_threaded != threaded) {
1267
if (process_count > 0) {
1268
// Proceed to process the group.
1269
bool using_threads = process_groups[from]->owner && process_groups[from]->owner->data.process_thread_group == Node::PROCESS_THREAD_GROUP_SUB_THREAD && !node_threading_disabled;
1270
1271
if (using_threads) {
1272
local_process_group_cache.clear();
1273
}
1274
for (uint32_t j = from; j < i; j++) {
1275
if (process_groups[j]->last_pass == process_last_pass) {
1276
if (using_threads) {
1277
local_process_group_cache.push_back(process_groups[j]);
1278
} else {
1279
_process_group(process_groups[j], p_physics);
1280
}
1281
}
1282
}
1283
1284
if (using_threads) {
1285
WorkerThreadPool::GroupID id = WorkerThreadPool::get_singleton()->add_template_group_task(this, &SceneTree::_process_groups_thread, p_physics, local_process_group_cache.size(), -1, true);
1286
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(id);
1287
}
1288
}
1289
1290
if (i == group_count) {
1291
// This one is invalid, no longer process
1292
break;
1293
}
1294
1295
from = i;
1296
current_threaded = threaded;
1297
current_order = order;
1298
}
1299
1300
if (process_groups[i]->removed) {
1301
continue;
1302
}
1303
1304
ProcessGroup *pg = process_groups[i];
1305
1306
// Validate group for processing
1307
bool process_valid = false;
1308
if (p_physics) {
1309
if (!pg->physics_nodes.is_empty()) {
1310
process_valid = true;
1311
} 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()) {
1312
process_valid = true;
1313
}
1314
} else {
1315
if (!pg->nodes.is_empty()) {
1316
process_valid = true;
1317
} 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()) {
1318
process_valid = true;
1319
}
1320
}
1321
1322
if (process_valid) {
1323
pg->last_pass = process_last_pass; // Enable for processing
1324
process_count++;
1325
}
1326
}
1327
1328
nodes_removed_on_group_call_lock--;
1329
if (nodes_removed_on_group_call_lock == 0) {
1330
nodes_removed_on_group_call.clear();
1331
}
1332
}
1333
1334
bool SceneTree::ProcessGroupSort::operator()(const ProcessGroup *p_left, const ProcessGroup *p_right) const {
1335
int left_order = p_left->owner ? p_left->owner->data.process_thread_group_order : 0;
1336
int right_order = p_right->owner ? p_right->owner->data.process_thread_group_order : 0;
1337
1338
if (left_order == right_order) {
1339
int left_threaded = p_left->owner != nullptr && p_left->owner->data.process_thread_group == Node::PROCESS_THREAD_GROUP_SUB_THREAD ? 0 : 1;
1340
int right_threaded = p_right->owner != nullptr && p_right->owner->data.process_thread_group == Node::PROCESS_THREAD_GROUP_SUB_THREAD ? 0 : 1;
1341
return left_threaded < right_threaded;
1342
} else {
1343
return left_order < right_order;
1344
}
1345
}
1346
1347
void SceneTree::_remove_process_group(Node *p_node) {
1348
_THREAD_SAFE_METHOD_
1349
ProcessGroup *pg = (ProcessGroup *)p_node->data.process_group;
1350
ERR_FAIL_NULL(pg);
1351
ERR_FAIL_COND(pg->removed);
1352
pg->removed = true;
1353
pg->owner = nullptr;
1354
p_node->data.process_group = nullptr;
1355
process_groups_dirty = true;
1356
}
1357
1358
void SceneTree::_add_process_group(Node *p_node) {
1359
_THREAD_SAFE_METHOD_
1360
ERR_FAIL_NULL(p_node);
1361
1362
ProcessGroup *pg = memnew(ProcessGroup);
1363
1364
pg->owner = p_node;
1365
p_node->data.process_group = pg;
1366
1367
process_groups.push_back(pg);
1368
1369
process_groups_dirty = true;
1370
}
1371
1372
void SceneTree::_remove_node_from_process_group(Node *p_node, Node *p_owner) {
1373
_THREAD_SAFE_METHOD_
1374
ProcessGroup *pg = p_owner ? (ProcessGroup *)p_owner->data.process_group : &default_process_group;
1375
1376
if (p_node->is_processing() || p_node->is_processing_internal()) {
1377
bool found = pg->nodes.erase(p_node);
1378
ERR_FAIL_COND(!found);
1379
}
1380
1381
if (p_node->is_physics_processing() || p_node->is_physics_processing_internal()) {
1382
bool found = pg->physics_nodes.erase(p_node);
1383
ERR_FAIL_COND(!found);
1384
}
1385
}
1386
1387
void SceneTree::_add_node_to_process_group(Node *p_node, Node *p_owner) {
1388
_THREAD_SAFE_METHOD_
1389
ProcessGroup *pg = p_owner ? (ProcessGroup *)p_owner->data.process_group : &default_process_group;
1390
1391
if (p_node->is_processing() || p_node->is_processing_internal()) {
1392
pg->nodes.push_back(p_node);
1393
pg->node_order_dirty = true;
1394
}
1395
1396
if (p_node->is_physics_processing() || p_node->is_physics_processing_internal()) {
1397
pg->physics_nodes.push_back(p_node);
1398
pg->physics_node_order_dirty = true;
1399
}
1400
}
1401
1402
void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_call_type, const Ref<InputEvent> &p_input, Viewport *p_viewport) {
1403
Vector<Node *> nodes_copy;
1404
{
1405
_THREAD_SAFE_METHOD_
1406
1407
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
1408
if (!E) {
1409
return;
1410
}
1411
Group &g = E->value;
1412
if (g.nodes.is_empty()) {
1413
return;
1414
}
1415
1416
_update_group_order(g);
1417
1418
//copy, so copy on write happens in case something is removed from process while being called
1419
//performance is not lost because only if something is added/removed the vector is copied.
1420
nodes_copy = g.nodes;
1421
}
1422
1423
int gr_node_count = nodes_copy.size();
1424
Node **gr_nodes = nodes_copy.ptrw();
1425
1426
{
1427
_THREAD_SAFE_METHOD_
1428
nodes_removed_on_group_call_lock++;
1429
}
1430
1431
Vector<ObjectID> no_context_node_ids; // Nodes may be deleted due to this shortcut input.
1432
1433
for (int i = gr_node_count - 1; i >= 0; i--) {
1434
if (p_viewport->is_input_handled()) {
1435
break;
1436
}
1437
1438
Node *n = gr_nodes[i];
1439
if (nodes_removed_on_group_call.has(n)) {
1440
continue;
1441
}
1442
1443
if (!n->can_process()) {
1444
continue;
1445
}
1446
1447
switch (p_call_type) {
1448
case CALL_INPUT_TYPE_INPUT:
1449
n->_call_input(p_input);
1450
break;
1451
case CALL_INPUT_TYPE_SHORTCUT_INPUT: {
1452
const Control *c = Object::cast_to<Control>(n);
1453
if (c) {
1454
// If calling shortcut input on a control, ensure it respects the shortcut context.
1455
// Shortcut context (based on focus) only makes sense for controls (UI), so don't need to worry about it for nodes
1456
if (c->get_shortcut_context() == nullptr) {
1457
no_context_node_ids.append(n->get_instance_id());
1458
continue;
1459
}
1460
if (!c->is_focus_owner_in_shortcut_context()) {
1461
continue;
1462
}
1463
}
1464
n->_call_shortcut_input(p_input);
1465
break;
1466
}
1467
case CALL_INPUT_TYPE_UNHANDLED_INPUT:
1468
n->_call_unhandled_input(p_input);
1469
break;
1470
case CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT:
1471
n->_call_unhandled_key_input(p_input);
1472
break;
1473
}
1474
}
1475
1476
for (const ObjectID &id : no_context_node_ids) {
1477
if (p_viewport->is_input_handled()) {
1478
break;
1479
}
1480
Node *n = ObjectDB::get_instance<Node>(id);
1481
if (n) {
1482
n->_call_shortcut_input(p_input);
1483
}
1484
}
1485
1486
{
1487
_THREAD_SAFE_METHOD_
1488
nodes_removed_on_group_call_lock--;
1489
if (nodes_removed_on_group_call_lock == 0) {
1490
nodes_removed_on_group_call.clear();
1491
}
1492
}
1493
}
1494
1495
void SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
1496
r_error.error = Callable::CallError::CALL_OK;
1497
1498
ERR_FAIL_COND(p_argcount < 3);
1499
ERR_FAIL_COND(!p_args[0]->is_num());
1500
ERR_FAIL_COND(!p_args[1]->is_string());
1501
ERR_FAIL_COND(!p_args[2]->is_string());
1502
1503
int flags = *p_args[0];
1504
StringName group = *p_args[1];
1505
StringName method = *p_args[2];
1506
1507
call_group_flagsp(flags, group, method, p_args + 3, p_argcount - 3);
1508
}
1509
1510
void SceneTree::_call_group(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
1511
r_error.error = Callable::CallError::CALL_OK;
1512
1513
ERR_FAIL_COND(p_argcount < 2);
1514
ERR_FAIL_COND(!p_args[0]->is_string());
1515
ERR_FAIL_COND(!p_args[1]->is_string());
1516
1517
StringName group = *p_args[0];
1518
StringName method = *p_args[1];
1519
1520
call_group_flagsp(GROUP_CALL_DEFAULT, group, method, p_args + 2, p_argcount - 2);
1521
}
1522
1523
int64_t SceneTree::get_frame() const {
1524
return current_frame;
1525
}
1526
1527
TypedArray<Node> SceneTree::_get_nodes_in_group(const StringName &p_group) {
1528
_THREAD_SAFE_METHOD_
1529
TypedArray<Node> ret;
1530
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
1531
if (!E) {
1532
return ret;
1533
}
1534
1535
_update_group_order(E->value); //update order just in case
1536
int nc = E->value.nodes.size();
1537
if (nc == 0) {
1538
return ret;
1539
}
1540
1541
ret.resize(nc);
1542
1543
Node **ptr = E->value.nodes.ptrw();
1544
for (int i = 0; i < nc; i++) {
1545
ret[i] = ptr[i];
1546
}
1547
1548
return ret;
1549
}
1550
1551
bool SceneTree::has_group(const StringName &p_identifier) const {
1552
_THREAD_SAFE_METHOD_
1553
return group_map.has(p_identifier);
1554
}
1555
1556
int SceneTree::get_node_count_in_group(const StringName &p_group) const {
1557
_THREAD_SAFE_METHOD_
1558
HashMap<StringName, Group>::ConstIterator E = group_map.find(p_group);
1559
if (!E) {
1560
return 0;
1561
}
1562
1563
return E->value.nodes.size();
1564
}
1565
1566
Node *SceneTree::get_first_node_in_group(const StringName &p_group) {
1567
_THREAD_SAFE_METHOD_
1568
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
1569
if (!E) {
1570
return nullptr; // No group.
1571
}
1572
1573
_update_group_order(E->value); // Update order just in case.
1574
1575
if (E->value.nodes.is_empty()) {
1576
return nullptr;
1577
}
1578
1579
return E->value.nodes[0];
1580
}
1581
1582
void SceneTree::get_nodes_in_group(const StringName &p_group, List<Node *> *p_list) {
1583
_THREAD_SAFE_METHOD_
1584
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
1585
if (!E) {
1586
return;
1587
}
1588
1589
_update_group_order(E->value); //update order just in case
1590
int nc = E->value.nodes.size();
1591
if (nc == 0) {
1592
return;
1593
}
1594
Node **ptr = E->value.nodes.ptrw();
1595
for (int i = 0; i < nc; i++) {
1596
p_list->push_back(ptr[i]);
1597
}
1598
}
1599
1600
void SceneTree::_flush_delete_queue() {
1601
_THREAD_SAFE_METHOD_
1602
1603
while (delete_queue.size()) {
1604
Object *obj = ObjectDB::get_instance(delete_queue.front()->get());
1605
if (obj) {
1606
memdelete(obj);
1607
}
1608
delete_queue.pop_front();
1609
}
1610
}
1611
1612
void SceneTree::queue_delete(Object *p_object) {
1613
_THREAD_SAFE_METHOD_
1614
ERR_FAIL_NULL(p_object);
1615
p_object->_is_queued_for_deletion = true;
1616
delete_queue.push_back(p_object->get_instance_id());
1617
}
1618
1619
int SceneTree::get_node_count() const {
1620
return nodes_in_tree_count;
1621
}
1622
1623
void SceneTree::set_edited_scene_root(Node *p_node) {
1624
#ifdef TOOLS_ENABLED
1625
edited_scene_root = p_node;
1626
#endif
1627
}
1628
1629
Node *SceneTree::get_edited_scene_root() const {
1630
#ifdef TOOLS_ENABLED
1631
return edited_scene_root;
1632
#else
1633
return nullptr;
1634
#endif
1635
}
1636
1637
void SceneTree::set_current_scene(Node *p_scene) {
1638
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Changing scene can only be done from the main thread.");
1639
ERR_FAIL_COND(p_scene && p_scene->get_parent() != root);
1640
current_scene = p_scene;
1641
}
1642
1643
Node *SceneTree::get_current_scene() const {
1644
return current_scene;
1645
}
1646
1647
void SceneTree::_flush_scene_change() {
1648
if (prev_scene_id.is_valid()) {
1649
// Might have already been freed externally.
1650
Node *prev_scene = ObjectDB::get_instance<Node>(prev_scene_id);
1651
if (prev_scene) {
1652
memdelete(prev_scene);
1653
}
1654
prev_scene_id = ObjectID();
1655
}
1656
1657
DEV_ASSERT(pending_new_scene_id.is_valid());
1658
Node *pending_new_scene = ObjectDB::get_instance<Node>(pending_new_scene_id);
1659
if (pending_new_scene) {
1660
// Ensure correct state before `add_child` (might enqueue subsequent scene change).
1661
current_scene = pending_new_scene;
1662
pending_new_scene_id = ObjectID();
1663
1664
root->add_child(pending_new_scene);
1665
// Update display for cursor instantly.
1666
root->update_mouse_cursor_state();
1667
1668
// Only on successful scene change.
1669
emit_signal(SNAME("scene_changed"));
1670
} else {
1671
current_scene = nullptr;
1672
pending_new_scene_id = ObjectID();
1673
ERR_PRINT("Scene instance has been freed before becoming the current scene. No current scene is set.");
1674
}
1675
}
1676
1677
Error SceneTree::change_scene_to_file(const String &p_path) {
1678
ERR_FAIL_COND_V_MSG(!Thread::is_main_thread(), ERR_INVALID_PARAMETER, "Changing scene can only be done from the main thread.");
1679
Ref<PackedScene> new_scene = ResourceLoader::load(p_path);
1680
if (new_scene.is_null()) {
1681
return ERR_CANT_OPEN;
1682
}
1683
1684
return change_scene_to_packed(new_scene);
1685
}
1686
1687
Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) {
1688
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.");
1689
1690
Node *new_scene = p_scene->instantiate();
1691
ERR_FAIL_NULL_V(new_scene, ERR_CANT_CREATE);
1692
1693
// If called again while a change is pending.
1694
if (pending_new_scene_id.is_valid()) {
1695
Node *pending_new_scene = ObjectDB::get_instance<Node>(pending_new_scene_id);
1696
if (pending_new_scene) {
1697
queue_delete(pending_new_scene);
1698
}
1699
pending_new_scene_id = ObjectID();
1700
}
1701
1702
if (current_scene) {
1703
prev_scene_id = current_scene->get_instance_id();
1704
// Let as many side effects as possible happen or be queued now,
1705
// so they are run before the scene is actually deleted.
1706
root->remove_child(current_scene);
1707
}
1708
DEV_ASSERT(!current_scene);
1709
1710
pending_new_scene_id = new_scene->get_instance_id();
1711
return OK;
1712
}
1713
1714
Error SceneTree::reload_current_scene() {
1715
ERR_FAIL_COND_V_MSG(!Thread::is_main_thread(), ERR_INVALID_PARAMETER, "Reloading scene can only be done from the main thread.");
1716
ERR_FAIL_NULL_V(current_scene, ERR_UNCONFIGURED);
1717
String fname = current_scene->get_scene_file_path();
1718
return change_scene_to_file(fname);
1719
}
1720
1721
void SceneTree::unload_current_scene() {
1722
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Unloading the current scene can only be done from the main thread.");
1723
if (current_scene) {
1724
memdelete(current_scene);
1725
current_scene = nullptr;
1726
}
1727
}
1728
1729
void SceneTree::add_current_scene(Node *p_current) {
1730
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Adding a current scene can only be done from the main thread.");
1731
current_scene = p_current;
1732
root->add_child(p_current);
1733
}
1734
1735
Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always, bool p_process_in_physics, bool p_ignore_time_scale) {
1736
_THREAD_SAFE_METHOD_
1737
Ref<SceneTreeTimer> stt;
1738
stt.instantiate();
1739
stt->set_process_always(p_process_always);
1740
stt->set_time_left(p_delay_sec);
1741
stt->set_process_in_physics(p_process_in_physics);
1742
stt->set_ignore_time_scale(p_ignore_time_scale);
1743
timers.push_back(stt);
1744
return stt;
1745
}
1746
1747
Ref<Tween> SceneTree::create_tween() {
1748
_THREAD_SAFE_METHOD_
1749
Ref<Tween> tween;
1750
tween.instantiate(this);
1751
tweens.push_back(tween);
1752
return tween;
1753
}
1754
1755
void SceneTree::remove_tween(const Ref<Tween> &p_tween) {
1756
_THREAD_SAFE_METHOD_
1757
for (List<Ref<Tween>>::Element *E = tweens.back(); E; E = E->prev()) {
1758
if (E->get() == p_tween) {
1759
E->erase();
1760
break;
1761
}
1762
}
1763
}
1764
1765
TypedArray<Tween> SceneTree::get_processed_tweens() {
1766
_THREAD_SAFE_METHOD_
1767
TypedArray<Tween> ret;
1768
ret.resize(tweens.size());
1769
1770
int i = 0;
1771
for (const Ref<Tween> &tween : tweens) {
1772
ret[i] = tween;
1773
i++;
1774
}
1775
1776
return ret;
1777
}
1778
1779
Ref<MultiplayerAPI> SceneTree::get_multiplayer(const NodePath &p_for_path) const {
1780
ERR_FAIL_COND_V_MSG(!Thread::is_main_thread(), Ref<MultiplayerAPI>(), "Multiplayer can only be manipulated from the main thread.");
1781
if (p_for_path.is_empty()) {
1782
return multiplayer;
1783
}
1784
1785
const Vector<StringName> tnames = p_for_path.get_names();
1786
const StringName *nptr = tnames.ptr();
1787
for (const KeyValue<NodePath, Ref<MultiplayerAPI>> &E : custom_multiplayers) {
1788
const Vector<StringName> snames = E.key.get_names();
1789
if (tnames.size() < snames.size()) {
1790
continue;
1791
}
1792
const StringName *sptr = snames.ptr();
1793
bool valid = true;
1794
for (int i = 0; i < snames.size(); i++) {
1795
if (sptr[i] != nptr[i]) {
1796
valid = false;
1797
break;
1798
}
1799
}
1800
if (valid) {
1801
return E.value;
1802
}
1803
}
1804
1805
return multiplayer;
1806
}
1807
1808
void SceneTree::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer, const NodePath &p_root_path) {
1809
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Multiplayer can only be manipulated from the main thread.");
1810
if (p_root_path.is_empty()) {
1811
ERR_FAIL_COND(p_multiplayer.is_null());
1812
if (multiplayer.is_valid()) {
1813
multiplayer->object_configuration_remove(nullptr, NodePath("/" + root->get_name()));
1814
}
1815
multiplayer = p_multiplayer;
1816
multiplayer->object_configuration_add(nullptr, NodePath("/" + root->get_name()));
1817
} else {
1818
if (custom_multiplayers.has(p_root_path)) {
1819
custom_multiplayers[p_root_path]->object_configuration_remove(nullptr, p_root_path);
1820
} else if (p_multiplayer.is_valid()) {
1821
const Vector<StringName> tnames = p_root_path.get_names();
1822
const StringName *nptr = tnames.ptr();
1823
for (const KeyValue<NodePath, Ref<MultiplayerAPI>> &E : custom_multiplayers) {
1824
const Vector<StringName> snames = E.key.get_names();
1825
if (tnames.size() < snames.size()) {
1826
continue;
1827
}
1828
const StringName *sptr = snames.ptr();
1829
bool valid = true;
1830
for (int i = 0; i < snames.size(); i++) {
1831
if (sptr[i] != nptr[i]) {
1832
valid = false;
1833
break;
1834
}
1835
}
1836
ERR_FAIL_COND_MSG(valid, "Multiplayer is already configured for a parent of this path: '" + String(p_root_path) + "' in '" + String(E.key) + "'.");
1837
}
1838
}
1839
if (p_multiplayer.is_valid()) {
1840
custom_multiplayers[p_root_path] = p_multiplayer;
1841
p_multiplayer->object_configuration_add(nullptr, p_root_path);
1842
} else {
1843
custom_multiplayers.erase(p_root_path);
1844
}
1845
}
1846
}
1847
1848
void SceneTree::set_multiplayer_poll_enabled(bool p_enabled) {
1849
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Multiplayer can only be manipulated from the main thread.");
1850
multiplayer_poll = p_enabled;
1851
}
1852
1853
bool SceneTree::is_multiplayer_poll_enabled() const {
1854
return multiplayer_poll;
1855
}
1856
1857
void SceneTree::_bind_methods() {
1858
ClassDB::bind_method(D_METHOD("get_root"), &SceneTree::get_root);
1859
ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group);
1860
1861
ClassDB::bind_method(D_METHOD("is_accessibility_enabled"), &SceneTree::is_accessibility_enabled);
1862
ClassDB::bind_method(D_METHOD("is_accessibility_supported"), &SceneTree::is_accessibility_supported);
1863
1864
ClassDB::bind_method(D_METHOD("is_auto_accept_quit"), &SceneTree::is_auto_accept_quit);
1865
ClassDB::bind_method(D_METHOD("set_auto_accept_quit", "enabled"), &SceneTree::set_auto_accept_quit);
1866
ClassDB::bind_method(D_METHOD("is_quit_on_go_back"), &SceneTree::is_quit_on_go_back);
1867
ClassDB::bind_method(D_METHOD("set_quit_on_go_back", "enabled"), &SceneTree::set_quit_on_go_back);
1868
1869
ClassDB::bind_method(D_METHOD("set_debug_collisions_hint", "enable"), &SceneTree::set_debug_collisions_hint);
1870
ClassDB::bind_method(D_METHOD("is_debugging_collisions_hint"), &SceneTree::is_debugging_collisions_hint);
1871
ClassDB::bind_method(D_METHOD("set_debug_paths_hint", "enable"), &SceneTree::set_debug_paths_hint);
1872
ClassDB::bind_method(D_METHOD("is_debugging_paths_hint"), &SceneTree::is_debugging_paths_hint);
1873
ClassDB::bind_method(D_METHOD("set_debug_navigation_hint", "enable"), &SceneTree::set_debug_navigation_hint);
1874
ClassDB::bind_method(D_METHOD("is_debugging_navigation_hint"), &SceneTree::is_debugging_navigation_hint);
1875
1876
ClassDB::bind_method(D_METHOD("set_edited_scene_root", "scene"), &SceneTree::set_edited_scene_root);
1877
ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &SceneTree::get_edited_scene_root);
1878
1879
ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause);
1880
ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused);
1881
1882
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));
1883
ClassDB::bind_method(D_METHOD("create_tween"), &SceneTree::create_tween);
1884
ClassDB::bind_method(D_METHOD("get_processed_tweens"), &SceneTree::get_processed_tweens);
1885
1886
ClassDB::bind_method(D_METHOD("get_node_count"), &SceneTree::get_node_count);
1887
ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame);
1888
ClassDB::bind_method(D_METHOD("quit", "exit_code"), &SceneTree::quit, DEFVAL(EXIT_SUCCESS));
1889
1890
ClassDB::bind_method(D_METHOD("set_physics_interpolation_enabled", "enabled"), &SceneTree::set_physics_interpolation_enabled);
1891
ClassDB::bind_method(D_METHOD("is_physics_interpolation_enabled"), &SceneTree::is_physics_interpolation_enabled);
1892
1893
ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete);
1894
1895
MethodInfo mi;
1896
mi.name = "call_group_flags";
1897
mi.arguments.push_back(PropertyInfo(Variant::INT, "flags"));
1898
mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "group"));
1899
mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
1900
1901
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_group_flags", &SceneTree::_call_group_flags, mi);
1902
1903
ClassDB::bind_method(D_METHOD("notify_group_flags", "call_flags", "group", "notification"), &SceneTree::notify_group_flags);
1904
ClassDB::bind_method(D_METHOD("set_group_flags", "call_flags", "group", "property", "value"), &SceneTree::set_group_flags);
1905
1906
MethodInfo mi2;
1907
mi2.name = "call_group";
1908
mi2.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "group"));
1909
mi2.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
1910
1911
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_group", &SceneTree::_call_group, mi2);
1912
1913
ClassDB::bind_method(D_METHOD("notify_group", "group", "notification"), &SceneTree::notify_group);
1914
ClassDB::bind_method(D_METHOD("set_group", "group", "property", "value"), &SceneTree::set_group);
1915
1916
ClassDB::bind_method(D_METHOD("get_nodes_in_group", "group"), &SceneTree::_get_nodes_in_group);
1917
ClassDB::bind_method(D_METHOD("get_first_node_in_group", "group"), &SceneTree::get_first_node_in_group);
1918
ClassDB::bind_method(D_METHOD("get_node_count_in_group", "group"), &SceneTree::get_node_count_in_group);
1919
1920
ClassDB::bind_method(D_METHOD("set_current_scene", "child_node"), &SceneTree::set_current_scene);
1921
ClassDB::bind_method(D_METHOD("get_current_scene"), &SceneTree::get_current_scene);
1922
1923
ClassDB::bind_method(D_METHOD("change_scene_to_file", "path"), &SceneTree::change_scene_to_file);
1924
ClassDB::bind_method(D_METHOD("change_scene_to_packed", "packed_scene"), &SceneTree::change_scene_to_packed);
1925
1926
ClassDB::bind_method(D_METHOD("reload_current_scene"), &SceneTree::reload_current_scene);
1927
ClassDB::bind_method(D_METHOD("unload_current_scene"), &SceneTree::unload_current_scene);
1928
1929
ClassDB::bind_method(D_METHOD("set_multiplayer", "multiplayer", "root_path"), &SceneTree::set_multiplayer, DEFVAL(NodePath()));
1930
ClassDB::bind_method(D_METHOD("get_multiplayer", "for_path"), &SceneTree::get_multiplayer, DEFVAL(NodePath()));
1931
ClassDB::bind_method(D_METHOD("set_multiplayer_poll_enabled", "enabled"), &SceneTree::set_multiplayer_poll_enabled);
1932
ClassDB::bind_method(D_METHOD("is_multiplayer_poll_enabled"), &SceneTree::is_multiplayer_poll_enabled);
1933
1934
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_accept_quit"), "set_auto_accept_quit", "is_auto_accept_quit");
1935
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "quit_on_go_back"), "set_quit_on_go_back", "is_quit_on_go_back");
1936
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_collisions_hint"), "set_debug_collisions_hint", "is_debugging_collisions_hint");
1937
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_paths_hint"), "set_debug_paths_hint", "is_debugging_paths_hint");
1938
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_navigation_hint"), "set_debug_navigation_hint", "is_debugging_navigation_hint");
1939
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_pause", "is_paused");
1940
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_edited_scene_root", "get_edited_scene_root");
1941
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_current_scene", "get_current_scene");
1942
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "", "get_root");
1943
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multiplayer_poll"), "set_multiplayer_poll_enabled", "is_multiplayer_poll_enabled");
1944
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_interpolation"), "set_physics_interpolation_enabled", "is_physics_interpolation_enabled");
1945
1946
ADD_SIGNAL(MethodInfo("tree_changed"));
1947
ADD_SIGNAL(MethodInfo("scene_changed"));
1948
ADD_SIGNAL(MethodInfo("tree_process_mode_changed")); //editor only signal, but due to API hash it can't be removed in run-time
1949
ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
1950
ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
1951
ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
1952
ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
1953
1954
ADD_SIGNAL(MethodInfo("process_frame"));
1955
ADD_SIGNAL(MethodInfo("physics_frame"));
1956
1957
BIND_ENUM_CONSTANT(GROUP_CALL_DEFAULT);
1958
BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE);
1959
BIND_ENUM_CONSTANT(GROUP_CALL_DEFERRED);
1960
BIND_ENUM_CONSTANT(GROUP_CALL_UNIQUE);
1961
}
1962
1963
SceneTree *SceneTree::singleton = nullptr;
1964
1965
SceneTree::IdleCallback SceneTree::idle_callbacks[SceneTree::MAX_IDLE_CALLBACKS];
1966
int SceneTree::idle_callback_count = 0;
1967
1968
void SceneTree::_call_idle_callbacks() {
1969
for (int i = 0; i < idle_callback_count; i++) {
1970
idle_callbacks[i]();
1971
}
1972
}
1973
1974
void SceneTree::add_idle_callback(IdleCallback p_callback) {
1975
ERR_FAIL_COND(idle_callback_count >= MAX_IDLE_CALLBACKS);
1976
idle_callbacks[idle_callback_count++] = p_callback;
1977
}
1978
1979
#ifdef TOOLS_ENABLED
1980
void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
1981
bool add_options = false;
1982
if (p_idx == 0) {
1983
static const Vector<StringName> names = {
1984
StringName("add_to_group", true),
1985
StringName("call_group", true),
1986
StringName("get_first_node_in_group", true),
1987
StringName("get_node_count_in_group", true),
1988
StringName("get_nodes_in_group", true),
1989
StringName("has_group", true),
1990
StringName("notify_group", true),
1991
StringName("set_group", true),
1992
};
1993
add_options = names.has(p_function);
1994
} else if (p_idx == 1) {
1995
static const Vector<StringName> names = {
1996
StringName("call_group_flags", true),
1997
StringName("notify_group_flags", true),
1998
StringName("set_group_flags", true),
1999
};
2000
add_options = names.has(p_function);
2001
}
2002
if (add_options) {
2003
HashMap<StringName, String> global_groups = ProjectSettings::get_singleton()->get_global_groups_list();
2004
for (const KeyValue<StringName, String> &E : global_groups) {
2005
r_options->push_back(E.key.operator String().quote());
2006
}
2007
}
2008
MainLoop::get_argument_options(p_function, p_idx, r_options);
2009
}
2010
#endif
2011
2012
void SceneTree::set_disable_node_threading(bool p_disable) {
2013
node_threading_disabled = p_disable;
2014
}
2015
2016
SceneTree::SceneTree() {
2017
if (singleton == nullptr) {
2018
singleton = this;
2019
}
2020
debug_collisions_color = GLOBAL_DEF("debug/shapes/collision/shape_color", Color(0.0, 0.6, 0.7, 0.42));
2021
debug_collision_contact_color = GLOBAL_DEF("debug/shapes/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8));
2022
debug_paths_color = GLOBAL_DEF("debug/shapes/paths/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
2023
debug_paths_width = GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "debug/shapes/paths/geometry_width", PROPERTY_HINT_RANGE, "0.01,10,0.001,or_greater"), 2.0);
2024
collision_debug_contacts = GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1"), 10000);
2025
accessibility_upd_per_sec = GLOBAL_GET(SNAME("accessibility/general/updates_per_second"));
2026
2027
GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
2028
2029
process_group_call_queue_allocator = memnew(CallQueue::Allocator(64));
2030
Math::randomize();
2031
2032
// Create with mainloop.
2033
2034
root = memnew(Window);
2035
root->set_min_size(Size2i(64, 64)); // Define a very small minimum window size to prevent bugs such as GH-37242.
2036
root->set_process_mode(Node::PROCESS_MODE_PAUSABLE);
2037
root->set_name("root");
2038
2039
if (Engine::get_singleton()->is_editor_hint()) {
2040
root->set_wrap_controls(true);
2041
root->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_ALWAYS);
2042
} else {
2043
root->set_auto_translate_mode(GLOBAL_GET("internationalization/rendering/root_node_auto_translate") ? Node::AUTO_TRANSLATE_MODE_ALWAYS : Node::AUTO_TRANSLATE_MODE_DISABLED);
2044
}
2045
2046
// Set after auto translate mode to avoid changing the displayed title back and forth.
2047
root->set_title(GLOBAL_GET("application/config/name"));
2048
2049
#ifndef _3D_DISABLED
2050
if (root->get_world_3d().is_null()) {
2051
root->set_world_3d(Ref<World3D>(memnew(World3D)));
2052
}
2053
root->set_as_audio_listener_3d(true);
2054
#endif // _3D_DISABLED
2055
2056
set_physics_interpolation_enabled(GLOBAL_DEF("physics/common/physics_interpolation", false));
2057
2058
// Always disable jitter fix if physics interpolation is enabled -
2059
// Jitter fix will interfere with interpolation, and is not necessary
2060
// when interpolation is active.
2061
if (is_physics_interpolation_enabled()) {
2062
Engine::get_singleton()->set_physics_jitter_fix(0);
2063
}
2064
2065
// Initialize network state.
2066
set_multiplayer(MultiplayerAPI::create_default_interface());
2067
2068
root->set_as_audio_listener_2d(true);
2069
current_scene = nullptr;
2070
2071
const int msaa_mode_2d = GLOBAL_GET("rendering/anti_aliasing/quality/msaa_2d");
2072
root->set_msaa_2d(Viewport::MSAA(msaa_mode_2d));
2073
2074
const int msaa_mode_3d = GLOBAL_GET("rendering/anti_aliasing/quality/msaa_3d");
2075
root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d));
2076
2077
const bool transparent_background = GLOBAL_DEF("rendering/viewport/transparent_background", false);
2078
root->set_transparent_background(transparent_background);
2079
2080
const bool use_hdr_2d = GLOBAL_GET("rendering/viewport/hdr_2d");
2081
root->set_use_hdr_2d(use_hdr_2d);
2082
2083
const int ssaa_mode = GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast),SMAA (Average)"), 0);
2084
root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode));
2085
2086
const bool use_taa = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/use_taa", false);
2087
root->set_use_taa(use_taa);
2088
2089
const bool use_debanding = GLOBAL_DEF("rendering/anti_aliasing/quality/use_debanding", false);
2090
root->set_use_debanding(use_debanding);
2091
2092
const bool use_occlusion_culling = GLOBAL_DEF("rendering/occlusion_culling/use_occlusion_culling", false);
2093
root->set_use_occlusion_culling(use_occlusion_culling);
2094
2095
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);
2096
root->set_mesh_lod_threshold(mesh_lod_threshold);
2097
2098
bool snap_2d_transforms = GLOBAL_DEF_BASIC("rendering/2d/snap/snap_2d_transforms_to_pixel", false);
2099
root->set_snap_2d_transforms_to_pixel(snap_2d_transforms);
2100
2101
bool snap_2d_vertices = GLOBAL_DEF("rendering/2d/snap/snap_2d_vertices_to_pixel", false);
2102
root->set_snap_2d_vertices_to_pixel(snap_2d_vertices);
2103
2104
// We setup VRS for the main viewport here, in the editor this will have little effect.
2105
const int vrs_mode = GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/vrs/mode", PROPERTY_HINT_ENUM, String::utf8("Disabled,Texture,XR")), 0);
2106
root->set_vrs_mode(Viewport::VRSMode(vrs_mode));
2107
const String vrs_texture_path = String(GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/vrs/texture", PROPERTY_HINT_FILE, "*.bmp,*.png,*.tga,*.webp"), String())).strip_edges();
2108
if (vrs_mode == 1 && !vrs_texture_path.is_empty()) {
2109
Ref<Image> vrs_image;
2110
vrs_image.instantiate();
2111
Error load_err = ImageLoader::load_image(vrs_texture_path, vrs_image);
2112
if (load_err) {
2113
ERR_PRINT("Non-existing or invalid VRS texture at '" + vrs_texture_path + "'.");
2114
} else {
2115
Ref<ImageTexture> vrs_texture;
2116
vrs_texture.instantiate();
2117
vrs_texture->create_from_image(vrs_image);
2118
root->set_vrs_texture(vrs_texture);
2119
}
2120
}
2121
2122
int shadowmap_size = GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_size", PROPERTY_HINT_RANGE, "256,16384"), 4096);
2123
GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_size.mobile", 2048);
2124
bool shadowmap_16_bits = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_16_bits");
2125
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);
2126
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);
2127
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);
2128
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);
2129
2130
root->set_positional_shadow_atlas_size(shadowmap_size);
2131
root->set_positional_shadow_atlas_16_bits(shadowmap_16_bits);
2132
root->set_positional_shadow_atlas_quadrant_subdiv(0, Viewport::PositionalShadowAtlasQuadrantSubdiv(atlas_q0));
2133
root->set_positional_shadow_atlas_quadrant_subdiv(1, Viewport::PositionalShadowAtlasQuadrantSubdiv(atlas_q1));
2134
root->set_positional_shadow_atlas_quadrant_subdiv(2, Viewport::PositionalShadowAtlasQuadrantSubdiv(atlas_q2));
2135
root->set_positional_shadow_atlas_quadrant_subdiv(3, Viewport::PositionalShadowAtlasQuadrantSubdiv(atlas_q3));
2136
2137
Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/2d/sdf/oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%"), 1)));
2138
root->set_sdf_oversize(sdf_oversize);
2139
Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/2d/sdf/scale", PROPERTY_HINT_ENUM, "100%,50%,25%"), 1)));
2140
root->set_sdf_scale(sdf_scale);
2141
2142
#ifndef _3D_DISABLED
2143
{ // Load default fallback environment.
2144
// Get possible extensions.
2145
List<String> exts;
2146
ResourceLoader::get_recognized_extensions_for_type("Environment", &exts);
2147
String ext_hint;
2148
for (const String &E : exts) {
2149
if (!ext_hint.is_empty()) {
2150
ext_hint += ",";
2151
}
2152
ext_hint += "*." + E;
2153
}
2154
// Get path.
2155
String env_path = GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/environment/defaults/default_environment", PROPERTY_HINT_FILE, ext_hint), "");
2156
// Setup property.
2157
env_path = env_path.strip_edges();
2158
if (!env_path.is_empty()) {
2159
Ref<Environment> env = ResourceLoader::load(env_path);
2160
if (env.is_valid()) {
2161
root->get_world_3d()->set_fallback_environment(env);
2162
} else {
2163
if (Engine::get_singleton()->is_editor_hint()) {
2164
// File was erased, clear the field.
2165
ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
2166
} else {
2167
// File was erased, notify user.
2168
ERR_PRINT("Default Environment as specified in the project setting \"rendering/environment/defaults/default_environment\" could not be loaded.");
2169
}
2170
}
2171
}
2172
}
2173
#endif // _3D_DISABLED
2174
2175
#if !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
2176
root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true));
2177
#endif // !defined(PHYSICS_2D_DISABLED) || !defined(PHYSICS_3D_DISABLED)
2178
2179
root->connect("close_requested", callable_mp(this, &SceneTree::_main_window_close));
2180
root->connect("go_back_requested", callable_mp(this, &SceneTree::_main_window_go_back));
2181
root->connect(SceneStringName(focus_entered), callable_mp(this, &SceneTree::_main_window_focus_in));
2182
2183
#ifdef TOOLS_ENABLED
2184
edited_scene_root = nullptr;
2185
#endif
2186
2187
process_groups.push_back(&default_process_group);
2188
}
2189
2190
SceneTree::~SceneTree() {
2191
if (prev_scene_id.is_valid()) {
2192
Node *prev_scene = ObjectDB::get_instance<Node>(prev_scene_id);
2193
if (prev_scene) {
2194
memdelete(prev_scene);
2195
}
2196
prev_scene_id = ObjectID();
2197
}
2198
if (pending_new_scene_id.is_valid()) {
2199
Node *pending_new_scene = ObjectDB::get_instance<Node>(pending_new_scene_id);
2200
if (pending_new_scene) {
2201
memdelete(pending_new_scene);
2202
}
2203
pending_new_scene_id = ObjectID();
2204
}
2205
if (root) {
2206
root->_set_tree(nullptr);
2207
root->_propagate_after_exit_tree();
2208
memdelete(root);
2209
}
2210
2211
// Process groups are not deleted immediately, they may remain around. Delete them now.
2212
for (uint32_t i = 0; i < process_groups.size(); i++) {
2213
if (process_groups[i] != &default_process_group) {
2214
memdelete(process_groups[i]);
2215
}
2216
}
2217
2218
memdelete(process_group_call_queue_allocator);
2219
2220
if (singleton == this) {
2221
singleton = nullptr;
2222
}
2223
}
2224
2225