feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -31,17 +31,12 @@
#include "scene_tree.h"
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
#include "core/input/input.h"
#include "core/io/dir_access.h"
#include "core/io/image_loader.h"
#include "core/io/marshalls.h"
#include "core/io/resource_loader.h"
#include "core/object/message_queue.h"
#include "core/object/worker_thread_pool.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "node.h"
#include "scene/animation/tween.h"
#include "scene/debugger/scene_debugger.h"
@ -49,22 +44,18 @@
#include "scene/main/multiplayer_api.h"
#include "scene/main/viewport.h"
#include "scene/resources/environment.h"
#include "scene/resources/font.h"
#include "scene/resources/image_texture.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/world_2d.h"
#include "servers/display_server.h"
#include "servers/navigation_server_3d.h"
#include "servers/physics_server_2d.h"
#ifndef _3D_DISABLED
#include "scene/3d/node_3d.h"
#include "scene/resources/3d/world_3d.h"
#include "servers/physics_server_3d.h"
#endif // _3D_DISABLED
#include "window.h"
#include <stdio.h>
#include <stdlib.h>
void SceneTreeTimer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_time_left", "time"), &SceneTreeTimer::set_time_left);
@ -103,7 +94,7 @@ void SceneTreeTimer::set_ignore_time_scale(bool p_ignore) {
ignore_time_scale = p_ignore;
}
bool SceneTreeTimer::is_ignore_time_scale() {
bool SceneTreeTimer::is_ignoring_time_scale() {
return ignore_time_scale;
}
@ -118,6 +109,29 @@ void SceneTreeTimer::release_connections() {
SceneTreeTimer::SceneTreeTimer() {}
#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
void SceneTree::tree_changed() {
emit_signal(tree_changed_name);
}
@ -278,11 +292,15 @@ void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_gro
continue;
}
Node *node = gr_nodes[i];
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
Callable::CallError ce;
gr_nodes[i]->callp(p_function, p_args, p_argcount, ce);
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)));
}
} else {
MessageQueue::get_singleton()->push_callp(gr_nodes[i], p_function, p_args, p_argcount);
MessageQueue::get_singleton()->push_callp(node, p_function, p_args, p_argcount);
}
}
@ -292,11 +310,15 @@ void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_gro
continue;
}
Node *node = gr_nodes[i];
if (!(p_call_flags & GROUP_CALL_DEFERRED)) {
Callable::CallError ce;
gr_nodes[i]->callp(p_function, p_args, p_argcount, ce);
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)));
}
} else {
MessageQueue::get_singleton()->push_callp(gr_nodes[i], p_function, p_args, p_argcount);
MessageQueue::get_singleton()->push_callp(node, p_function, p_args, p_argcount);
}
}
}
@ -460,14 +482,34 @@ void SceneTree::set_physics_interpolation_enabled(bool p_enabled) {
_physics_interpolation_enabled = p_enabled;
RenderingServer::get_singleton()->set_physics_interpolation_enabled(p_enabled);
// Perform an auto reset on the root node for convenience for the user.
if (root) {
root->reset_physics_interpolation();
}
}
bool SceneTree::is_physics_interpolation_enabled() const {
return _physics_interpolation_enabled;
}
#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
void SceneTree::iteration_prepare() {
if (_physics_interpolation_enabled) {
// Make sure any pending transforms from the last tick / frame
// are flushed before pumping the interpolation prev and currents.
flush_transform_notifications();
RenderingServer::get_singleton()->tick();
}
}
@ -492,17 +534,32 @@ bool SceneTree::physics_process(double p_time) {
MessageQueue::get_singleton()->flush(); //small little hack
process_timers(p_time, true); //go through timers
process_tweens(p_time, true);
flush_transform_notifications();
// This should happen last because any processing that deletes something beforehand might expect the object to be removed in the same frame.
_flush_delete_queue();
_call_idle_callbacks();
return _quit;
}
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();
#ifndef _3D_DISABLED
// Any objects performing client physics interpolation
// should be given an opportunity to keep their previous transforms
// up to date.
_client_physics_interpolation.physics_process();
#endif
}
}
bool SceneTree::process(double p_time) {
if (MainLoop::process(p_time)) {
_quit = true;
@ -529,78 +586,94 @@ bool SceneTree::process(double p_time) {
MessageQueue::get_singleton()->flush(); //small little hack
flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications
_flush_delete_queue();
if (unlikely(pending_new_scene)) {
_flush_scene_change();
}
process_timers(p_time, false); //go through timers
process_tweens(p_time, false);
flush_transform_notifications(); //additional transforms after timers update
flush_transform_notifications(); // Additional transforms after timers update.
// This should happen last because any processing that deletes something beforehand might expect the object to be removed in the same frame.
_flush_delete_queue();
_call_idle_callbacks();
#ifdef TOOLS_ENABLED
#ifndef _3D_DISABLED
if (Engine::get_singleton()->is_editor_hint()) {
//simple hack to reload fallback environment if it changed from editor
String env_path = GLOBAL_GET(SNAME("rendering/environment/defaults/default_environment"));
env_path = env_path.strip_edges(); //user may have added a space or two
String cpath;
Ref<Environment> fallback = get_root()->get_world_3d()->get_fallback_environment();
if (fallback.is_valid()) {
cpath = fallback->get_path();
}
if (cpath != env_path) {
if (!env_path.is_empty()) {
fallback = ResourceLoader::load(env_path);
if (fallback.is_null()) {
//could not load fallback, set as empty
ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
}
} else {
fallback.unref();
env_path = env_path.strip_edges(); // User may have added a space or two.
bool can_load = true;
if (env_path.begins_with("uid://")) {
// If an uid path, ensure it is mapped to a resource which could not be
// the case if the editor is still scanning the filesystem.
ResourceUID::ID id = ResourceUID::get_singleton()->text_to_id(env_path);
can_load = ResourceUID::get_singleton()->has_id(id);
if (can_load) {
env_path = ResourceUID::get_singleton()->get_id_path(id);
}
}
if (can_load) {
String cpath;
Ref<Environment> fallback = get_root()->get_world_3d()->get_fallback_environment();
if (fallback.is_valid()) {
cpath = fallback->get_path();
}
if (cpath != env_path) {
if (!env_path.is_empty()) {
fallback = ResourceLoader::load(env_path);
if (fallback.is_null()) {
//could not load fallback, set as empty
ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", "");
}
} else {
fallback.unref();
}
get_root()->get_world_3d()->set_fallback_environment(fallback);
}
get_root()->get_world_3d()->set_fallback_environment(fallback);
}
}
#endif // _3D_DISABLED
#endif // TOOLS_ENABLED
if (_physics_interpolation_enabled) {
RenderingServer::get_singleton()->pre_draw(true);
}
return _quit;
}
void SceneTree::process_timers(double p_delta, bool p_physics_frame) {
_THREAD_SAFE_METHOD_
List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element
const List<Ref<SceneTreeTimer>>::Element *L = timers.back(); // Last element.
const double unscaled_delta = Engine::get_singleton()->get_process_step();
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)) {
Ref<SceneTreeTimer> timer = E->get();
if ((paused && !timer->is_process_always()) || (timer->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.
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);
double time_left = timer->get_time_left();
time_left -= timer->is_ignoring_time_scale() ? unscaled_delta : p_delta;
timer->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.
break; // Break on last, so if new timers were added during list traversal, ignore them.
}
E = N;
}
@ -609,12 +682,15 @@ void SceneTree::process_timers(double p_delta, bool p_physics_frame) {
void SceneTree::process_tweens(double p_delta, bool p_physics) {
_THREAD_SAFE_METHOD_
// This methods works similarly to how SceneTreeTimers are handled.
List<Ref<Tween>>::Element *L = tweens.back();
const List<Ref<Tween>>::Element *L = tweens.back();
const double unscaled_delta = Engine::get_singleton()->get_process_step();
for (List<Ref<Tween>>::Element *E = tweens.front(); E;) {
List<Ref<Tween>>::Element *N = E->next();
Ref<Tween> &tween = E->get();
// Don't process if paused or process mode doesn't match.
if (!E->get()->can_process(paused) || (p_physics == (E->get()->get_process_mode() == Tween::TWEEN_PROCESS_IDLE))) {
if (!tween->can_process(paused) || (p_physics == (tween->get_process_mode() == Tween::TWEEN_PROCESS_IDLE))) {
if (E == L) {
break;
}
@ -622,8 +698,8 @@ void SceneTree::process_tweens(double p_delta, bool p_physics) {
continue;
}
if (!E->get()->step(p_delta)) {
E->get()->clear();
if (!tween->step(tween->is_ignoring_time_scale() ? unscaled_delta : p_delta)) {
tween->clear();
tweens.erase(E);
}
if (E == L) {
@ -833,7 +909,7 @@ Ref<ArrayMesh> SceneTree::get_debug_contact_mesh() {
return debug_contact_mesh;
}
debug_contact_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
debug_contact_mesh.instantiate();
Ref<StandardMaterial3D> mat = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
@ -888,11 +964,14 @@ Ref<ArrayMesh> SceneTree::get_debug_contact_mesh() {
void SceneTree::set_pause(bool p_enabled) {
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Pause can only be set from the main thread.");
ERR_FAIL_COND_MSG(suspended, "Pause state cannot be modified while suspended.");
if (p_enabled == paused) {
return;
}
paused = p_enabled;
#ifndef _3D_DISABLED
PhysicsServer3D::get_singleton()->set_active(!p_enabled);
#endif // _3D_DISABLED
@ -906,6 +985,30 @@ bool SceneTree::is_paused() const {
return paused;
}
void SceneTree::set_suspend(bool p_enabled) {
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Suspend can only be set from the main thread.");
if (p_enabled == suspended) {
return;
}
suspended = p_enabled;
Engine::get_singleton()->set_freeze_time_scale(p_enabled);
#ifndef _3D_DISABLED
PhysicsServer3D::get_singleton()->set_active(!p_enabled && !paused);
#endif // _3D_DISABLED
PhysicsServer2D::get_singleton()->set_active(!p_enabled && !paused);
if (get_root()) {
get_root()->_propagate_suspend_notification(p_enabled);
}
}
bool SceneTree::is_suspended() const {
return suspended;
}
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.
@ -1257,8 +1360,8 @@ void SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Callab
ERR_FAIL_COND(p_argcount < 3);
ERR_FAIL_COND(!p_args[0]->is_num());
ERR_FAIL_COND(p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING);
ERR_FAIL_COND(p_args[2]->get_type() != Variant::STRING_NAME && p_args[2]->get_type() != Variant::STRING);
ERR_FAIL_COND(!p_args[1]->is_string());
ERR_FAIL_COND(!p_args[2]->is_string());
int flags = *p_args[0];
StringName group = *p_args[1];
@ -1271,8 +1374,8 @@ void SceneTree::_call_group(const Variant **p_args, int p_argcount, Callable::Ca
r_error.error = Callable::CallError::CALL_OK;
ERR_FAIL_COND(p_argcount < 2);
ERR_FAIL_COND(p_args[0]->get_type() != Variant::STRING_NAME && p_args[0]->get_type() != Variant::STRING);
ERR_FAIL_COND(p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING);
ERR_FAIL_COND(!p_args[0]->is_string());
ERR_FAIL_COND(!p_args[1]->is_string());
StringName group = *p_args[0];
StringName method = *p_args[1];
@ -1486,11 +1589,22 @@ Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_a
Ref<Tween> SceneTree::create_tween() {
_THREAD_SAFE_METHOD_
Ref<Tween> tween = memnew(Tween(true));
Ref<Tween> tween;
tween.instantiate(this);
tweens.push_back(tween);
return tween;
}
void SceneTree::remove_tween(const Ref<Tween> &p_tween) {
_THREAD_SAFE_METHOD_
for (List<Ref<Tween>>::Element *E = tweens.back(); E; E = E->prev()) {
if (E->get() == p_tween) {
E->erase();
break;
}
}
}
TypedArray<Tween> SceneTree::get_processed_tweens() {
_THREAD_SAFE_METHOD_
TypedArray<Tween> ret;
@ -1537,7 +1651,7 @@ Ref<MultiplayerAPI> SceneTree::get_multiplayer(const NodePath &p_for_path) const
void SceneTree::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer, const NodePath &p_root_path) {
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Multiplayer can only be manipulated from the main thread.");
if (p_root_path.is_empty()) {
ERR_FAIL_COND(!p_multiplayer.is_valid());
ERR_FAIL_COND(p_multiplayer.is_null());
if (multiplayer.is_valid()) {
multiplayer->object_configuration_remove(nullptr, NodePath("/" + root->get_name()));
}
@ -1731,7 +1845,7 @@ SceneTree::SceneTree() {
debug_collisions_color = GLOBAL_DEF("debug/shapes/collision/shape_color", Color(0.0, 0.6, 0.7, 0.42));
debug_collision_contact_color = GLOBAL_DEF("debug/shapes/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8));
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);
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);
collision_debug_contacts = GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1"), 10000);
GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
@ -1753,7 +1867,7 @@ SceneTree::SceneTree() {
}
#ifndef _3D_DISABLED
if (!root->get_world_3d().is_valid()) {
if (root->get_world_3d().is_null()) {
root->set_world_3d(Ref<World3D>(memnew(World3D)));
}
root->set_as_audio_listener_3d(true);
@ -1761,22 +1875,29 @@ SceneTree::SceneTree() {
set_physics_interpolation_enabled(GLOBAL_DEF("physics/common/physics_interpolation", false));
// 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);
}
// Initialize network state.
set_multiplayer(MultiplayerAPI::create_default_interface());
root->set_as_audio_listener_2d(true);
current_scene = nullptr;
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);
const int msaa_mode_2d = GLOBAL_GET("rendering/anti_aliasing/quality/msaa_2d");
root->set_msaa_2d(Viewport::MSAA(msaa_mode_2d));
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);
const int msaa_mode_3d = GLOBAL_GET("rendering/anti_aliasing/quality/msaa_3d");
root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d));
const bool transparent_background = GLOBAL_DEF("rendering/viewport/transparent_background", false);
root->set_transparent_background(transparent_background);
const bool use_hdr_2d = GLOBAL_DEF_RST_BASIC("rendering/viewport/hdr_2d", false);
const bool use_hdr_2d = GLOBAL_GET("rendering/viewport/hdr_2d");
root->set_use_hdr_2d(use_hdr_2d);
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);
@ -1820,7 +1941,7 @@ SceneTree::SceneTree() {
int shadowmap_size = GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_size", PROPERTY_HINT_RANGE, "256,16384"), 4096);
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);
bool shadowmap_16_bits = GLOBAL_GET("rendering/lights_and_shadows/positional_shadow/atlas_16_bits");
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);