summaryrefslogtreecommitdiffstats
path: root/main/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'main/main.cpp')
-rw-r--r--main/main.cpp417
1 files changed, 319 insertions, 98 deletions
diff --git a/main/main.cpp b/main/main.cpp
index ef997e71a7..7b46957904 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -70,6 +70,7 @@
#include "servers/movie_writer/movie_writer.h"
#include "servers/movie_writer/movie_writer_mjpeg.h"
#include "servers/navigation_server_2d.h"
+#include "servers/navigation_server_2d_dummy.h"
#include "servers/navigation_server_3d.h"
#include "servers/navigation_server_3d_dummy.h"
#include "servers/physics_server_2d.h"
@@ -114,7 +115,10 @@
#ifdef MODULE_GDSCRIPT_ENABLED
#include "modules/gdscript/gdscript.h"
-#endif
+#if defined(TOOLS_ENABLED) && !defined(GDSCRIPT_NO_LSP)
+#include "modules/gdscript/language_server/gdscript_language_server.h"
+#endif // TOOLS_ENABLED && !GDSCRIPT_NO_LSP
+#endif // MODULE_GDSCRIPT_ENABLED
/* Static members */
@@ -209,8 +213,11 @@ static bool debug_collisions = false;
static bool debug_paths = false;
static bool debug_navigation = false;
static bool debug_avoidance = false;
+static bool debug_canvas_item_redraw = false;
#endif
+static int max_fps = -1;
static int frame_delay = 0;
+static int audio_output_latency = 0;
static bool disable_render_loop = false;
static int fixed_fps = -1;
static MovieWriter *movie_writer = nullptr;
@@ -219,6 +226,7 @@ static bool print_fps = false;
#ifdef TOOLS_ENABLED
static bool dump_gdextension_interface = false;
static bool dump_extension_api = false;
+static bool include_docs_in_extension_api_dump = false;
static bool validate_extension_api = false;
static String validate_extension_api_file;
#endif
@@ -287,7 +295,7 @@ void initialize_physics() {
// Physics server not found, Use the default physics
physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server();
}
- ERR_FAIL_COND(!physics_server_3d);
+ ERR_FAIL_NULL(physics_server_3d);
physics_server_3d->init();
// 2D Physics server
@@ -297,7 +305,7 @@ void initialize_physics() {
// Physics server not found, Use the default physics
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
}
- ERR_FAIL_COND(!physics_server_2d);
+ ERR_FAIL_NULL(physics_server_2d);
physics_server_2d->init();
}
@@ -318,6 +326,7 @@ void finalize_display() {
void initialize_navigation_server() {
ERR_FAIL_COND(navigation_server_3d != nullptr);
+ ERR_FAIL_COND(navigation_server_2d != nullptr);
// Init 3D Navigation Server
navigation_server_3d = NavigationServer3DManager::new_default_server();
@@ -330,16 +339,27 @@ void initialize_navigation_server() {
// Should be impossible, but make sure it's not null.
ERR_FAIL_NULL_MSG(navigation_server_3d, "Failed to initialize NavigationServer3D.");
+ navigation_server_3d->init();
// Init 2D Navigation Server
- navigation_server_2d = memnew(NavigationServer2D);
+ navigation_server_2d = NavigationServer2DManager::new_default_server();
+ if (!navigation_server_2d) {
+ WARN_PRINT_ONCE("No NavigationServer2D implementation has been registered! Falling back to a dummy implementation: navigation features will be unavailable.");
+ navigation_server_2d = memnew(NavigationServer2DDummy);
+ }
+
ERR_FAIL_NULL_MSG(navigation_server_2d, "Failed to initialize NavigationServer2D.");
+ navigation_server_2d->init();
}
void finalize_navigation_server() {
+ ERR_FAIL_NULL(navigation_server_3d);
+ navigation_server_3d->finish();
memdelete(navigation_server_3d);
navigation_server_3d = nullptr;
+ ERR_FAIL_NULL(navigation_server_2d);
+ navigation_server_2d->finish();
memdelete(navigation_server_2d);
navigation_server_2d = nullptr;
}
@@ -382,7 +402,10 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" -e, --editor Start the editor instead of running the scene.\n");
OS::get_singleton()->print(" -p, --project-manager Start the project manager, even if a project is auto-detected.\n");
OS::get_singleton()->print(" --debug-server <uri> Start the editor debug server (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007)\n");
-#endif
+#if defined(MODULE_GDSCRIPT_ENABLED) && !defined(GDSCRIPT_NO_LSP)
+ OS::get_singleton()->print(" --lsp-port <port> Use the specified port for the language server protocol. The port must be between 0 to 65535.\n");
+#endif // MODULE_GDSCRIPT_ENABLED && !GDSCRIPT_NO_LSP
+#endif // TOOLS_ENABLED
OS::get_singleton()->print(" --quit Quit after the first iteration.\n");
OS::get_singleton()->print(" --quit-after <int> Quit after the given number of iterations. Set to 0 to disable.\n");
OS::get_singleton()->print(" -l, --language <locale> Use a specific locale (<locale> being a two-letter code).\n");
@@ -418,6 +441,8 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(")");
}
OS::get_singleton()->print("].\n");
+ OS::get_singleton()->print(" --audio-output-latency <ms> Override audio output latency in milliseconds (default is 15 ms).\n");
+ OS::get_singleton()->print(" Lower values make sound playback more reactive but increase CPU usage, and may result in audio cracking if the CPU can't keep up.\n");
OS::get_singleton()->print(" --rendering-method <renderer> Renderer name. Requires driver support.\n");
OS::get_singleton()->print(" --rendering-driver <driver> Rendering driver (depends on display driver).\n");
@@ -453,6 +478,7 @@ void Main::print_help(const char *p_binary) {
#if DEBUG_ENABLED
OS::get_singleton()->print(" --gpu-abort Abort on graphics API usage errors (usually validation layer errors). May help see the problem if your system freezes.\n");
#endif
+ OS::get_singleton()->print(" --generate-spirv-debug-info Generate SPIR-V debug information. This allows source-level shader debugging with RenderDoc.\n");
OS::get_singleton()->print(" --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");
OS::get_singleton()->print(" --single-threaded-scene Scene tree runs in single-threaded mode. Sub-thread groups are disabled and run on the main thread.\n");
#if defined(DEBUG_ENABLED)
@@ -461,8 +487,10 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n");
OS::get_singleton()->print(" --debug-avoidance Show navigation avoidance debug visuals when running the scene.\n");
OS::get_singleton()->print(" --debug-stringnames Print all StringName allocations to stdout when the engine quits.\n");
+ OS::get_singleton()->print(" --debug-canvas-item-redraw Display a rectangle each time a canvas item requests a redraw (useful to troubleshoot low processor mode).\n");
#endif
- OS::get_singleton()->print(" --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds).\n");
+ OS::get_singleton()->print(" --max-fps <fps> Set a maximum number of frames per second rendered (can be used to limit power usage). A value of 0 results in unlimited framerate.\n");
+ OS::get_singleton()->print(" --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds). Do not use as a FPS limiter; use --max-fps instead.\n");
OS::get_singleton()->print(" --time-scale <scale> Force time scale (higher values are faster, 1.0 is normal speed).\n");
OS::get_singleton()->print(" --disable-vsync Forces disabling of vertical synchronization, even if enabled in the project settings. Does not override driver-level V-Sync enforcement.\n");
OS::get_singleton()->print(" --disable-render-loop Disable render loop so rendering only occurs when called explicitly from script.\n");
@@ -474,6 +502,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print("Standalone tools:\n");
OS::get_singleton()->print(" -s, --script <script> Run a script.\n");
+ OS::get_singleton()->print(" --main-loop <main_loop_name> Run a MainLoop specified by its global class name.\n");
OS::get_singleton()->print(" --check-only Only parse for errors and quit (use with --script).\n");
#ifdef TOOLS_ENABLED
OS::get_singleton()->print(" --export-release <preset> <path> Export the project in release mode using the given preset and output path. The preset name should match one defined in export_presets.cfg.\n");
@@ -495,7 +524,8 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n");
OS::get_singleton()->print(" --dump-gdextension-interface Generate GDExtension header file 'gdextension_interface.h' in the current folder. This file is the base file required to implement a GDExtension.\n");
OS::get_singleton()->print(" --dump-extension-api Generate JSON dump of the Godot API for GDExtension bindings named 'extension_api.json' in the current folder.\n");
- OS::get_singleton()->print(" --validate-extension-api <path> Validate an extension API file dumped (with the option above) from a previous version of the engine to ensure API compatibility. If incompatibilities or errors are detected, the return code will be non zero.\n");
+ OS::get_singleton()->print(" --dump-extension-api-with-docs Generate JSON dump of the Godot API like the previous option, but including documentation.\n");
+ OS::get_singleton()->print(" --validate-extension-api <path> Validate an extension API file dumped (with one of the two previous options) from a previous version of the engine to ensure API compatibility. If incompatibilities or errors are detected, the return code will be non zero.\n");
OS::get_singleton()->print(" --benchmark Benchmark the run time and print it to console.\n");
OS::get_singleton()->print(" --benchmark-file <path> Benchmark the run time and save it to a given file in JSON format. The path should be absolute.\n");
#ifdef TESTS_ENABLED
@@ -558,9 +588,15 @@ Error Main::test_setup() {
ResourceLoader::load_path_remaps();
+ // Initialize ThemeDB early so that scene types can register their theme items.
+ // Default theme will be initialized later, after modules and ScriptServer are ready.
+ initialize_theme_db();
+
register_scene_types();
register_driver_types();
+ register_scene_singletons();
+
initialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE);
GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SCENE);
@@ -576,9 +612,9 @@ Error Main::test_setup() {
register_platform_apis();
// Theme needs modules to be initialized so that sub-resources can be loaded.
- initialize_theme_db();
- theme_db->initialize_theme();
- register_scene_singletons();
+ theme_db->initialize_theme_noproject();
+
+ initialize_navigation_server();
ERR_FAIL_COND_V(TextServerManager::get_singleton()->get_interface_count() == 0, ERR_CANT_CREATE);
@@ -638,6 +674,8 @@ void Main::test_cleanup() {
finalize_theme_db();
+ finalize_navigation_server();
+
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
unregister_server_types();
@@ -707,8 +745,7 @@ int Main::test_entrypoint(int argc, char *argv[], bool &tests_need_run) {
* responsible for the initialization of all low level singletons and core types, and parsing
* command line arguments to configure things accordingly.
* If p_second_phase is true, it will chain into setup2() (default behavior). This is
- * disabled on some platforms (Android, iOS, UWP) which trigger the second step in their
- * own time.
+ * disabled on some platforms (Android, iOS) which trigger the second step in their own time.
*
* - setup2(p_main_tid_override) registers high level servers and singletons, displays the
* boot splash, then registers higher level types (scene, editor, etc.).
@@ -856,6 +893,15 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->next()->get());
}
}
+ // If gpu is specified, both editor and debug instances started from editor will inherit.
+ if (I->get() == "--gpu-index") {
+ if (I->next()) {
+ forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get());
+ forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->next()->get());
+ forwardable_cli_arguments[CLI_SCOPE_PROJECT].push_back(I->get());
+ forwardable_cli_arguments[CLI_SCOPE_PROJECT].push_back(I->next()->get());
+ }
+ }
#endif
if (adding_user_args) {
@@ -914,6 +960,14 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->print("Missing audio driver argument, aborting.\n");
goto error;
}
+ } else if (I->get() == "--audio-output-latency") {
+ if (I->next()) {
+ audio_output_latency = I->next()->get().to_int();
+ N = I->next()->next();
+ } else {
+ OS::get_singleton()->print("Missing audio output latency argument, aborting.\n");
+ goto error;
+ }
} else if (I->get() == "--text-driver") {
if (I->next()) {
text_driver = I->next()->get();
@@ -976,13 +1030,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
goto error;
}
} else if (I->get() == "-f" || I->get() == "--fullscreen") { // force fullscreen
-
init_fullscreen = true;
+ window_mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
} else if (I->get() == "-m" || I->get() == "--maximized") { // force maximized window
-
init_maximized = true;
window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
-
} else if (I->get() == "-w" || I->get() == "--windowed") { // force windowed window
init_windowed = true;
@@ -1000,6 +1052,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (I->get() == "--gpu-abort") {
Engine::singleton->abort_on_gpu_errors = true;
#endif
+ } else if (I->get() == "--generate-spirv-debug-info") {
+ Engine::singleton->generate_spirv_debug_info = true;
} else if (I->get() == "--tablet-driver") {
if (I->next()) {
tablet_driver = I->next()->get();
@@ -1011,19 +1065,19 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else if (I->get() == "--delta-smoothing") {
if (I->next()) {
String string = I->next()->get();
- bool recognised = false;
+ bool recognized = false;
if (string == "enable") {
OS::get_singleton()->set_delta_smoothing(true);
delta_smoothing_override = true;
- recognised = true;
+ recognized = true;
}
if (string == "disable") {
OS::get_singleton()->set_delta_smoothing(false);
delta_smoothing_override = false;
- recognised = true;
+ recognized = true;
}
- if (!recognised) {
- OS::get_singleton()->print("Delta-smoothing argument not recognised, aborting.\n");
+ if (!recognized) {
+ OS::get_singleton()->print("Delta-smoothing argument not recognized, aborting.\n");
goto error;
}
N = I->next()->next();
@@ -1150,6 +1204,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
rtm = OS::RENDER_THREAD_UNSAFE;
} else if (I->next()->get() == "separate") {
rtm = OS::RENDER_SEPARATE_THREAD;
+ } else {
+ OS::get_singleton()->print("Unknown render thread mode, aborting.\nValid options are 'unsafe', 'safe' and 'separate'.\n");
+ goto error;
}
N = I->next()->next();
@@ -1202,6 +1259,17 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// run the project instead of a cmdline tool.
// Needs full refactoring to fix properly.
main_args.push_back(I->get());
+ } else if (I->get() == "--dump-extension-api-with-docs") {
+ // Register as an editor instance to use low-end fallback if relevant.
+ editor = true;
+ cmdline_tool = true;
+ dump_extension_api = true;
+ include_docs_in_extension_api_dump = true;
+ print_line("Dumping Extension API including documentation");
+ // Hack. Not needed but otherwise we end up detecting that this should
+ // run the project instead of a cmdline tool.
+ // Needs full refactoring to fix properly.
+ main_args.push_back(I->get());
} else if (I->get() == "--validate-extension-api") {
// Register as an editor instance to use low-end fallback if relevant.
editor = true;
@@ -1271,6 +1339,19 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
audio_driver = NULL_AUDIO_DRIVER;
display_driver = NULL_DISPLAY_DRIVER;
main_args.push_back(I->get());
+#ifdef MODULE_GDSCRIPT_ENABLED
+ } else if (I->get() == "--gdscript-docs") {
+ if (I->next()) {
+ project_path = I->next()->get();
+ // Will be handled in start()
+ main_args.push_back(I->get());
+ main_args.push_back(I->next()->get());
+ N = I->next()->next();
+ } else {
+ OS::get_singleton()->print("Missing relative or absolute path to project for --gdscript-docs, aborting.\n");
+ goto error;
+ }
+#endif // MODULE_GDSCRIPT_ENABLED
#endif // TOOLS_ENABLED
} else if (I->get() == "--path") { // set path of project to start or edit
@@ -1325,6 +1406,16 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
goto error;
}
+ } else if (I->get() == "--max-fps") { // set maximum rendered FPS
+
+ if (I->next()) {
+ max_fps = I->next()->get().to_int();
+ N = I->next()->next();
+ } else {
+ OS::get_singleton()->print("Missing maximum FPS argument, aborting.\n");
+ goto error;
+ }
+
} else if (I->get() == "--frame-delay") { // force frame delay
if (I->next()) {
@@ -1366,6 +1457,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
debug_navigation = true;
} else if (I->get() == "--debug-avoidance") {
debug_avoidance = true;
+ } else if (I->get() == "--debug-canvas-item-redraw") {
+ debug_canvas_item_redraw = true;
} else if (I->get() == "--debug-stringnames") {
StringName::set_debug_stringnames(true);
#endif
@@ -1453,7 +1546,21 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->print("Missing <path> argument for --benchmark-file <path>.\n");
goto error;
}
-
+#if defined(TOOLS_ENABLED) && defined(MODULE_GDSCRIPT_ENABLED) && !defined(GDSCRIPT_NO_LSP)
+ } else if (I->get() == "--lsp-port") {
+ if (I->next()) {
+ int port_override = I->next()->get().to_int();
+ if (port_override < 0 || port_override > 65535) {
+ OS::get_singleton()->print("<port> argument for --lsp-port <port> must be between 0 and 65535.\n");
+ goto error;
+ }
+ GDScriptLanguageServer::port_override = port_override;
+ N = I->next()->next();
+ } else {
+ OS::get_singleton()->print("Missing <port> argument for --lsp-port <port>.\n");
+ goto error;
+ }
+#endif // TOOLS_ENABLED && MODULE_GDSCRIPT_ENABLED && !GDSCRIPT_NO_LSP
} else if (I->get() == "--" || I->get() == "++") {
adding_user_args = true;
} else {
@@ -1518,6 +1625,13 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
}
+#ifdef TOOLS_ENABLED
+ if (editor) {
+ Engine::get_singleton()->set_editor_hint(true);
+ Engine::get_singleton()->set_extension_reloading_enabled(true);
+ }
+#endif
+
// Initialize user data dir.
OS::get_singleton()->ensure_user_data_dir();
@@ -1545,9 +1659,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#ifdef TOOLS_ENABLED
if (editor) {
packed_data->set_disabled(true);
- Engine::get_singleton()->set_editor_hint(true);
main_args.push_back("--editor");
- if (!init_windowed) {
+ if (!init_windowed && !init_fullscreen) {
init_maximized = true;
window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
}
@@ -1607,7 +1720,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
if (bool(GLOBAL_GET("application/run/disable_stderr"))) {
CoreGlobals::print_error_enabled = false;
- };
+ }
if (quiet_stdout) {
CoreGlobals::print_line_enabled = false;
@@ -1626,27 +1739,43 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
String default_driver = driver_hints.get_slice(",", 0);
// For now everything defaults to vulkan when available. This can change in future updates.
- GLOBAL_DEF("rendering/rendering_device/driver", default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.windows", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.android", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.ios", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.macos", PROPERTY_HINT_ENUM, driver_hints), default_driver);
-
- driver_hints = "";
+ GLOBAL_DEF_RST_NOVAL("rendering/rendering_device/driver", default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.windows", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.android", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.ios", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.macos", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ }
+
+ {
+ String driver_hints = "";
+ String driver_hints_angle = "";
+ String driver_hints_egl = "";
#ifdef GLES3_ENABLED
- driver_hints += "opengl3";
+ driver_hints = "opengl3";
+ driver_hints_angle = "opengl3,opengl3_angle";
+ driver_hints_egl = "opengl3,opengl3_es";
+#endif
+
+ String default_driver = driver_hints.get_slice(",", 0);
+ String default_driver_macos = default_driver;
+#if defined(GLES3_ENABLED) && defined(EGL_STATIC) && defined(MACOS_ENABLED)
+ default_driver_macos = "opengl3_angle"; // Default to ANGLE if it's built-in.
#endif
- default_driver = driver_hints.get_slice(",", 0);
+ GLOBAL_DEF_RST_NOVAL("rendering/gl_compatibility/driver", default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ENUM, driver_hints_angle), default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints_egl), default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.web", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.android", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.ios", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, driver_hints_angle), default_driver_macos);
+
+ GLOBAL_DEF_RST("rendering/gl_compatibility/nvidia_disable_threaded_optimization", true);
+ GLOBAL_DEF_RST("rendering/gl_compatibility/fallback_to_angle", true);
+ GLOBAL_DEF_RST("rendering/gl_compatibility/fallback_to_native", true);
- GLOBAL_DEF("rendering/gl_compatibility/driver", default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.web", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.android", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.ios", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ GLOBAL_DEF_RST(PropertyInfo(Variant::ARRAY, "rendering/gl_compatibility/force_angle_on_devices", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::DICTIONARY, PROPERTY_HINT_NONE, String())), Array());
}
// Start with RenderingDevice-based backends. Should be included if any RD driver present.
@@ -1720,7 +1849,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// Set a default renderer if none selected. Try to choose one that matches the driver.
if (rendering_method.is_empty()) {
- if (rendering_driver == "opengl3") {
+ if (rendering_driver == "opengl3" || rendering_driver == "opengl3_angle" || rendering_driver == "opengl3_es") {
rendering_method = "gl_compatibility";
} else {
rendering_method = "forward_plus";
@@ -1738,6 +1867,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#ifdef GLES3_ENABLED
if (rendering_method == "gl_compatibility") {
available_drivers.push_back("opengl3");
+ available_drivers.push_back("opengl3_angle");
+ available_drivers.push_back("opengl3_es");
}
#endif
if (available_drivers.is_empty()) {
@@ -1830,21 +1961,31 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int());
int initial_position_type = GLOBAL_GET("display/window/size/initial_position_type").operator int();
- if (initial_position_type == 0) {
+ if (initial_position_type == 0) { // Absolute.
if (!init_use_custom_pos) {
init_custom_pos = GLOBAL_GET("display/window/size/initial_position").operator Vector2i();
init_use_custom_pos = true;
}
- } else if (initial_position_type == 1) {
+ } else if (initial_position_type == 1) { // Center of Primary Screen.
if (!init_use_custom_screen) {
init_screen = DisplayServer::SCREEN_PRIMARY;
init_use_custom_screen = true;
}
- } else if (initial_position_type == 2) {
+ } else if (initial_position_type == 2) { // Center of Other Screen.
if (!init_use_custom_screen) {
init_screen = GLOBAL_GET("display/window/size/initial_screen").operator int();
init_use_custom_screen = true;
}
+ } else if (initial_position_type == 3) { // Center of Screen With Mouse Pointer.
+ if (!init_use_custom_screen) {
+ init_screen = DisplayServer::SCREEN_WITH_MOUSE_FOCUS;
+ init_use_custom_screen = true;
+ }
+ } else if (initial_position_type == 4) { // Center of Screen With Keyboard Focus.
+ if (!init_use_custom_screen) {
+ init_screen = DisplayServer::SCREEN_WITH_KEYBOARD_FOCUS;
+ init_use_custom_screen = true;
+ }
}
}
@@ -1874,7 +2015,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
if (rtm >= 0 && rtm < 3) {
- if (editor) {
+ if (editor || project_manager) {
+ // Editor and project manager cannot run with rendering in a separate thread (they will crash on startup).
rtm = OS::RENDER_THREAD_SAFE;
}
OS::get_singleton()->_render_thread_mode = OS::RenderThreadMode(rtm);
@@ -1942,6 +2084,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
Engine::get_singleton()->set_max_physics_steps_per_frame(GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "physics/common/max_physics_steps_per_frame", PROPERTY_HINT_RANGE, "1,100,1"), 8));
Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
Engine::get_singleton()->set_max_fps(GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/max_fps", PROPERTY_HINT_RANGE, "0,1000,1"), 0));
+ Engine::get_singleton()->set_audio_output_latency(GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "audio/driver/output_latency", PROPERTY_HINT_RANGE, "1,100,1"), 15));
+ // Use a safer default output_latency for web to avoid audio cracking on low-end devices, especially mobile.
+ GLOBAL_DEF_RST("audio/driver/output_latency.web", 50);
GLOBAL_DEF("debug/settings/stdout/print_fps", false);
GLOBAL_DEF("debug/settings/stdout/print_gpu_profile", false);
@@ -1951,10 +2096,22 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->_verbose_stdout = GLOBAL_GET("debug/settings/stdout/verbose_stdout");
}
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
+ OS::get_singleton()->set_environment("MVK_CONFIG_LOG_LEVEL", OS::get_singleton()->_verbose_stdout ? "3" : "1"); // 1 = Errors only, 3 = Info
+#endif
+
+ if (max_fps >= 0) {
+ Engine::get_singleton()->set_max_fps(max_fps);
+ }
+
if (frame_delay == 0) {
frame_delay = GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/frame_delay_msec", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), 0);
}
+ if (audio_output_latency >= 1) {
+ Engine::get_singleton()->set_audio_output_latency(audio_output_latency);
+ }
+
OS::get_singleton()->set_low_processor_usage_mode(GLOBAL_DEF("application/run/low_processor_mode", false));
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(
GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "0,33200,1,or_greater"), 6900)); // Roughly 144 FPS
@@ -1975,10 +2132,17 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/form_factor", PROPERTY_HINT_ENUM, "Head Mounted,Handheld"), "0");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/view_configuration", PROPERTY_HINT_ENUM, "Mono,Stereo"), "1"); // "Mono,Stereo,Quad,Observer"
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/reference_space", PROPERTY_HINT_ENUM, "Local,Stage"), "1");
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/environment_blend_mode", PROPERTY_HINT_ENUM, "Opaque,Additive,Alpha"), "0");
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/foveation_level", PROPERTY_HINT_ENUM, "Off,Low,Medium,High"), "0");
+ GLOBAL_DEF_BASIC("xr/openxr/foveation_dynamic", false);
GLOBAL_DEF_BASIC("xr/openxr/submit_depth_buffer", false);
GLOBAL_DEF_BASIC("xr/openxr/startup_alert", true);
+ // OpenXR project extensions settings.
+ GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking", true);
+ GLOBAL_DEF_BASIC("xr/openxr/extensions/eye_gaze_interaction", false);
+
#ifdef TOOLS_ENABLED
// Disabled for now, using XR inside of the editor we'll be working on during the coming months.
@@ -2060,6 +2224,25 @@ error:
return exit_code;
}
+Error _parse_resource_dummy(void *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
+ VariantParser::Token token;
+ VariantParser::get_token(p_stream, token, line, r_err_str);
+ if (token.type != VariantParser::TK_NUMBER && token.type != VariantParser::TK_STRING) {
+ r_err_str = "Expected number (old style sub-resource index) or String (ext-resource ID)";
+ return ERR_PARSE_ERROR;
+ }
+
+ r_res.unref();
+
+ VariantParser::get_token(p_stream, token, line, r_err_str);
+ if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
+ r_err_str = "Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+ return OK;
+}
+
Error Main::setup2() {
Thread::make_main_thread(); // Make whatever thread call this the main thread.
set_current_thread_safe_for_nodes(true);
@@ -2091,6 +2274,8 @@ Error Main::setup2() {
// Editor setting class is not available, load config directly.
if (!init_use_custom_screen && (editor || project_manager) && EditorPaths::get_singleton()->are_paths_valid()) {
Ref<DirAccess> dir = DirAccess::open(EditorPaths::get_singleton()->get_config_dir());
+ ERR_FAIL_COND_V(dir.is_null(), FAILED);
+
String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres";
String config_file_path = EditorPaths::get_singleton()->get_config_dir().path_join(config_file_name);
if (dir->file_exists(config_file_name)) {
@@ -2107,12 +2292,16 @@ Error Main::setup2() {
int lines = 0;
String error_text;
+ VariantParser::ResourceParser rp_new;
+ rp_new.ext_func = _parse_resource_dummy;
+ rp_new.sub_func = _parse_resource_dummy;
+
while (true) {
assign = Variant();
next_tag.fields.clear();
next_tag.name = String();
- err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true);
+ err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new, true);
if (err == ERR_FILE_EOF) {
break;
}
@@ -2208,6 +2397,10 @@ Error Main::setup2() {
}
}
+ if (OS::get_singleton()->_render_thread_mode == OS::RENDER_SEPARATE_THREAD) {
+ WARN_PRINT("The Multi-Threaded rendering thread model is experimental, and has known issues which can lead to project crashes. Use the Single-Safe option in the project settings instead.");
+ }
+
/* Initialize Pen Tablet Driver */
{
@@ -2387,6 +2580,9 @@ Error Main::setup2() {
id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true)));
}
+ GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
+ GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
+
MAIN_PRINT("Main: Load Translations and Remaps");
translation_server->setup(); //register translations, load them, etc.
@@ -2464,9 +2660,15 @@ Error Main::setup2() {
OS::get_singleton()->benchmark_begin_measure("scene");
+ // Initialize ThemeDB early so that scene types can register their theme items.
+ // Default theme will be initialized later, after modules and ScriptServer are ready.
+ initialize_theme_db();
+
register_scene_types();
register_driver_types();
+ register_scene_singletons();
+
initialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE);
GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SCENE);
@@ -2484,11 +2686,6 @@ Error Main::setup2() {
register_platform_apis();
- // Theme needs modules to be initialized so that sub-resources can be loaded.
- // Default theme is initialized later, after ScriptServer is ready.
- initialize_theme_db();
- register_scene_singletons();
-
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/mouse_cursor/custom_image", PROPERTY_HINT_FILE, "*.png,*.webp"), String());
GLOBAL_DEF_BASIC("display/mouse_cursor/custom_image_hotspot", Vector2());
GLOBAL_DEF_BASIC("display/mouse_cursor/tooltip_position_offset", Point2(10, 10));
@@ -2566,6 +2763,7 @@ bool Main::start() {
String positional_arg;
String game_path;
String script;
+ String main_loop_type;
bool check_only = false;
#ifdef TOOLS_ENABLED
@@ -2629,6 +2827,8 @@ bool Main::start() {
bool parsed_pair = true;
if (args[i] == "-s" || args[i] == "--script") {
script = args[i + 1];
+ } else if (args[i] == "--main-loop") {
+ main_loop_type = args[i + 1];
#ifdef TOOLS_ENABLED
} else if (args[i] == "--doctool") {
doc_tool_path = args[i + 1];
@@ -2670,41 +2870,16 @@ bool Main::start() {
}
uint64_t minimum_time_msec = GLOBAL_DEF(PropertyInfo(Variant::INT, "application/boot_splash/minimum_display_time", PROPERTY_HINT_RANGE, "0,100,1,or_greater,suffix:ms"), 0);
+ if (Engine::get_singleton()->is_editor_hint()) {
+ minimum_time_msec = 0;
+ }
#ifdef TOOLS_ENABLED
#ifdef MODULE_GDSCRIPT_ENABLED
- if (!doc_tool_path.is_empty() && !gdscript_docs_path.is_empty()) {
- DocTools docs;
- Error err;
-
- Vector<String> paths = get_files_with_extension(gdscript_docs_path, "gd");
- ERR_FAIL_COND_V_MSG(paths.size() == 0, false, "Couldn't find any GDScript files under the given directory: " + gdscript_docs_path);
-
- for (const String &path : paths) {
- Ref<GDScript> gdscript = ResourceLoader::load(path);
- for (const DocData::ClassDoc &class_doc : gdscript->get_documentation()) {
- docs.add_doc(class_doc);
- }
- }
-
- if (doc_tool_path == ".") {
- doc_tool_path = "./docs";
- }
-
- Ref<DirAccess> da = DirAccess::create_for_path(doc_tool_path);
- err = da->make_dir_recursive(doc_tool_path);
- ERR_FAIL_COND_V_MSG(err != OK, false, "Error: Can't create GDScript docs directory: " + doc_tool_path + ": " + itos(err));
-
- HashMap<String, String> doc_data_classes;
- err = docs.save_classes(doc_tool_path, doc_data_classes, false);
- ERR_FAIL_COND_V_MSG(err != OK, false, "Error saving GDScript docs:" + itos(err));
-
- OS::get_singleton()->set_exit_code(EXIT_SUCCESS);
- return false;
- }
-#endif // MODULE_GDSCRIPT_ENABLED
-
+ if (!doc_tool_path.is_empty() && gdscript_docs_path.is_empty()) {
+#else
if (!doc_tool_path.is_empty()) {
+#endif
// Needed to instance editor-only classes for their default values
Engine::get_singleton()->set_editor_hint(true);
@@ -2724,6 +2899,7 @@ bool Main::start() {
// Default values should be synced with mono_gd/gd_mono.cpp.
GLOBAL_DEF("dotnet/project/assembly_name", "");
GLOBAL_DEF("dotnet/project/solution_directory", "");
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "dotnet/project/assembly_reload_attempts", PROPERTY_HINT_RANGE, "1,16,1,or_greater"), 3);
#endif
Error err;
@@ -2795,7 +2971,8 @@ bool Main::start() {
}
if (dump_extension_api) {
- GDExtensionAPIDump::generate_extension_json_file("extension_api.json");
+ Engine::get_singleton()->set_editor_hint(true); // "extension_api.json" should always contains editor singletons.
+ GDExtensionAPIDump::generate_extension_json_file("extension_api.json", include_docs_in_extension_api_dump);
}
if (dump_gdextension_interface || dump_extension_api) {
@@ -2847,7 +3024,9 @@ bool Main::start() {
if (editor) {
main_loop = memnew(SceneTree);
}
- String main_loop_type = GLOBAL_GET("application/run/main_loop_type");
+ if (main_loop_type.is_empty()) {
+ main_loop_type = GLOBAL_GET("application/run/main_loop_type");
+ }
if (!script.is_empty()) {
Ref<Script> script_res = ResourceLoader::load(script);
@@ -2874,7 +3053,7 @@ bool Main::start() {
ERR_FAIL_V_MSG(false, vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script));
}
- script_loop->set_initialize_script(script_res);
+ script_loop->set_script(script_res);
main_loop = script_loop;
} else {
return false;
@@ -2897,7 +3076,7 @@ bool Main::start() {
OS::get_singleton()->alert("Error: Invalid MainLoop script base type: " + script_base);
ERR_FAIL_V_MSG(false, vformat("The global class %s does not inherit from SceneTree or MainLoop.", main_loop_type));
}
- script_loop->set_initialize_script(script_res);
+ script_loop->set_script(script_res);
main_loop = script_loop;
}
}
@@ -2912,7 +3091,7 @@ bool Main::start() {
return false;
} else {
Object *ml = ClassDB::instantiate(main_loop_type);
- ERR_FAIL_COND_V_MSG(!ml, false, "Can't instance MainLoop type.");
+ ERR_FAIL_NULL_V_MSG(ml, false, "Can't instance MainLoop type.");
main_loop = Object::cast_to<MainLoop>(ml);
if (!main_loop) {
@@ -2922,6 +3101,8 @@ bool Main::start() {
}
}
+ OS::get_singleton()->set_main_loop(main_loop);
+
SceneTree *sml = Object::cast_to<SceneTree>(main_loop);
if (sml) {
#ifdef DEBUG_ENABLED
@@ -2933,19 +3114,17 @@ bool Main::start() {
}
if (debug_navigation) {
sml->set_debug_navigation_hint(true);
+ NavigationServer3D::get_singleton()->set_debug_navigation_enabled(true);
}
if (debug_avoidance) {
- sml->set_debug_avoidance_hint(true);
+ NavigationServer3D::get_singleton()->set_debug_avoidance_enabled(true);
}
if (debug_navigation || debug_avoidance) {
NavigationServer3D::get_singleton()->set_active(true);
NavigationServer3D::get_singleton()->set_debug_enabled(true);
- if (debug_navigation) {
- NavigationServer3D::get_singleton()->set_debug_navigation_enabled(true);
- }
- if (debug_avoidance) {
- NavigationServer3D::get_singleton()->set_debug_avoidance_enabled(true);
- }
+ }
+ if (debug_canvas_item_redraw) {
+ RenderingServer::get_singleton()->canvas_item_set_debug_redraw(true);
}
#endif
@@ -3036,6 +3215,38 @@ bool Main::start() {
}
#ifdef TOOLS_ENABLED
+#ifdef MODULE_GDSCRIPT_ENABLED
+ if (!doc_tool_path.is_empty() && !gdscript_docs_path.is_empty()) {
+ DocTools docs;
+ Error err;
+
+ Vector<String> paths = get_files_with_extension(gdscript_docs_path, "gd");
+ ERR_FAIL_COND_V_MSG(paths.size() == 0, false, "Couldn't find any GDScript files under the given directory: " + gdscript_docs_path);
+
+ for (const String &path : paths) {
+ Ref<GDScript> gdscript = ResourceLoader::load(path);
+ for (const DocData::ClassDoc &class_doc : gdscript->get_documentation()) {
+ docs.add_doc(class_doc);
+ }
+ }
+
+ if (doc_tool_path == ".") {
+ doc_tool_path = "./docs";
+ }
+
+ Ref<DirAccess> da = DirAccess::create_for_path(doc_tool_path);
+ err = da->make_dir_recursive(doc_tool_path);
+ ERR_FAIL_COND_V_MSG(err != OK, false, "Error: Can't create GDScript docs directory: " + doc_tool_path + ": " + itos(err));
+
+ HashMap<String, String> doc_data_classes;
+ err = docs.save_classes(doc_tool_path, doc_data_classes, false);
+ ERR_FAIL_COND_V_MSG(err != OK, false, "Error saving GDScript docs:" + itos(err));
+
+ OS::get_singleton()->set_exit_code(EXIT_SUCCESS);
+ return false;
+ }
+#endif // MODULE_GDSCRIPT_ENABLED
+
EditorNode *editor_node = nullptr;
if (editor) {
OS::get_singleton()->benchmark_begin_measure("editor");
@@ -3061,6 +3272,7 @@ bool Main::start() {
Size2i stretch_size = Size2i(GLOBAL_GET("display/window/size/viewport_width"),
GLOBAL_GET("display/window/size/viewport_height"));
real_t stretch_scale = GLOBAL_GET("display/window/stretch/scale");
+ String stretch_scale_mode = GLOBAL_GET("display/window/stretch/scale_mode");
Window::ContentScaleMode cs_sm = Window::CONTENT_SCALE_MODE_DISABLED;
if (stretch_mode == "canvas_items") {
@@ -3080,8 +3292,14 @@ bool Main::start() {
cs_aspect = Window::CONTENT_SCALE_ASPECT_EXPAND;
}
+ Window::ContentScaleStretch cs_stretch = Window::CONTENT_SCALE_STRETCH_FRACTIONAL;
+ if (stretch_scale_mode == "integer") {
+ cs_stretch = Window::CONTENT_SCALE_STRETCH_INTEGER;
+ }
+
sml->get_root()->set_content_scale_mode(cs_sm);
sml->get_root()->set_content_scale_aspect(cs_aspect);
+ sml->get_root()->set_content_scale_stretch(cs_stretch);
sml->get_root()->set_content_scale_size(stretch_size);
sml->get_root()->set_content_scale_factor(stretch_scale);
@@ -3140,6 +3358,8 @@ bool Main::start() {
if (sep == -1) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), false);
+
local_game_path = da->get_current_dir().path_join(local_game_path);
} else {
Ref<DirAccess> da = DirAccess::open(local_game_path.substr(0, sep));
@@ -3188,7 +3408,7 @@ bool Main::start() {
scene = scenedata->instantiate();
}
- ERR_FAIL_COND_V_MSG(!scene, false, "Failed loading scene: " + local_game_path);
+ ERR_FAIL_NULL_V_MSG(scene, false, "Failed loading scene: " + local_game_path + ".");
sml->add_current_scene(scene);
#ifdef MACOS_ENABLED
@@ -3246,8 +3466,6 @@ bool Main::start() {
DisplayServer::get_singleton()->set_icon(icon);
}
- OS::get_singleton()->set_main_loop(main_loop);
-
if (movie_writer) {
movie_writer->begin(DisplayServer::get_singleton()->window_get_size(), fixed_fps, Engine::get_singleton()->get_write_movie_path());
}
@@ -3337,6 +3555,9 @@ bool Main::iteration() {
// process all our active interfaces
XRServer::get_singleton()->_process();
+ NavigationServer2D::get_singleton()->sync();
+ NavigationServer3D::get_singleton()->sync();
+
for (int iters = 0; iters < advance.physics_steps; ++iters) {
if (Input::get_singleton()->is_using_input_buffering() && agile_input_event_flushing) {
Input::get_singleton()->flush_buffered_events();