/**************************************************************************/ /* main.cpp */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /**************************************************************************/ /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ #include "main.h" #include "core/config/project_settings.h" #include "core/core_globals.h" #include "core/core_string_names.h" #include "core/crypto/crypto.h" #include "core/debugger/engine_debugger.h" #include "core/extension/extension_api_dump.h" #include "core/extension/gdextension_interface_dump.gen.h" #include "core/extension/gdextension_manager.h" #include "core/input/input.h" #include "core/input/input_map.h" #include "core/io/dir_access.h" #include "core/io/file_access_pack.h" #include "core/io/file_access_zip.h" #include "core/io/image_loader.h" #include "core/io/ip.h" #include "core/io/resource_loader.h" #include "core/object/message_queue.h" #include "core/os/os.h" #include "core/os/time.h" #include "core/register_core_types.h" #include "core/string/translation.h" #include "core/version.h" #include "drivers/register_driver_types.h" #include "main/app_icon.gen.h" #include "main/main_timer_sync.h" #include "main/performance.h" #include "main/splash.gen.h" #include "modules/register_module_types.h" #include "platform/register_platform_apis.h" #include "scene/main/scene_tree.h" #include "scene/main/window.h" #include "scene/register_scene_types.h" #include "scene/resources/packed_scene.h" #include "scene/theme/theme_db.h" #include "servers/audio_server.h" #include "servers/camera_server.h" #include "servers/display_server.h" #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" #include "servers/physics_server_3d.h" #include "servers/register_server_types.h" #include "servers/rendering/rendering_server_default.h" #include "servers/text/text_server_dummy.h" #include "servers/text_server.h" #include "servers/xr_server.h" #ifdef TESTS_ENABLED #include "tests/test_main.h" #endif #ifdef TOOLS_ENABLED #include "editor/debugger/editor_debugger_node.h" #include "editor/doc_data_class_path.gen.h" #include "editor/doc_tools.h" #include "editor/editor_file_system.h" #include "editor/editor_help.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" #include "editor/editor_settings.h" #include "editor/editor_translation.h" #include "editor/progress_dialog.h" #include "editor/project_manager.h" #include "editor/register_editor_types.h" #ifndef NO_EDITOR_SPLASH #include "main/splash_editor.gen.h" #endif #ifndef DISABLE_DEPRECATED #include "editor/project_converter_3_to_4.h" #endif // DISABLE_DEPRECATED #endif // TOOLS_ENABLED #include "modules/modules_enabled.gen.h" // For mono. #if defined(MODULE_MONO_ENABLED) && defined(TOOLS_ENABLED) #include "modules/mono/editor/bindings_generator.h" #endif #ifdef MODULE_GDSCRIPT_ENABLED #include "modules/gdscript/gdscript.h" #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 */ // Singletons // Initialized in setup() static Engine *engine = nullptr; static ProjectSettings *globals = nullptr; static Input *input = nullptr; static InputMap *input_map = nullptr; static TranslationServer *translation_server = nullptr; static Performance *performance = nullptr; static PackedData *packed_data = nullptr; static Time *time_singleton = nullptr; #ifdef MINIZIP_ENABLED static ZipArchive *zip_packed_data = nullptr; #endif static MessageQueue *message_queue = nullptr; // Initialized in setup2() static AudioServer *audio_server = nullptr; static DisplayServer *display_server = nullptr; static RenderingServer *rendering_server = nullptr; static CameraServer *camera_server = nullptr; static XRServer *xr_server = nullptr; static TextServerManager *tsman = nullptr; static PhysicsServer3DManager *physics_server_3d_manager = nullptr; static PhysicsServer3D *physics_server_3d = nullptr; static PhysicsServer2DManager *physics_server_2d_manager = nullptr; static PhysicsServer2D *physics_server_2d = nullptr; static NavigationServer3D *navigation_server_3d = nullptr; static NavigationServer2D *navigation_server_2d = nullptr; static ThemeDB *theme_db = nullptr; // We error out if setup2() doesn't turn this true static bool _start_success = false; // Drivers String tablet_driver = ""; String text_driver = ""; String rendering_driver = ""; String rendering_method = ""; static int text_driver_idx = -1; static int display_driver_idx = -1; static int audio_driver_idx = -1; // Engine config/tools static bool single_window = false; static bool editor = false; static bool project_manager = false; static bool cmdline_tool = false; static String locale; static bool show_help = false; static uint64_t quit_after = 0; static OS::ProcessID editor_pid = 0; #ifdef TOOLS_ENABLED static bool found_project = false; static bool auto_build_solutions = false; static String debug_server_uri; static bool wait_for_import = false; #ifndef DISABLE_DEPRECATED static int converter_max_kb_file = 4 * 1024; // 4MB static int converter_max_line_length = 100000; #endif // DISABLE_DEPRECATED HashMap> forwardable_cli_arguments; #endif static bool single_threaded_scene = false; // Display static DisplayServer::WindowMode window_mode = DisplayServer::WINDOW_MODE_WINDOWED; static DisplayServer::ScreenOrientation window_orientation = DisplayServer::SCREEN_LANDSCAPE; static DisplayServer::VSyncMode window_vsync_mode = DisplayServer::VSYNC_ENABLED; static uint32_t window_flags = 0; static Size2i window_size = Size2i(1152, 648); static int init_screen = DisplayServer::SCREEN_PRIMARY; static bool init_fullscreen = false; static bool init_maximized = false; static bool init_windowed = false; static bool init_always_on_top = false; static bool init_use_custom_pos = false; static bool init_use_custom_screen = false; static Vector2 init_custom_pos; // Debug static bool use_debug_profiler = false; #ifdef DEBUG_ENABLED 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; static bool disable_vsync = false; 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 bool profile_gpu = false; // Constants. static const String NULL_DISPLAY_DRIVER("headless"); static const String NULL_AUDIO_DRIVER("Dummy"); /* Helper methods */ bool Main::is_cmdline_tool() { return cmdline_tool; } #ifdef TOOLS_ENABLED const Vector &Main::get_forwardable_cli_arguments(Main::CLIScope p_scope) { return forwardable_cli_arguments[p_scope]; } #endif static String unescape_cmdline(const String &p_str) { return p_str.replace("%20", " "); } static String get_full_version_string() { String hash = String(VERSION_HASH); if (!hash.is_empty()) { hash = "." + hash.left(9); } return String(VERSION_FULL_BUILD) + hash; } #if defined(TOOLS_ENABLED) && defined(MODULE_GDSCRIPT_ENABLED) static Vector get_files_with_extension(const String &p_root, const String &p_extension) { Vector paths; Ref dir = DirAccess::open(p_root); if (dir.is_valid()) { dir->list_dir_begin(); String fn = dir->get_next(); while (!fn.is_empty()) { if (!dir->current_is_hidden() && fn != "." && fn != "..") { if (dir->current_is_dir()) { paths.append_array(get_files_with_extension(p_root.path_join(fn), p_extension)); } else if (fn.get_extension() == p_extension) { paths.append(p_root.path_join(fn)); } } fn = dir->get_next(); } dir->list_dir_end(); } return paths; } #endif // FIXME: Could maybe be moved to have less code in main.cpp. void initialize_physics() { /// 3D Physics Server physics_server_3d = PhysicsServer3DManager::get_singleton()->new_server( GLOBAL_GET(PhysicsServer3DManager::setting_property_name)); if (!physics_server_3d) { // Physics server not found, Use the default physics physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server(); } ERR_FAIL_NULL(physics_server_3d); physics_server_3d->init(); // 2D Physics server physics_server_2d = PhysicsServer2DManager::get_singleton()->new_server( GLOBAL_GET(PhysicsServer2DManager::get_singleton()->setting_property_name)); if (!physics_server_2d) { // Physics server not found, Use the default physics physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server(); } ERR_FAIL_NULL(physics_server_2d); physics_server_2d->init(); } void finalize_physics() { physics_server_3d->finish(); memdelete(physics_server_3d); physics_server_2d->finish(); memdelete(physics_server_2d); } void finalize_display() { rendering_server->finish(); memdelete(rendering_server); memdelete(display_server); } 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(); // Fall back to dummy if no default server has been registered. if (!navigation_server_3d) { WARN_PRINT_ONCE("No NavigationServer3D implementation has been registered! Falling back to a dummy implementation: navigation features will be unavailable."); navigation_server_3d = memnew(NavigationServer3DDummy); } // 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 = 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; } void initialize_theme_db() { theme_db = memnew(ThemeDB); } void finalize_theme_db() { memdelete(theme_db); theme_db = nullptr; } //#define DEBUG_INIT #ifdef DEBUG_INIT #define MAIN_PRINT(m_txt) print_line(m_txt) #else #define MAIN_PRINT(m_txt) #endif void Main::print_help(const char *p_binary) { print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); OS::get_singleton()->print("Free and open source software under the terms of the MIT license.\n"); OS::get_singleton()->print("(c) 2014-present Godot Engine contributors.\n"); OS::get_singleton()->print("(c) 2007-2014 Juan Linietsky, Ariel Manzur.\n"); OS::get_singleton()->print("\n"); OS::get_singleton()->print("Usage: %s [options] [path to scene or 'project.godot' file]\n", p_binary); OS::get_singleton()->print("\n"); OS::get_singleton()->print("General options:\n"); OS::get_singleton()->print(" -h, --help Display this help message.\n"); OS::get_singleton()->print(" --version Display the version string.\n"); OS::get_singleton()->print(" -v, --verbose Use verbose stdout mode.\n"); OS::get_singleton()->print(" -q, --quiet Quiet mode, silences stdout messages. Errors are still displayed.\n"); OS::get_singleton()->print("\n"); OS::get_singleton()->print("Run options:\n"); OS::get_singleton()->print(" --, ++ Separator for user-provided arguments. Following arguments are not used by the engine, but can be read from `OS.get_cmdline_user_args()`.\n"); #ifdef TOOLS_ENABLED 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 Start the editor debug server (://[:], e.g. tcp://127.0.0.1:6007)\n"); #if defined(MODULE_GDSCRIPT_ENABLED) && !defined(GDSCRIPT_NO_LSP) OS::get_singleton()->print(" --lsp-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 Quit after the given number of iterations. Set to 0 to disable.\n"); OS::get_singleton()->print(" -l, --language Use a specific locale ( being a two-letter code).\n"); OS::get_singleton()->print(" --path Path to a project ( must contain a 'project.godot' file).\n"); OS::get_singleton()->print(" -u, --upwards Scan folders upwards for project.godot file.\n"); OS::get_singleton()->print(" --main-pack Path to a pack (.pck) file to load.\n"); OS::get_singleton()->print(" --render-thread Render thread mode ['unsafe', 'safe', 'separate'].\n"); OS::get_singleton()->print(" --remote-fs
Remote filesystem ([:] address).\n"); OS::get_singleton()->print(" --remote-fs-password Password for remote filesystem.\n"); OS::get_singleton()->print(" --audio-driver Audio driver ["); for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) { if (i > 0) { OS::get_singleton()->print(", "); } OS::get_singleton()->print("'%s'", AudioDriverManager::get_driver(i)->get_name()); } OS::get_singleton()->print("].\n"); OS::get_singleton()->print(" --display-driver Display driver (and rendering driver) ["); for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { if (i > 0) { OS::get_singleton()->print(", "); } OS::get_singleton()->print("'%s' (", DisplayServer::get_create_function_name(i)); Vector rd = DisplayServer::get_create_function_rendering_drivers(i); for (int j = 0; j < rd.size(); j++) { if (j > 0) { OS::get_singleton()->print(", "); } OS::get_singleton()->print("'%s'", rd[j].utf8().get_data()); } OS::get_singleton()->print(")"); } OS::get_singleton()->print("].\n"); OS::get_singleton()->print(" --audio-output-latency 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 name. Requires driver support.\n"); OS::get_singleton()->print(" --rendering-driver Rendering driver (depends on display driver).\n"); OS::get_singleton()->print(" --gpu-index Use a specific GPU (run with --verbose to get available device list).\n"); OS::get_singleton()->print(" --text-driver Text driver (Fonts, BiDi, shaping).\n"); OS::get_singleton()->print(" --tablet-driver Pen tablet input driver.\n"); OS::get_singleton()->print(" --headless Enable headless mode (--display-driver headless --audio-driver Dummy). Useful for servers and with --script.\n"); OS::get_singleton()->print(" --write-movie Writes a video to the specified path (usually with .avi or .png extension).\n"); OS::get_singleton()->print(" --fixed-fps is forced when enabled, but it can be used to change movie FPS.\n"); OS::get_singleton()->print(" --disable-vsync can speed up movie writing but makes interaction more difficult.\n"); OS::get_singleton()->print(" --quit-after can be used to specify the number of frames to write.\n"); OS::get_singleton()->print("\n"); OS::get_singleton()->print("Display options:\n"); OS::get_singleton()->print(" -f, --fullscreen Request fullscreen mode.\n"); OS::get_singleton()->print(" -m, --maximized Request a maximized window.\n"); OS::get_singleton()->print(" -w, --windowed Request windowed mode.\n"); OS::get_singleton()->print(" -t, --always-on-top Request an always-on-top window.\n"); OS::get_singleton()->print(" --resolution x Request window resolution.\n"); OS::get_singleton()->print(" --position , Request window position (if set, screen argument is ignored).\n"); OS::get_singleton()->print(" --screen Request window screen.\n"); OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n"); OS::get_singleton()->print(" --xr-mode Select XR (Extended Reality) mode ['default', 'off', 'on'].\n"); OS::get_singleton()->print("\n"); OS::get_singleton()->print("Debug options:\n"); OS::get_singleton()->print(" -d, --debug Debug (local stdout debugger).\n"); OS::get_singleton()->print(" -b, --breakpoints Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n"); OS::get_singleton()->print(" --profiling Enable profiling in the script debugger.\n"); OS::get_singleton()->print(" --gpu-profile Show a GPU profile of the tasks that took the most time during frame rendering.\n"); OS::get_singleton()->print(" --gpu-validation Enable graphics API validation layers for debugging.\n"); #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 Remote debug (://[:], 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) OS::get_singleton()->print(" --debug-collisions Show collision shapes when running the scene.\n"); OS::get_singleton()->print(" --debug-paths Show path lines when running the scene.\n"); 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(" --max-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 Simulate high CPU load (delay each frame by milliseconds). Do not use as a FPS limiter; use --max-fps instead.\n"); OS::get_singleton()->print(" --time-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"); OS::get_singleton()->print(" --disable-crash-handler Disable crash handler when supported by the platform code.\n"); OS::get_singleton()->print(" --fixed-fps Force a fixed number of frames per second. This setting disables real-time synchronization.\n"); OS::get_singleton()->print(" --delta-smoothing Enable or disable frame delta smoothing ['enable', 'disable'].\n"); OS::get_singleton()->print(" --print-fps Print the frames per second to the stdout.\n"); OS::get_singleton()->print("\n"); OS::get_singleton()->print("Standalone tools:\n"); OS::get_singleton()->print(" -s, --script