2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* 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. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "main.h"
2017-08-19 16:45:03 +02:00
2020-11-07 23:33:38 +01:00
# include "core/config/project_settings.h"
2022-05-20 14:28:44 +02:00
# include "core/core_globals.h"
2020-07-20 18:35:34 +02:00
# include "core/core_string_names.h"
2019-07-19 15:29:57 +02:00
# include "core/crypto/crypto.h"
2020-02-27 03:30:20 +01:00
# include "core/debugger/engine_debugger.h"
2021-06-19 17:58:49 +02:00
# include "core/extension/extension_api_dump.h"
2022-12-07 12:11:28 +01:00
# include "core/extension/gdextension_interface_dump.gen.h"
# include "core/extension/gdextension_manager.h"
2020-04-28 15:19:37 +02:00
# include "core/input/input.h"
2020-03-01 23:14:37 +01:00
# include "core/input/input_map.h"
2021-06-11 14:51:48 +02:00
# include "core/io/dir_access.h"
2018-09-11 18:13:45 +02:00
# include "core/io/file_access_pack.h"
# include "core/io/file_access_zip.h"
2018-09-30 17:21:07 +02:00
# include "core/io/image_loader.h"
2018-09-11 18:13:45 +02:00
# include "core/io/ip.h"
# include "core/io/resource_loader.h"
2020-11-07 23:33:38 +01:00
# include "core/object/message_queue.h"
2018-09-11 18:13:45 +02:00
# include "core/os/os.h"
2021-05-24 13:54:05 +02:00
# include "core/os/time.h"
2014-02-10 02:10:30 +01:00
# include "core/register_core_types.h"
2020-11-07 23:33:38 +01:00
# include "core/string/translation.h"
2018-09-11 18:13:45 +02:00
# include "core/version.h"
2014-02-10 02:10:30 +01:00
# include "drivers/register_driver_types.h"
2018-09-11 18:13:45 +02:00
# include "main/app_icon.gen.h"
2019-02-12 14:23:35 +01:00
# include "main/main_timer_sync.h"
2018-09-11 18:13:45 +02:00
# include "main/performance.h"
# include "main/splash.gen.h"
2014-02-10 02:10:30 +01:00
# include "modules/register_module_types.h"
2017-11-16 01:33:48 +01:00
# include "platform/register_platform_apis.h"
2017-06-27 03:58:03 +02:00
# include "scene/main/scene_tree.h"
2020-03-04 02:51:12 +01:00
# include "scene/main/window.h"
2018-09-11 18:13:45 +02:00
# include "scene/register_scene_types.h"
# include "scene/resources/packed_scene.h"
2022-08-08 18:29:36 +02:00
# include "scene/theme/theme_db.h"
2017-01-15 20:06:14 +01:00
# include "servers/audio_server.h"
2019-11-29 07:54:39 +01:00
# include "servers/camera_server.h"
2020-03-03 14:36:29 +01:00
# include "servers/display_server.h"
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
# include "servers/movie_writer/movie_writer.h"
# include "servers/movie_writer/movie_writer_mjpeg.h"
2020-03-27 19:21:27 +01:00
# include "servers/navigation_server_2d.h"
2023-08-17 18:32:30 +02:00
# include "servers/navigation_server_2d_dummy.h"
2020-03-27 19:21:27 +01:00
# include "servers/navigation_server_3d.h"
2022-11-21 08:35:20 +01:00
# include "servers/navigation_server_3d_dummy.h"
2020-03-27 19:21:27 +01:00
# include "servers/physics_server_2d.h"
# include "servers/physics_server_3d.h"
2018-09-11 18:13:45 +02:00
# include "servers/register_server_types.h"
2020-12-03 22:09:47 +01:00
# include "servers/rendering/rendering_server_default.h"
2022-02-13 13:41:29 +01:00
# include "servers/text/text_server_dummy.h"
2020-08-05 08:25:28 +02:00
# include "servers/text_server.h"
2020-04-08 16:47:36 +02:00
# include "servers/xr_server.h"
2014-02-10 02:10:30 +01:00
2020-07-25 15:59:30 +02:00
# ifdef TESTS_ENABLED
2020-07-25 23:06:07 +02:00
# include "tests/test_main.h"
2020-07-25 15:59:30 +02:00
# endif
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
2022-11-11 20:12:48 +01:00
# include "editor/debugger/editor_debugger_node.h"
2020-03-24 09:54:49 +01:00
# include "editor/doc_data_class_path.gen.h"
2020-11-29 04:42:06 +01:00
# include "editor/doc_tools.h"
2023-02-07 21:14:00 +01:00
# include "editor/editor_help.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_node.h"
2022-02-14 14:00:03 +01:00
# include "editor/editor_paths.h"
2018-09-15 14:45:54 +02:00
# include "editor/editor_settings.h"
2021-12-15 16:01:06 +01:00
# include "editor/editor_translation.h"
2019-12-24 08:17:23 +01:00
# include "editor/progress_dialog.h"
2017-03-05 14:21:25 +01:00
# include "editor/project_manager.h"
2022-05-01 11:57:36 +02:00
# include "editor/register_editor_types.h"
2023-02-10 09:07:01 +01:00
2021-11-30 12:36:56 +01:00
# ifndef NO_EDITOR_SPLASH
# include "main/splash_editor.gen.h"
# endif
2023-02-10 09:07:01 +01:00
# ifndef DISABLE_DEPRECATED
# include "editor/project_converter_3_to_4.h"
# endif // DISABLE_DEPRECATED
# endif // TOOLS_ENABLED
2014-02-10 02:10:30 +01:00
2021-11-12 13:42:58 +01:00
# include "modules/modules_enabled.gen.h" // For mono.
2023-03-07 19:10:54 +01:00
# if defined(MODULE_MONO_ENABLED) && defined(TOOLS_ENABLED)
# include "modules/mono/editor/bindings_generator.h"
# endif
2023-04-26 23:32:03 +02:00
# ifdef MODULE_GDSCRIPT_ENABLED
# include "modules/gdscript/gdscript.h"
2023-09-18 05:09:18 +02:00
# 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
2023-04-26 23:32:03 +02:00
2018-09-20 11:45:05 +02:00
/* Static members */
// Singletons
// Initialized in setup()
2020-04-02 01:20:12 +02:00
static Engine * engine = nullptr ;
static ProjectSettings * globals = nullptr ;
2020-04-28 15:19:37 +02:00
static Input * input = nullptr ;
2020-04-02 01:20:12 +02:00
static InputMap * input_map = nullptr ;
static TranslationServer * translation_server = nullptr ;
static Performance * performance = nullptr ;
static PackedData * packed_data = nullptr ;
2021-05-24 13:54:05 +02:00
static Time * time_singleton = nullptr ;
2015-04-21 00:38:02 +02:00
# ifdef MINIZIP_ENABLED
2020-04-02 01:20:12 +02:00
static ZipArchive * zip_packed_data = nullptr ;
2015-04-21 00:38:02 +02:00
# endif
2020-04-02 01:20:12 +02:00
static MessageQueue * message_queue = nullptr ;
2018-09-20 11:45:05 +02:00
// Initialized in setup2()
2020-04-02 01:20:12 +02:00
static AudioServer * audio_server = nullptr ;
static DisplayServer * display_server = nullptr ;
static RenderingServer * rendering_server = nullptr ;
static CameraServer * camera_server = nullptr ;
2020-04-08 16:47:36 +02:00
static XRServer * xr_server = nullptr ;
2020-08-05 08:25:28 +02:00
static TextServerManager * tsman = nullptr ;
2022-09-06 15:35:33 +02:00
static PhysicsServer3DManager * physics_server_3d_manager = nullptr ;
2022-04-27 05:52:53 +02:00
static PhysicsServer3D * physics_server_3d = nullptr ;
2022-09-06 15:35:33 +02:00
static PhysicsServer2DManager * physics_server_2d_manager = nullptr ;
2022-04-27 05:52:53 +02:00
static PhysicsServer2D * physics_server_2d = nullptr ;
static NavigationServer3D * navigation_server_3d = nullptr ;
static NavigationServer2D * navigation_server_2d = nullptr ;
2022-08-08 18:29:36 +02:00
static ThemeDB * theme_db = nullptr ;
2018-09-20 11:45:05 +02:00
// We error out if setup2() doesn't turn this true
static bool _start_success = false ;
// Drivers
Add Wayland support
Not everything is yet implemented, either for Godot or personal
limitations (I don't have all hardware in the world). A brief list of
the most important issues follows:
- Single-window only: the `DisplayServer` API doesn't expose enough
information for properly creating XDG shell windows.
- Very dumb rendering loop: this is very complicated, just know that
the low consumption mode is forced to 2000 Hz and some clever hacks are
in place to overcome a specific Wayland limitation. This will be
improved to the extent possible both downstream and upstream.
- Features to implement yet: IME, touch input, native file dialog,
drawing tablet (commented out due to a refactor), screen recording.
- Mouse passthrough can't be implement through a poly API, we need a
rect-based one.
- The cursor doesn't yet support fractional scaling.
- Auto scale is rounded up when using fractional scaling as we don't
have a per-window scale query API (basically we need
`DisplayServer::window_get_scale`).
- Building with `x11=no wayland=yes opengl=yes openxr=yes` fails.
This also adds a new project property and editor setting for selecting the
default DisplayServer to start, to allow this backend to start first in
exported projects (X11 is still the default for now). The editor setting
always overrides the project setting.
Special thanks to Drew Devault, toger5, Sebastian Krzyszkowiak, Leandro
Benedet Garcia, Subhransu, Yury Zhuravlev and Mara Huldra.
2023-12-15 02:55:34 +01:00
String display_driver = " " ;
2021-02-17 15:07:56 +01:00
String tablet_driver = " " ;
2020-09-03 13:22:16 +02:00
String text_driver = " " ;
2020-11-18 19:11:30 +01:00
String rendering_driver = " " ;
2022-09-08 02:44:36 +02:00
String rendering_method = " " ;
2020-08-05 08:25:28 +02:00
static int text_driver_idx = - 1 ;
2018-09-20 11:45:05 +02:00
static int audio_driver_idx = - 1 ;
// Engine config/tools
2022-08-13 21:52:03 +02:00
static bool single_window = false ;
2018-09-20 11:45:05 +02:00
static bool editor = false ;
static bool project_manager = false ;
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
static bool cmdline_tool = false ;
2018-09-20 11:45:05 +02:00
static String locale ;
2024-01-19 14:39:00 +01:00
static String log_file ;
2018-09-20 11:45:05 +02:00
static bool show_help = false ;
2023-02-20 08:44:33 +01:00
static uint64_t quit_after = 0 ;
2022-07-21 21:41:02 +02:00
static OS : : ProcessID editor_pid = 0 ;
2018-10-03 14:05:17 +02:00
# ifdef TOOLS_ENABLED
2022-09-24 18:49:53 +02:00
static bool found_project = false ;
2018-10-03 14:05:17 +02:00
static bool auto_build_solutions = false ;
2021-08-29 01:58:15 +02:00
static String debug_server_uri ;
2023-02-10 09:07:01 +01:00
# ifndef DISABLE_DEPRECATED
2022-08-13 22:17:35 +02:00
static int converter_max_kb_file = 4 * 1024 ; // 4MB
static int converter_max_line_length = 100000 ;
2023-02-10 09:07:01 +01:00
# endif // DISABLE_DEPRECATED
2022-08-13 21:52:03 +02:00
HashMap < Main : : CLIScope , Vector < String > > forwardable_cli_arguments ;
2018-10-03 14:05:17 +02:00
# endif
2023-04-10 18:45:53 +02:00
static bool single_threaded_scene = false ;
2018-09-20 11:45:05 +02:00
// Display
2014-02-10 02:10:30 +01:00
2020-03-03 14:36:29 +01:00
static DisplayServer : : WindowMode window_mode = DisplayServer : : WINDOW_MODE_WINDOWED ;
static DisplayServer : : ScreenOrientation window_orientation = DisplayServer : : SCREEN_LANDSCAPE ;
2021-06-19 17:44:59 +02:00
static DisplayServer : : VSyncMode window_vsync_mode = DisplayServer : : VSYNC_ENABLED ;
2020-03-03 14:36:29 +01:00
static uint32_t window_flags = 0 ;
2021-11-16 19:53:27 +01:00
static Size2i window_size = Size2i ( 1152 , 648 ) ;
2020-03-03 14:36:29 +01:00
2023-01-04 23:00:02 +01:00
static int init_screen = DisplayServer : : SCREEN_PRIMARY ;
2018-09-20 11:45:05 +02:00
static bool init_fullscreen = false ;
2017-03-05 16:44:50 +01:00
static bool init_maximized = false ;
static bool init_windowed = false ;
2017-12-27 20:51:19 +01:00
static bool init_always_on_top = false ;
2017-03-05 16:44:50 +01:00
static bool init_use_custom_pos = false ;
2023-01-19 09:28:53 +01:00
static bool init_use_custom_screen = false ;
2018-09-20 11:45:05 +02:00
static Vector2 init_custom_pos ;
// Debug
static bool use_debug_profiler = false ;
2017-04-07 16:17:16 +02:00
# ifdef DEBUG_ENABLED
2017-03-05 16:44:50 +01:00
static bool debug_collisions = false ;
2022-06-15 23:24:06 +02:00
static bool debug_paths = false ;
2017-03-05 16:44:50 +01:00
static bool debug_navigation = false ;
2023-01-10 07:14:16 +01:00
static bool debug_avoidance = false ;
2023-07-07 19:35:54 +02:00
static bool debug_canvas_item_redraw = false ;
2017-04-07 16:17:16 +02:00
# endif
2023-06-08 19:33:10 +02:00
static int max_fps = - 1 ;
2017-03-05 16:44:50 +01:00
static int frame_delay = 0 ;
2023-06-08 19:46:05 +02:00
static int audio_output_latency = 0 ;
2017-08-30 12:40:35 +02:00
static bool disable_render_loop = false ;
static int fixed_fps = - 1 ;
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
static MovieWriter * movie_writer = nullptr ;
static bool disable_vsync = false ;
2018-03-21 08:46:05 +01:00
static bool print_fps = false ;
2021-06-19 17:58:49 +02:00
# ifdef TOOLS_ENABLED
2022-12-07 12:11:28 +01:00
static bool dump_gdextension_interface = false ;
2021-06-19 17:58:49 +02:00
static bool dump_extension_api = false ;
2023-09-25 22:22:06 +02:00
static bool include_docs_in_extension_api_dump = false ;
Add a backwards-compatibility system for GDExtension method
This adds a way to ensure that methods that were modified in the Godot API will continue working in older builds of GDExtension even if the new signature is different.
```C++
// New version (changed)
ClassDB::bind_method(D_METHOD("add_sphere","radius","position"),&MyShapes::add_sphere);
// Compatibility version (still available to extensions).
ClassDB::bind_compatibility_method(D_METHOD("add_sphere","radius"),&MyShapes::_compat_add_sphere);
```
**Q**: If I add an extra argument and provide a default value (hence can still be called the same), do I still have to provide the compatibility version?
**A**: Yes, you must still provide a compatibility method. Most language bindings use the raw method pointer to do the call and process the default parameters in the binding language, hence if the actual method signature changes it will no longer work.
**Q**: If I removed a method, can I still bind a compatibility version even though the main method no longer exists?
**A**: Yes, for methods that were removed or renamed, compatibility versions can still be provided.
**Q**: Would it be possible to automate checking that methods were removed by mistake?
**A**: Yes, as part of a future PR, the idea is to add a a command line option to Godot that can be run like : `$ godot --test-api-compatibility older_api_dump.json`, which will also be integrated to the CI runs.
2023-04-25 20:53:07 +02:00
static bool validate_extension_api = false ;
static String validate_extension_api_file ;
2021-06-19 17:58:49 +02:00
# endif
2021-01-23 00:50:24 +01:00
bool profile_gpu = false ;
2022-12-20 22:49:11 +01:00
// Constants.
static const String NULL_DISPLAY_DRIVER ( " headless " ) ;
static const String NULL_AUDIO_DRIVER ( " Dummy " ) ;
2020-02-15 21:37:48 +01:00
// The length of the longest column in the command-line help we should align to
// (excluding the 2-space left and right margins).
// Currently, this is `--export-release <preset> <path>`.
static const int OPTION_COLUMN_LENGTH = 32 ;
2018-09-20 11:45:05 +02:00
/* Helper methods */
2018-02-16 16:00:54 +01:00
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
bool Main : : is_cmdline_tool ( ) {
return cmdline_tool ;
}
2022-08-13 21:52:03 +02:00
# ifdef TOOLS_ENABLED
const Vector < String > & Main : : get_forwardable_cli_arguments ( Main : : CLIScope p_scope ) {
return forwardable_cli_arguments [ p_scope ] ;
}
# endif
2018-09-20 11:45:05 +02:00
static String unescape_cmdline ( const String & p_str ) {
return p_str . replace ( " %20 " , " " ) ;
}
2017-10-21 13:02:06 +02:00
2018-09-20 11:45:05 +02:00
static String get_full_version_string ( ) {
String hash = String ( VERSION_HASH ) ;
2022-02-08 20:50:37 +01:00
if ( ! hash . is_empty ( ) ) {
2019-06-01 13:51:10 +02:00
hash = " . " + hash . left ( 9 ) ;
2020-05-14 16:41:43 +02:00
}
2018-09-20 11:45:05 +02:00
return String ( VERSION_FULL_BUILD ) + hash ;
}
2023-04-26 23:32:03 +02:00
# if defined(TOOLS_ENABLED) && defined(MODULE_GDSCRIPT_ENABLED)
static Vector < String > get_files_with_extension ( const String & p_root , const String & p_extension ) {
Vector < String > paths ;
Ref < DirAccess > 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
2022-09-06 15:35:33 +02:00
// FIXME: Could maybe be moved to have less code in main.cpp.
2018-09-20 11:45:05 +02:00
void initialize_physics ( ) {
2017-10-21 13:02:06 +02:00
/// 3D Physics Server
2022-09-06 15:35:33 +02:00
physics_server_3d = PhysicsServer3DManager : : get_singleton ( ) - > new_server (
2022-10-18 16:43:37 +02:00
GLOBAL_GET ( PhysicsServer3DManager : : setting_property_name ) ) ;
2022-04-27 05:52:53 +02:00
if ( ! physics_server_3d ) {
2017-10-21 13:02:06 +02:00
// Physics server not found, Use the default physics
2022-09-06 15:35:33 +02:00
physics_server_3d = PhysicsServer3DManager : : get_singleton ( ) - > new_default_server ( ) ;
2017-10-21 13:02:06 +02:00
}
2023-09-09 17:52:40 +02:00
ERR_FAIL_NULL ( physics_server_3d ) ;
2022-04-27 05:52:53 +02:00
physics_server_3d - > init ( ) ;
2017-10-21 13:02:06 +02:00
2022-09-06 15:35:33 +02:00
// 2D Physics server
physics_server_2d = PhysicsServer2DManager : : get_singleton ( ) - > new_server (
2022-10-18 16:43:37 +02:00
GLOBAL_GET ( PhysicsServer2DManager : : get_singleton ( ) - > setting_property_name ) ) ;
2022-04-27 05:52:53 +02:00
if ( ! physics_server_2d ) {
2017-10-21 13:02:06 +02:00
// Physics server not found, Use the default physics
2022-09-06 15:35:33 +02:00
physics_server_2d = PhysicsServer2DManager : : get_singleton ( ) - > new_default_server ( ) ;
2017-10-21 13:02:06 +02:00
}
2023-09-09 17:52:40 +02:00
ERR_FAIL_NULL ( physics_server_2d ) ;
2022-04-27 05:52:53 +02:00
physics_server_2d - > init ( ) ;
2017-10-21 13:02:06 +02:00
}
void finalize_physics ( ) {
2022-04-27 05:52:53 +02:00
physics_server_3d - > finish ( ) ;
memdelete ( physics_server_3d ) ;
2017-10-21 13:02:06 +02:00
2022-04-27 05:52:53 +02:00
physics_server_2d - > finish ( ) ;
memdelete ( physics_server_2d ) ;
2017-10-21 13:02:06 +02:00
}
2020-03-03 14:36:29 +01:00
void finalize_display ( ) {
2020-03-27 19:21:27 +01:00
rendering_server - > finish ( ) ;
memdelete ( rendering_server ) ;
2020-03-03 14:36:29 +01:00
memdelete ( display_server ) ;
}
2020-01-10 12:22:34 +01:00
void initialize_navigation_server ( ) {
2022-04-27 05:52:53 +02:00
ERR_FAIL_COND ( navigation_server_3d ! = nullptr ) ;
2023-07-07 15:59:10 +02:00
ERR_FAIL_COND ( navigation_server_2d ! = nullptr ) ;
2020-02-26 09:42:51 +01:00
2022-11-21 08:35:20 +01:00
// Init 3D Navigation Server
2022-04-27 05:52:53 +02:00
navigation_server_3d = NavigationServer3DManager : : new_default_server ( ) ;
2022-11-21 08:35:20 +01:00
// 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. " ) ;
2023-07-07 15:59:10 +02:00
navigation_server_3d - > init ( ) ;
2022-11-21 08:35:20 +01:00
// Init 2D Navigation Server
2023-08-17 18:32:30 +02:00
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 ) ;
}
2022-11-21 08:35:20 +01:00
ERR_FAIL_NULL_MSG ( navigation_server_2d , " Failed to initialize NavigationServer2D. " ) ;
2023-08-17 18:32:30 +02:00
navigation_server_2d - > init ( ) ;
2020-01-10 12:22:34 +01:00
}
void finalize_navigation_server ( ) {
2023-07-07 15:59:10 +02:00
ERR_FAIL_NULL ( navigation_server_3d ) ;
navigation_server_3d - > finish ( ) ;
2022-04-27 05:52:53 +02:00
memdelete ( navigation_server_3d ) ;
navigation_server_3d = nullptr ;
2020-02-26 09:42:51 +01:00
2023-07-07 15:59:10 +02:00
ERR_FAIL_NULL ( navigation_server_2d ) ;
2023-08-17 18:32:30 +02:00
navigation_server_2d - > finish ( ) ;
2022-04-27 05:52:53 +02:00
memdelete ( navigation_server_2d ) ;
navigation_server_2d = nullptr ;
2020-01-10 12:22:34 +01:00
}
2022-08-08 18:29:36 +02:00
void initialize_theme_db ( ) {
theme_db = memnew ( ThemeDB ) ;
}
void finalize_theme_db ( ) {
memdelete ( theme_db ) ;
theme_db = nullptr ;
}
2014-02-10 02:10:30 +01:00
//#define DEBUG_INIT
# ifdef DEBUG_INIT
# define MAIN_PRINT(m_txt) print_line(m_txt)
# else
# define MAIN_PRINT(m_txt)
# endif
2020-02-15 21:37:48 +01:00
/**
* Prints a copyright notice in the command - line help with colored text . A newline is
* automatically added at the end .
*/
void Main : : print_help_copyright ( const char * p_notice ) {
OS : : get_singleton ( ) - > print ( " \u001b [90m%s \u001b [0m \n " , p_notice ) ;
}
/**
* Prints a title in the command - line help with colored text . A newline is
* automatically added at beginning and at the end .
*/
void Main : : print_help_title ( const char * p_title ) {
OS : : get_singleton ( ) - > print ( " \n \u001b [1;93m%s: \u001b [0m \n " , p_title ) ;
}
/**
* Returns the option string with required and optional arguments colored separately from the rest of the option .
* This color replacement must be done * after * calling ` rpad ( ) ` for the length padding to be done correctly .
*/
String Main : : format_help_option ( const char * p_option ) {
return ( String ( p_option )
. rpad ( OPTION_COLUMN_LENGTH )
. replace ( " [ " , " \u001b [96m[ " )
. replace ( " ] " , " ] \u001b [0m " )
. replace ( " < " , " \u001b [95m< " )
. replace ( " > " , " > \u001b [0m " ) ) ;
}
/**
* Prints an option in the command - line help with colored text . No newline is
* added at the end . ` p_availability ` denotes which build types the argument is
* available in . Support in release export templates implies support in debug
* export templates and editor . Support in debug export templates implies
* support in editor .
*/
void Main : : print_help_option ( const char * p_option , const char * p_description , CLIOptionAvailability p_availability ) {
const bool option_empty = ( p_option & & ! p_option [ 0 ] ) ;
if ( ! option_empty ) {
const char * availability_badge = " " ;
switch ( p_availability ) {
case CLI_OPTION_AVAILABILITY_EDITOR :
availability_badge = " \u001b [1;91mE " ;
break ;
case CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG :
availability_badge = " \u001b [1;94mD " ;
break ;
case CLI_OPTION_AVAILABILITY_TEMPLATE_RELEASE :
availability_badge = " \u001b [1;92mR " ;
break ;
case CLI_OPTION_AVAILABILITY_HIDDEN :
// Use for multiline option names (but not when the option name is empty).
availability_badge = " " ;
break ;
}
OS : : get_singleton ( ) - > print (
" \u001b [92m%s %s \u001b [0m %s " ,
format_help_option ( p_option ) . utf8 ( ) . ptr ( ) ,
availability_badge ,
p_description ) ;
} else {
// Make continuation lines for descriptions faint if the option name is empty.
OS : : get_singleton ( ) - > print (
" \u001b [92m%s \u001b [0m \u001b [90m%s " ,
format_help_option ( p_option ) . utf8 ( ) . ptr ( ) ,
p_description ) ;
}
}
2017-03-05 16:44:50 +01:00
void Main : : print_help ( const char * p_binary ) {
2020-02-15 21:37:48 +01:00
print_line ( " \u001b [38;5;39m " + String ( VERSION_NAME ) + " \u001b [0m v " + get_full_version_string ( ) + " - \u001b [4m " + String ( VERSION_WEBSITE ) + " \u001b [0m " ) ;
print_help_copyright ( " Free and open source software under the terms of the MIT license. " ) ;
print_help_copyright ( " (c) 2014-present Godot Engine contributors. (c) 2007-present Juan Linietsky, Ariel Manzur. " ) ;
2017-08-19 16:45:03 +02:00
2020-02-15 21:37:48 +01:00
print_help_title ( " Usage " ) ;
OS : : get_singleton ( ) - > print ( " %s \u001b [96m[options] [path to scene or \" project.godot \" file] \u001b [0m \n " , p_binary ) ;
# if defined(TOOLS_ENABLED)
print_help_title ( " Option legend (this build = editor) " ) ;
# elif defined(DEBUG_ENABLED)
print_help_title ( " Option legend (this build = debug export template) " ) ;
# else
print_help_title ( " Option legend (this build = release export template) " ) ;
# endif
2017-08-19 16:45:03 +02:00
2020-02-15 21:37:48 +01:00
OS : : get_singleton ( ) - > print ( " \u001b [1;92mR \u001b [0m Available in editor builds, debug export templates and release export templates. \n " ) ;
# ifdef DEBUG_ENABLED
OS : : get_singleton ( ) - > print ( " \u001b [1;94mD \u001b [0m Available in editor builds and debug export templates only. \n " ) ;
# endif
# ifdef TOOLS_ENABLED
OS : : get_singleton ( ) - > print ( " \u001b [1;91mE \u001b [0m Only available in editor builds. \n " ) ;
# endif
print_help_title ( " General options " ) ;
print_help_option ( " -h, --help " , " Display this help message. \n " ) ;
print_help_option ( " --version " , " Display the version string. \n " ) ;
print_help_option ( " -v, --verbose " , " Use verbose stdout mode. \n " ) ;
print_help_option ( " --quiet " , " Quiet mode, silences stdout messages. Errors are still displayed. \n " ) ;
print_help_title ( " Run options " ) ;
print_help_option ( " --, ++ " , " Separator for user-provided arguments. Following arguments are not used by the engine, but can be read from `OS.get_cmdline_user_args()`. \n " ) ;
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
2020-02-15 21:37:48 +01:00
print_help_option ( " -e, --editor " , " Start the editor instead of running the scene. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " -p, --project-manager " , " Start the project manager, even if a project is auto-detected. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " --debug-server <uri> " , " Start the editor debug server (<protocol>://<host/IP>[:port], e.g. tcp://127.0.0.1:6007) \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
2023-09-18 05:09:18 +02:00
# if defined(MODULE_GDSCRIPT_ENABLED) && !defined(GDSCRIPT_NO_LSP)
2020-02-15 21:37:48 +01:00
print_help_option ( " --lsp-port <port> " , " Use the specified port for the GDScript language server protocol. The port should be between 1025 and 49150. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
2023-09-18 05:09:18 +02:00
# endif // MODULE_GDSCRIPT_ENABLED && !GDSCRIPT_NO_LSP
2020-02-15 21:37:48 +01:00
# endif
print_help_option ( " --quit " , " Quit after the first iteration. \n " ) ;
print_help_option ( " --quit-after <int> " , " Quit after the given number of iterations. Set to 0 to disable. \n " ) ;
print_help_option ( " -l, --language <locale> " , " Use a specific locale (<locale> being a two-letter code). \n " ) ;
print_help_option ( " --path <directory> " , " Path to a project (<directory> must contain a \" project.godot \" file). \n " ) ;
print_help_option ( " -u, --upwards " , " Scan folders upwards for project.godot file. \n " ) ;
print_help_option ( " --main-pack <file> " , " Path to a pack (.pck) file to load. \n " ) ;
print_help_option ( " --render-thread <mode> " , " Render thread mode ( \" unsafe \" , \" safe \" , \" separate \" ). \n " ) ;
print_help_option ( " --remote-fs <address> " , " Remote filesystem (<host/IP>[:<port>] address). \n " ) ;
print_help_option ( " --remote-fs-password <password> " , " Password for remote filesystem. \n " ) ;
print_help_option ( " --audio-driver <driver> " , " Audio driver [ " ) ;
2020-03-03 14:36:29 +01:00
for ( int i = 0 ; i < AudioDriverManager : : get_driver_count ( ) ; i + + ) {
2020-03-27 10:48:30 +01:00
if ( i > 0 ) {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " , " ) ;
2020-03-27 10:48:30 +01:00
}
2020-02-15 21:37:48 +01:00
OS : : get_singleton ( ) - > print ( " \" %s \" " , AudioDriverManager : : get_driver ( i ) - > get_name ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2020-03-27 10:48:30 +01:00
OS : : get_singleton ( ) - > print ( " ]. \n " ) ;
2020-02-15 21:37:48 +01:00
print_help_option ( " --display-driver <driver> " , " Display driver (and rendering driver) [ " ) ;
2020-03-03 14:36:29 +01:00
for ( int i = 0 ; i < DisplayServer : : get_create_function_count ( ) ; i + + ) {
2020-03-27 10:48:30 +01:00
if ( i > 0 ) {
OS : : get_singleton ( ) - > print ( " , " ) ;
}
2020-02-15 21:37:48 +01:00
OS : : get_singleton ( ) - > print ( " \" %s \" ( " , DisplayServer : : get_create_function_name ( i ) ) ;
2020-03-03 14:36:29 +01:00
Vector < String > rd = DisplayServer : : get_create_function_rendering_drivers ( i ) ;
for ( int j = 0 ; j < rd . size ( ) ; j + + ) {
if ( j > 0 ) {
OS : : get_singleton ( ) - > print ( " , " ) ;
}
2020-02-15 21:37:48 +01:00
OS : : get_singleton ( ) - > print ( " \" %s \" " , rd [ j ] . utf8 ( ) . get_data ( ) ) ;
2020-03-03 14:36:29 +01:00
}
2020-03-27 10:48:30 +01:00
OS : : get_singleton ( ) - > print ( " ) " ) ;
2014-02-10 02:10:30 +01:00
}
2020-03-27 10:48:30 +01:00
OS : : get_singleton ( ) - > print ( " ]. \n " ) ;
2020-02-15 21:37:48 +01:00
print_help_option ( " --audio-output-latency <ms> " , " Override audio output latency in milliseconds (default is 15 ms). \n " ) ;
print_help_option ( " " , " 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 " ) ;
print_help_option ( " --rendering-method <renderer> " , " Renderer name. Requires driver support. \n " ) ;
print_help_option ( " --rendering-driver <driver> " , " Rendering driver (depends on display driver). \n " ) ;
print_help_option ( " --gpu-index <device_index> " , " Use a specific GPU (run with --verbose to get a list of available devices). \n " ) ;
print_help_option ( " --text-driver <driver> " , " Text driver (used for font rendering, bidirectional support and shaping). \n " ) ;
print_help_option ( " --tablet-driver <driver> " , " Pen tablet input driver. \n " ) ;
print_help_option ( " --headless " , " Enable headless mode (--display-driver headless --audio-driver Dummy). Useful for servers and with --script. \n " ) ;
print_help_option ( " --log-file <file> " , " Write output/error log to the specified path instead of the default location defined by the project. \n " ) ;
print_help_option ( " " , " <file> path should be absolute or relative to the project directory. \n " ) ;
print_help_option ( " --write-movie <file> " , " Write a video to the specified path (usually with .avi or .png extension). \n " ) ;
print_help_option ( " " , " --fixed-fps is forced when enabled, but it can be used to change movie FPS. \n " ) ;
print_help_option ( " " , " --disable-vsync can speed up movie writing but makes interaction more difficult. \n " ) ;
print_help_option ( " " , " --quit-after can be used to specify the number of frames to write. \n " ) ;
print_help_title ( " Display options " ) ;
print_help_option ( " -f, --fullscreen " , " Request fullscreen mode. \n " ) ;
print_help_option ( " -m, --maximized " , " Request a maximized window. \n " ) ;
print_help_option ( " -w, --windowed " , " Request windowed mode. \n " ) ;
print_help_option ( " -t, --always-on-top " , " Request an always-on-top window. \n " ) ;
print_help_option ( " --resolution <W>x<H> " , " Request window resolution. \n " ) ;
print_help_option ( " --position <X>,<Y> " , " Request window position. \n " ) ;
print_help_option ( " --screen <N> " , " Request window screen. \n " ) ;
print_help_option ( " --single-window " , " Use a single window (no separate subwindows). \n " ) ;
print_help_option ( " --xr-mode <mode> " , " Select XR (Extended Reality) mode [ \" default \" , \" off \" , \" on \" ]. \n " ) ;
print_help_title ( " Debug options " ) ;
print_help_option ( " -d, --debug " , " Debug (local stdout debugger). \n " ) ;
print_help_option ( " -b, --breakpoints " , " Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead). \n " ) ;
print_help_option ( " --profiling " , " Enable profiling in the script debugger. \n " ) ;
print_help_option ( " --gpu-profile " , " Show a GPU profile of the tasks that took the most time during frame rendering. \n " ) ;
print_help_option ( " --gpu-validation " , " Enable graphics API validation layers for debugging. \n " ) ;
2024-01-17 10:12:44 +01:00
# ifdef DEBUG_ENABLED
2020-02-15 21:37:48 +01:00
print_help_option ( " --gpu-abort " , " Abort on graphics API usage errors (usually validation layer errors). May help see the problem if your system freezes. \n " , CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG ) ;
2020-10-27 16:00:15 +01:00
# endif
2020-02-15 21:37:48 +01:00
print_help_option ( " --generate-spirv-debug-info " , " Generate SPIR-V debug information. This allows source-level shader debugging with RenderDoc. \n " ) ;
print_help_option ( " --remote-debug <uri> " , " Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007). \n " ) ;
print_help_option ( " --single-threaded-scene " , " Force scene tree to run in single-threaded mode. Sub-thread groups are disabled and run on the main thread. \n " ) ;
2021-08-03 16:59:18 +02:00
# if defined(DEBUG_ENABLED)
2020-02-15 21:37:48 +01:00
print_help_option ( " --debug-collisions " , " Show collision shapes when running the scene. \n " , CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG ) ;
print_help_option ( " --debug-paths " , " Show path lines when running the scene. \n " , CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG ) ;
print_help_option ( " --debug-navigation " , " Show navigation polygons when running the scene. \n " , CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG ) ;
print_help_option ( " --debug-avoidance " , " Show navigation avoidance debug visuals when running the scene. \n " , CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG ) ;
print_help_option ( " --debug-stringnames " , " Print all StringName allocations to stdout when the engine quits. \n " , CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG ) ;
print_help_option ( " --debug-canvas-item-redraw " , " Display a rectangle each time a canvas item requests a redraw (useful to troubleshoot low processor mode). \n " , CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG ) ;
2017-08-19 16:45:03 +02:00
2020-02-15 21:37:48 +01:00
# endif
print_help_option ( " --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 " ) ;
print_help_option ( " --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 " ) ;
print_help_option ( " --time-scale <scale> " , " Force time scale (higher values are faster, 1.0 is normal speed). \n " ) ;
print_help_option ( " --disable-vsync " , " Forces disabling of vertical synchronization, even if enabled in the project settings. Does not override driver-level V-Sync enforcement. \n " ) ;
print_help_option ( " --disable-render-loop " , " Disable render loop so rendering only occurs when called explicitly from script. \n " ) ;
print_help_option ( " --disable-crash-handler " , " Disable crash handler when supported by the platform code. \n " ) ;
print_help_option ( " --fixed-fps <fps> " , " Force a fixed number of frames per second. This setting disables real-time synchronization. \n " ) ;
print_help_option ( " --delta-smoothing <enable> " , " Enable or disable frame delta smoothing [ \" enable \" , \" disable \" ]. \n " ) ;
print_help_option ( " --print-fps " , " Print the frames per second to the stdout. \n " ) ;
print_help_title ( " Standalone tools " ) ;
print_help_option ( " -s, --script <script> " , " Run a script. \n " ) ;
print_help_option ( " --main-loop <main_loop_name> " , " Run a MainLoop specified by its global class name. \n " ) ;
print_help_option ( " --check-only " , " Only parse for errors and quit (use with --script). \n " ) ;
2017-08-19 22:47:27 +02:00
# ifdef TOOLS_ENABLED
2020-02-15 21:37:48 +01:00
print_help_option ( " --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 " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " " , " <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. \" builds/game.exe \" ). \n " ) ;
print_help_option ( " " , " The target directory must exist. \n " ) ;
print_help_option ( " --export-debug <preset> <path> " , " Export the project in debug mode using the given preset and output path. See --export-release description for other considerations. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " --export-pack <preset> <path> " , " Export the project data only using the given preset and output path. The <path> extension determines whether it will be in PCK or ZIP format. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " --install-android-build-template " , " Install the Android build template. Used in conjunction with --export-release or --export-debug. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
2023-02-10 09:07:01 +01:00
# ifndef DISABLE_DEPRECATED
2020-02-15 21:37:48 +01:00
// Commands are long; split the description to a second line.
print_help_option ( " --convert-3to4 " , " \n " , CLI_OPTION_AVAILABILITY_HIDDEN ) ;
print_help_option ( " [max_file_kb] [max_line_size] " , " Converts project from Godot 3.x to Godot 4.x. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " --validate-conversion-3to4 " , " \n " , CLI_OPTION_AVAILABILITY_HIDDEN ) ;
print_help_option ( " [max_file_kb] [max_line_size] " , " Shows what elements will be renamed when converting project from Godot 3.x to Godot 4.x. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
2023-02-10 09:07:01 +01:00
# endif // DISABLE_DEPRECATED
2020-02-15 21:37:48 +01:00
print_help_option ( " --doctool [path] " , " Dump the engine API reference to the given <path> (defaults to current directory) in XML format, merging if existing files are found. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " --no-docbase " , " Disallow dumping the base types (used with --doctool). \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
2023-04-26 23:32:03 +02:00
# ifdef MODULE_GDSCRIPT_ENABLED
2020-02-15 21:37:48 +01:00
print_help_option ( " --gdscript-docs <path> " , " Rather than dumping the engine API, generate API reference from the inline documentation in the GDScript files found in <path> (used with --doctool). \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
2023-04-26 23:32:03 +02:00
# endif
2020-02-15 21:37:48 +01:00
print_help_option ( " --build-solutions " , " Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " --dump-gdextension-interface " , " Generate a GDExtension header file \" gdextension_interface.h \" in the current folder. This file is the base file required to implement a GDExtension. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " --dump-extension-api " , " Generate a JSON dump of the Godot API for GDExtension bindings named \" extension_api.json \" in the current folder. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " --dump-extension-api-with-docs " , " Generate JSON dump of the Godot API like the previous option, but including documentation. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " --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. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " " , " If incompatibilities or errors are detected, the exit code will be non-zero. \n " ) ;
print_help_option ( " --benchmark " , " Benchmark the run time and print it to console. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
print_help_option ( " --benchmark-file <path> " , " Benchmark the run time and save it to a given file in JSON format. The path should be absolute. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
2020-07-25 15:59:30 +02:00
# ifdef TESTS_ENABLED
2020-02-15 21:37:48 +01:00
print_help_option ( " --test [--help] " , " Run unit tests. Use --test --help for more information. \n " , CLI_OPTION_AVAILABILITY_EDITOR ) ;
2020-07-25 15:59:30 +02:00
# endif
2014-02-10 02:10:30 +01:00
# endif
2020-08-04 09:22:30 +02:00
OS : : get_singleton ( ) - > print ( " \n " ) ;
2014-02-10 02:10:30 +01:00
}
2020-08-02 20:30:56 +02:00
# ifdef TESTS_ENABLED
// The order is the same as in `Main::setup()`, only core and some editor types
// are initialized here. This also combines `Main::setup2()` initialization.
Error Main : : test_setup ( ) {
2023-04-22 15:34:16 +02:00
Thread : : make_main_thread ( ) ;
2023-05-23 23:28:47 +02:00
set_current_thread_safe_for_nodes ( true ) ;
2023-04-22 15:34:16 +02:00
2020-08-02 20:30:56 +02:00
OS : : get_singleton ( ) - > initialize ( ) ;
engine = memnew ( Engine ) ;
register_core_types ( ) ;
register_core_driver_types ( ) ;
2021-04-07 19:23:18 +02:00
packed_data = memnew ( PackedData ) ;
2020-08-02 20:30:56 +02:00
globals = memnew ( ProjectSettings ) ;
2022-10-20 15:43:17 +02:00
register_core_settings ( ) ; // Here globals are present.
2022-07-18 12:09:19 +02:00
2021-02-22 14:16:46 +01:00
translation_server = memnew ( TranslationServer ) ;
2021-08-27 23:19:51 +02:00
tsman = memnew ( TextServerManager ) ;
2021-02-22 14:16:46 +01:00
2022-02-13 13:41:29 +01:00
if ( tsman ) {
Ref < TextServerDummy > ts ;
ts . instantiate ( ) ;
tsman - > add_interface ( ts ) ;
}
2022-09-06 15:35:33 +02:00
physics_server_3d_manager = memnew ( PhysicsServer3DManager ) ;
physics_server_2d_manager = memnew ( PhysicsServer2DManager ) ;
2022-05-03 11:56:08 +02:00
// From `Main::setup2()`.
initialize_modules ( MODULE_INITIALIZATION_LEVEL_CORE ) ;
2021-06-19 17:58:49 +02:00
register_core_extensions ( ) ;
2020-08-02 20:30:56 +02:00
register_core_singletons ( ) ;
2022-05-03 11:56:08 +02:00
/** INITIALIZE SERVERS **/
2020-08-02 20:30:56 +02:00
register_server_types ( ) ;
2022-08-04 15:55:45 +02:00
XRServer : : set_xr_mode ( XRServer : : XRMODE_OFF ) ; // Skip in tests.
2022-05-03 11:56:08 +02:00
initialize_modules ( MODULE_INITIALIZATION_LEVEL_SERVERS ) ;
2022-12-07 12:11:28 +01:00
GDExtensionManager : : get_singleton ( ) - > initialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_SERVERS ) ;
2021-02-22 14:16:46 +01:00
translation_server - > setup ( ) ; //register translations, load them, etc.
2021-12-09 10:42:46 +01:00
if ( ! locale . is_empty ( ) ) {
2021-02-22 14:16:46 +01:00
translation_server - > set_locale ( locale ) ;
}
translation_server - > load_translations ( ) ;
ResourceLoader : : load_translation_remaps ( ) ; //load remaps for resources
ResourceLoader : : load_path_remaps ( ) ;
2023-09-04 18:07:16 +02:00
// 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 ( ) ;
2020-08-02 20:30:56 +02:00
register_scene_types ( ) ;
2022-02-28 14:50:43 +01:00
register_driver_types ( ) ;
2020-08-02 20:30:56 +02:00
2023-09-04 18:07:16 +02:00
register_scene_singletons ( ) ;
2022-05-03 11:56:08 +02:00
initialize_modules ( MODULE_INITIALIZATION_LEVEL_SCENE ) ;
2022-12-07 12:11:28 +01:00
GDExtensionManager : : get_singleton ( ) - > initialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_SCENE ) ;
2022-05-03 11:56:08 +02:00
2020-08-02 20:30:56 +02:00
# ifdef TOOLS_ENABLED
ClassDB : : set_current_api ( ClassDB : : API_EDITOR ) ;
2022-05-01 11:57:36 +02:00
register_editor_types ( ) ;
2020-08-02 20:30:56 +02:00
2022-05-03 11:56:08 +02:00
initialize_modules ( MODULE_INITIALIZATION_LEVEL_EDITOR ) ;
2022-12-07 12:11:28 +01:00
GDExtensionManager : : get_singleton ( ) - > initialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_EDITOR ) ;
2022-05-03 11:56:08 +02:00
2020-08-02 20:30:56 +02:00
ClassDB : : set_current_api ( ClassDB : : API_CORE ) ;
# endif
register_platform_apis ( ) ;
2021-11-30 17:09:29 +01:00
// Theme needs modules to be initialized so that sub-resources can be loaded.
2023-09-04 18:07:16 +02:00
theme_db - > initialize_theme_noproject ( ) ;
2021-11-30 17:09:29 +01:00
2023-07-07 15:59:10 +02:00
initialize_navigation_server ( ) ;
2021-08-27 23:19:51 +02:00
ERR_FAIL_COND_V ( TextServerManager : : get_singleton ( ) - > get_interface_count ( ) = = 0 , ERR_CANT_CREATE ) ;
2022-02-13 13:41:29 +01:00
/* Use one with the most features available. */
int max_features = 0 ;
for ( int i = 0 ; i < TextServerManager : : get_singleton ( ) - > get_interface_count ( ) ; i + + ) {
uint32_t features = TextServerManager : : get_singleton ( ) - > get_interface ( i ) - > get_features ( ) ;
int feature_number = 0 ;
while ( features ) {
feature_number + = features & 1 ;
features > > = 1 ;
}
if ( feature_number > = max_features ) {
max_features = feature_number ;
text_driver_idx = i ;
}
}
if ( text_driver_idx > = 0 ) {
2023-01-23 20:10:42 +01:00
Ref < TextServer > ts = TextServerManager : : get_singleton ( ) - > get_interface ( text_driver_idx ) ;
TextServerManager : : get_singleton ( ) - > set_primary_interface ( ts ) ;
if ( ts - > has_feature ( TextServer : : FEATURE_USE_SUPPORT_DATA ) ) {
ts - > load_support_data ( " res:// " + ts - > get_support_data_filename ( ) ) ;
}
2022-02-13 13:41:29 +01:00
} else {
ERR_FAIL_V_MSG ( ERR_CANT_CREATE , " TextServer: Unable to create TextServer interface. " ) ;
}
2021-08-27 23:19:51 +02:00
2020-08-02 20:30:56 +02:00
ClassDB : : set_current_api ( ClassDB : : API_NONE ) ;
_start_success = true ;
return OK ;
}
// The order is the same as in `Main::cleanup()`.
void Main : : test_cleanup ( ) {
ERR_FAIL_COND ( ! _start_success ) ;
2022-11-21 14:04:01 +01:00
for ( int i = 0 ; i < TextServerManager : : get_singleton ( ) - > get_interface_count ( ) ; i + + ) {
TextServerManager : : get_singleton ( ) - > get_interface ( i ) - > cleanup ( ) ;
}
2020-08-02 20:30:56 +02:00
ResourceLoader : : remove_custom_loaders ( ) ;
ResourceSaver : : remove_custom_savers ( ) ;
# ifdef TOOLS_ENABLED
2022-12-07 12:11:28 +01:00
GDExtensionManager : : get_singleton ( ) - > deinitialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_EDITOR ) ;
2022-05-03 11:56:08 +02:00
uninitialize_modules ( MODULE_INITIALIZATION_LEVEL_EDITOR ) ;
2022-05-01 11:57:36 +02:00
unregister_editor_types ( ) ;
2020-08-02 20:30:56 +02:00
# endif
2021-08-27 23:19:51 +02:00
2022-12-07 12:11:28 +01:00
GDExtensionManager : : get_singleton ( ) - > deinitialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_SCENE ) ;
2022-05-03 11:56:08 +02:00
uninitialize_modules ( MODULE_INITIALIZATION_LEVEL_SCENE ) ;
2023-05-09 15:50:48 +02:00
2020-08-02 20:30:56 +02:00
unregister_platform_apis ( ) ;
2022-02-28 14:50:43 +01:00
unregister_driver_types ( ) ;
2020-08-02 20:30:56 +02:00
unregister_scene_types ( ) ;
2022-05-03 11:56:08 +02:00
2022-08-08 18:29:36 +02:00
finalize_theme_db ( ) ;
2023-07-07 15:59:10 +02:00
finalize_navigation_server ( ) ;
2022-12-07 12:11:28 +01:00
GDExtensionManager : : get_singleton ( ) - > deinitialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_SERVERS ) ;
2022-05-03 11:56:08 +02:00
uninitialize_modules ( MODULE_INITIALIZATION_LEVEL_SERVERS ) ;
2020-08-02 20:30:56 +02:00
unregister_server_types ( ) ;
2023-05-09 15:50:48 +02:00
EngineDebugger : : deinitialize ( ) ;
2020-08-02 20:30:56 +02:00
OS : : get_singleton ( ) - > finalize ( ) ;
2023-05-09 15:50:48 +02:00
if ( packed_data ) {
memdelete ( packed_data ) ;
}
2021-02-22 14:16:46 +01:00
if ( translation_server ) {
memdelete ( translation_server ) ;
}
2021-08-27 23:19:51 +02:00
if ( tsman ) {
memdelete ( tsman ) ;
}
2022-09-06 15:35:33 +02:00
if ( physics_server_3d_manager ) {
memdelete ( physics_server_3d_manager ) ;
}
if ( physics_server_2d_manager ) {
memdelete ( physics_server_2d_manager ) ;
}
2020-08-02 20:30:56 +02:00
if ( globals ) {
memdelete ( globals ) ;
}
if ( engine ) {
memdelete ( engine ) ;
}
unregister_core_driver_types ( ) ;
2022-02-16 18:02:38 +01:00
unregister_core_extensions ( ) ;
2023-05-09 15:50:48 +02:00
uninitialize_modules ( MODULE_INITIALIZATION_LEVEL_CORE ) ;
2020-08-02 20:30:56 +02:00
unregister_core_types ( ) ;
OS : : get_singleton ( ) - > finalize_core ( ) ;
}
# endif
2020-07-20 18:35:34 +02:00
int Main : : test_entrypoint ( int argc , char * argv [ ] , bool & tests_need_run ) {
2020-07-25 15:59:30 +02:00
# ifdef TESTS_ENABLED
2020-07-20 18:35:34 +02:00
for ( int x = 0 ; x < argc ; x + + ) {
2020-08-08 20:53:51 +02:00
if ( ( strncmp ( argv [ x ] , " --test " , 6 ) = = 0 ) & & ( strlen ( argv [ x ] ) = = 6 ) ) {
2020-07-20 18:35:34 +02:00
tests_need_run = true ;
2020-08-02 20:30:56 +02:00
// TODO: need to come up with different test contexts.
// Not every test requires high-level functionality like `ClassDB`.
test_setup ( ) ;
2020-07-24 15:38:57 +02:00
int status = test_main ( argc , argv ) ;
2020-08-02 20:30:56 +02:00
test_cleanup ( ) ;
2020-07-24 15:38:57 +02:00
return status ;
2020-07-20 18:35:34 +02:00
}
}
# endif
tests_need_run = false ;
return 0 ;
}
2018-09-20 11:45:05 +02:00
/* Engine initialization
*
* Consists of several methods that are called by each platform ' s specific main ( argc , argv ) .
* To fully understand engine init , one should therefore start from the platform ' s main and
* see how it calls into the Main class ' methods .
*
* The initialization is typically done in 3 steps ( with the setup2 step triggered either
* automatically by setup , or manually in the platform ' s main ) .
*
* - setup ( execpath , argc , argv , p_second_phase ) is the main entry point for all platforms ,
* responsible for the initialization of all low level singletons and core types , and parsing
* command line arguments to configure things accordingly .
2022-11-01 15:29:38 +01:00
* If p_second_phase is true , it will chain into setup2 ( ) ( default behavior ) . This is
2023-09-07 15:01:59 +02:00
* disabled on some platforms ( Android , iOS ) which trigger the second step in their own time .
2018-09-20 11:45:05 +02:00
*
* - setup2 ( p_main_tid_override ) registers high level servers and singletons , displays the
* boot splash , then registers higher level types ( scene , editor , etc . ) .
*
* - start ( ) is the last step and that ' s where command line tools can run , or the main loop
* can be created eventually and the project settings put into action . That ' s also where
* the editor node is created , if relevant .
* start ( ) does it own argument parsing for a subset of the command line arguments described
* in help , it ' s a bit messy and should be globalized with the setup ( ) parsing somehow .
*/
2017-03-05 16:44:50 +01:00
Error Main : : setup ( const char * execpath , int argc , char * argv [ ] , bool p_second_phase ) {
2023-04-22 15:34:16 +02:00
Thread : : make_main_thread ( ) ;
2023-05-23 23:28:47 +02:00
set_current_thread_safe_for_nodes ( true ) ;
2023-04-22 15:34:16 +02:00
2020-03-03 14:36:29 +01:00
OS : : get_singleton ( ) - > initialize ( ) ;
2017-01-13 16:51:14 +01:00
2023-01-13 20:24:12 +01:00
// Benchmark tracking must be done after `OS::get_singleton()->initialize()` as on some
// platforms, it's used to set up the time utilities.
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Total " ) ;
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Setup " ) ;
2023-01-13 20:24:12 +01:00
2017-03-05 16:44:50 +01:00
engine = memnew ( Engine ) ;
2017-01-13 16:51:14 +01:00
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: Initialize CORE " ) ;
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Core " ) ;
2014-02-10 02:10:30 +01:00
register_core_types ( ) ;
register_core_driver_types ( ) ;
MAIN_PRINT ( " Main: Initialize Globals " ) ;
2017-03-05 16:44:50 +01:00
input_map = memnew ( InputMap ) ;
2021-05-24 13:54:05 +02:00
time_singleton = memnew ( Time ) ;
2020-12-07 12:31:51 +01:00
globals = memnew ( ProjectSettings ) ;
2014-02-10 02:10:30 +01:00
2021-03-12 14:35:16 +01:00
register_core_settings ( ) ; //here globals are present
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
translation_server = memnew ( TranslationServer ) ;
performance = memnew ( Performance ) ;
2021-07-12 00:30:33 +02:00
GDREGISTER_CLASS ( Performance ) ;
2017-11-13 21:46:57 +01:00
engine - > add_singleton ( Engine : : Singleton ( " Performance " , performance ) ) ;
2014-02-10 02:10:30 +01:00
2020-12-29 22:20:02 +01:00
// Only flush stdout in debug builds by default, as spamming `print()` will
// decrease performance if this is enabled.
2021-02-28 23:26:14 +01:00
GLOBAL_DEF_RST ( " application/run/flush_stdout_on_print " , false ) ;
GLOBAL_DEF_RST ( " application/run/flush_stdout_on_print.debug " , true ) ;
2020-12-29 22:20:02 +01:00
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: Parse CMDLine " ) ;
/* argument parsing and main creation */
List < String > args ;
List < String > main_args ;
2022-07-29 15:30:52 +02:00
List < String > user_args ;
bool adding_user_args = false ;
2022-07-07 09:57:22 +02:00
List < String > platform_args = OS : : get_singleton ( ) - > get_cmdline_platform_args ( ) ;
2016-03-09 00:00:52 +01:00
2022-07-07 09:57:22 +02:00
// Add command line arguments.
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < argc ; i + + ) {
2014-02-18 14:37:22 +01:00
args . push_back ( String : : utf8 ( argv [ i ] ) ) ;
2014-02-10 02:10:30 +01:00
}
2022-07-07 09:57:22 +02:00
// Add arguments received from macOS LaunchService (URL schemas, file associations).
for ( const String & arg : platform_args ) {
args . push_back ( arg ) ;
}
2017-03-05 16:44:50 +01:00
List < String > : : Element * I = args . front ( ) ;
2014-02-10 02:10:30 +01:00
while ( I ) {
2019-05-31 15:27:53 +02:00
I - > get ( ) = unescape_cmdline ( I - > get ( ) . strip_edges ( ) ) ;
2017-03-05 16:44:50 +01:00
I = I - > next ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
String audio_driver = " " ;
2018-05-12 13:21:26 +02:00
String project_path = " . " ;
2017-10-10 14:45:54 +02:00
bool upwards = false ;
2020-02-27 03:30:20 +01:00
String debug_uri = " " ;
2019-07-29 20:09:22 +02:00
bool skip_breakpoints = false ;
2014-06-28 04:21:45 +02:00
String main_pack ;
2017-03-05 16:44:50 +01:00
bool quiet_stdout = false ;
int rtm = - 1 ;
2014-02-10 02:10:30 +01:00
String remotefs ;
String remotefs_pass ;
Vector < String > breakpoints ;
2017-03-05 16:44:50 +01:00
bool use_custom_res = true ;
bool force_res = false ;
2021-09-01 16:47:12 +02:00
bool delta_smoothing_override = false ;
2014-02-10 02:10:30 +01:00
2022-05-09 01:25:49 +02:00
String default_renderer = " " ;
2022-09-30 04:16:13 +02:00
String default_renderer_mobile = " " ;
2022-05-09 01:25:49 +02:00
String renderer_hints = " " ;
2014-06-28 04:21:45 +02:00
packed_data = PackedData : : get_singleton ( ) ;
2020-05-14 16:41:43 +02:00
if ( ! packed_data ) {
2014-06-28 04:21:45 +02:00
packed_data = memnew ( PackedData ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
# ifdef MINIZIP_ENABLED
2016-03-09 00:00:52 +01:00
2015-05-07 01:37:25 +02:00
//XXX: always get_singleton() == 0x0
2015-04-21 00:38:02 +02:00
zip_packed_data = ZipArchive : : get_singleton ( ) ;
2015-05-07 01:37:25 +02:00
//TODO: remove this temporary fix
if ( ! zip_packed_data ) {
zip_packed_data = memnew ( ZipArchive ) ;
}
2015-04-21 00:38:02 +02:00
packed_data - > add_pack_source ( zip_packed_data ) ;
2014-02-10 02:10:30 +01:00
# endif
2022-06-30 13:55:15 +02:00
// Default exit code, can be modified for certain errors.
Error exit_code = ERR_INVALID_PARAMETER ;
2017-08-19 16:45:03 +02:00
I = args . front ( ) ;
2017-03-05 16:44:50 +01:00
while ( I ) {
2022-07-20 08:28:22 +02:00
# ifdef MACOS_ENABLED
2020-04-09 19:06:43 +02:00
// Ignore the process serial number argument passed by macOS Gatekeeper.
// Otherwise, Godot would try to open a non-existent project on the first start and abort.
if ( I - > get ( ) . begins_with ( " -psn_ " ) ) {
I = I - > next ( ) ;
continue ;
}
# endif
2022-07-29 15:30:52 +02:00
2017-03-05 16:44:50 +01:00
List < String > : : Element * N = I - > next ( ) ;
2014-02-10 02:10:30 +01:00
2022-08-13 21:52:03 +02:00
# ifdef TOOLS_ENABLED
if ( I - > get ( ) = = " --debug " | |
I - > get ( ) = = " --verbose " | |
I - > get ( ) = = " --disable-crash-handler " ) {
forwardable_cli_arguments [ CLI_SCOPE_TOOL ] . push_back ( I - > get ( ) ) ;
forwardable_cli_arguments [ CLI_SCOPE_PROJECT ] . push_back ( I - > get ( ) ) ;
}
2022-08-25 08:42:34 +02:00
if ( I - > get ( ) = = " --single-window " ) {
forwardable_cli_arguments [ CLI_SCOPE_TOOL ] . push_back ( I - > get ( ) ) ;
}
if ( I - > get ( ) = = " --audio-driver " | |
2022-08-13 21:52:03 +02:00
I - > get ( ) = = " --display-driver " | |
2022-09-08 02:44:36 +02:00
I - > get ( ) = = " --rendering-method " | |
2022-08-13 21:52:03 +02:00
I - > get ( ) = = " --rendering-driver " ) {
2022-08-25 08:42:34 +02:00
if ( I - > next ( ) ) {
forwardable_cli_arguments [ CLI_SCOPE_TOOL ] . push_back ( I - > get ( ) ) ;
forwardable_cli_arguments [ CLI_SCOPE_TOOL ] . push_back ( I - > next ( ) - > get ( ) ) ;
}
2022-08-13 21:52:03 +02:00
}
2023-03-21 22:04:57 +01:00
// 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 ( ) ) ;
}
}
2022-08-13 21:52:03 +02:00
# endif
2022-07-29 15:30:52 +02:00
if ( adding_user_args ) {
user_args . push_back ( I - > get ( ) ) ;
} else if ( I - > get ( ) = = " -h " | | I - > get ( ) = = " --help " | | I - > get ( ) = = " /? " ) { // display help
2016-03-09 00:00:52 +01:00
2017-08-19 16:45:03 +02:00
show_help = true ;
2022-07-02 01:05:20 +02:00
exit_code = ERR_HELP ; // Hack to force an early exit in `main()` with a success code.
2014-02-10 02:10:30 +01:00
goto error ;
2016-03-09 00:00:52 +01:00
2017-09-24 11:32:05 +02:00
} else if ( I - > get ( ) = = " --version " ) {
print_line ( get_full_version_string ( ) ) ;
2022-07-02 01:05:20 +02:00
exit_code = ERR_HELP ; // Hack to force an early exit in `main()` with a success code.
2017-09-24 11:32:05 +02:00
goto error ;
2019-05-19 01:33:13 +02:00
} else if ( I - > get ( ) = = " -v " | | I - > get ( ) = = " --verbose " ) { // verbose output
OS : : get_singleton ( ) - > _verbose_stdout = true ;
2021-12-07 18:06:40 +01:00
} else if ( I - > get ( ) = = " -q " | | I - > get ( ) = = " --quiet " ) { // quieter output
2019-05-19 01:33:13 +02:00
quiet_stdout = true ;
} else if ( I - > get ( ) = = " --audio-driver " ) { // audio driver
if ( I - > next ( ) ) {
audio_driver = I - > next ( ) - > get ( ) ;
2019-09-27 15:06:15 +02:00
bool found = false ;
2020-03-03 14:36:29 +01:00
for ( int i = 0 ; i < AudioDriverManager : : get_driver_count ( ) ; i + + ) {
if ( audio_driver = = AudioDriverManager : : get_driver ( i ) - > get_name ( ) ) {
2019-09-27 15:06:15 +02:00
found = true ;
}
}
if ( ! found ) {
2020-07-20 18:35:34 +02:00
OS : : get_singleton ( ) - > print ( " Unknown audio driver '%s', aborting. \n Valid options are " ,
audio_driver . utf8 ( ) . get_data ( ) ) ;
2019-09-27 15:06:15 +02:00
2020-03-03 14:36:29 +01:00
for ( int i = 0 ; i < AudioDriverManager : : get_driver_count ( ) ; i + + ) {
if ( i = = AudioDriverManager : : get_driver_count ( ) - 1 ) {
2019-09-27 15:06:15 +02:00
OS : : get_singleton ( ) - > print ( " and " ) ;
} else if ( i ! = 0 ) {
OS : : get_singleton ( ) - > print ( " , " ) ;
}
2020-03-03 14:36:29 +01:00
OS : : get_singleton ( ) - > print ( " '%s' " , AudioDriverManager : : get_driver ( i ) - > get_name ( ) ) ;
2019-09-27 15:06:15 +02:00
}
OS : : get_singleton ( ) - > print ( " . \n " ) ;
goto error ;
}
2019-05-19 01:33:13 +02:00
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing audio driver argument, aborting. \n " ) ;
goto error ;
}
2023-06-08 19:46:05 +02:00
} 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 ;
}
2020-08-05 08:25:28 +02:00
} else if ( I - > get ( ) = = " --text-driver " ) {
if ( I - > next ( ) ) {
text_driver = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing text driver argument, aborting. \n " ) ;
goto error ;
}
2019-05-19 01:33:13 +02:00
2020-03-03 14:36:29 +01:00
} else if ( I - > get ( ) = = " --display-driver " ) { // force video driver
2019-05-19 01:33:13 +02:00
if ( I - > next ( ) ) {
2020-03-03 14:36:29 +01:00
display_driver = I - > next ( ) - > get ( ) ;
2019-09-27 15:06:15 +02:00
bool found = false ;
2020-03-03 14:36:29 +01:00
for ( int i = 0 ; i < DisplayServer : : get_create_function_count ( ) ; i + + ) {
if ( display_driver = = DisplayServer : : get_create_function_name ( i ) ) {
2019-09-27 15:06:15 +02:00
found = true ;
}
}
if ( ! found ) {
2020-07-20 18:35:34 +02:00
OS : : get_singleton ( ) - > print ( " Unknown display driver '%s', aborting. \n Valid options are " ,
display_driver . utf8 ( ) . get_data ( ) ) ;
2019-09-27 15:06:15 +02:00
2020-03-03 14:36:29 +01:00
for ( int i = 0 ; i < DisplayServer : : get_create_function_count ( ) ; i + + ) {
if ( i = = DisplayServer : : get_create_function_count ( ) - 1 ) {
2019-09-27 15:06:15 +02:00
OS : : get_singleton ( ) - > print ( " and " ) ;
} else if ( i ! = 0 ) {
OS : : get_singleton ( ) - > print ( " , " ) ;
}
2020-03-03 14:36:29 +01:00
OS : : get_singleton ( ) - > print ( " '%s' " , DisplayServer : : get_create_function_name ( i ) ) ;
2019-09-27 15:06:15 +02:00
}
OS : : get_singleton ( ) - > print ( " . \n " ) ;
goto error ;
}
2019-05-19 01:33:13 +02:00
N = I - > next ( ) - > next ( ) ;
} else {
2020-11-18 19:11:30 +01:00
OS : : get_singleton ( ) - > print ( " Missing display driver argument, aborting. \n " ) ;
goto error ;
}
2022-09-08 02:44:36 +02:00
} else if ( I - > get ( ) = = " --rendering-method " ) {
if ( I - > next ( ) ) {
rendering_method = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing renderer name argument, aborting. \n " ) ;
goto error ;
}
2020-11-18 19:11:30 +01:00
} else if ( I - > get ( ) = = " --rendering-driver " ) {
if ( I - > next ( ) ) {
rendering_driver = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing rendering driver argument, aborting. \n " ) ;
2019-05-19 01:33:13 +02:00
goto error ;
}
} else if ( I - > get ( ) = = " -f " | | I - > get ( ) = = " --fullscreen " ) { // force fullscreen
init_fullscreen = true ;
2023-09-13 10:19:11 +02:00
window_mode = DisplayServer : : WINDOW_MODE_FULLSCREEN ;
2019-05-19 01:33:13 +02:00
} else if ( I - > get ( ) = = " -m " | | I - > get ( ) = = " --maximized " ) { // force maximized window
init_maximized = true ;
2020-03-03 14:36:29 +01:00
window_mode = DisplayServer : : WINDOW_MODE_MAXIMIZED ;
2019-05-19 01:33:13 +02:00
} else if ( I - > get ( ) = = " -w " | | I - > get ( ) = = " --windowed " ) { // force windowed window
init_windowed = true ;
2021-11-15 13:55:41 +01:00
} else if ( I - > get ( ) = = " --gpu-index " ) {
if ( I - > next ( ) ) {
Engine : : singleton - > gpu_idx = I - > next ( ) - > get ( ) . to_int ( ) ;
N = I - > next ( ) - > next ( ) ;
} else {
2021-12-07 20:07:47 +01:00
OS : : get_singleton ( ) - > print ( " Missing GPU index argument, aborting. \n " ) ;
2021-11-15 13:55:41 +01:00
goto error ;
}
2022-05-16 21:34:18 +02:00
} else if ( I - > get ( ) = = " --gpu-validation " ) {
2020-10-27 16:00:15 +01:00
Engine : : singleton - > use_validation_layers = true ;
2020-11-18 19:01:41 +01:00
# ifdef DEBUG_ENABLED
2020-10-27 16:00:15 +01:00
} else if ( I - > get ( ) = = " --gpu-abort " ) {
2019-10-05 15:27:43 +02:00
Engine : : singleton - > abort_on_gpu_errors = true ;
2020-10-27 16:00:15 +01:00
# endif
2023-08-12 14:56:49 +02:00
} else if ( I - > get ( ) = = " --generate-spirv-debug-info " ) {
Engine : : singleton - > generate_spirv_debug_info = true ;
2020-05-19 22:34:26 +02:00
} else if ( I - > get ( ) = = " --tablet-driver " ) {
if ( I - > next ( ) ) {
tablet_driver = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing tablet driver argument, aborting. \n " ) ;
goto error ;
}
2021-09-01 16:47:12 +02:00
} else if ( I - > get ( ) = = " --delta-smoothing " ) {
if ( I - > next ( ) ) {
String string = I - > next ( ) - > get ( ) ;
2023-06-16 08:45:35 +02:00
bool recognized = false ;
2021-09-01 16:47:12 +02:00
if ( string = = " enable " ) {
OS : : get_singleton ( ) - > set_delta_smoothing ( true ) ;
delta_smoothing_override = true ;
2023-06-16 08:45:35 +02:00
recognized = true ;
2021-09-01 16:47:12 +02:00
}
if ( string = = " disable " ) {
OS : : get_singleton ( ) - > set_delta_smoothing ( false ) ;
delta_smoothing_override = false ;
2023-06-16 08:45:35 +02:00
recognized = true ;
2021-09-01 16:47:12 +02:00
}
2023-06-16 08:45:35 +02:00
if ( ! recognized ) {
OS : : get_singleton ( ) - > print ( " Delta-smoothing argument not recognized, aborting. \n " ) ;
2021-09-01 16:47:12 +02:00
goto error ;
}
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing delta-smoothing argument, aborting. \n " ) ;
goto error ;
}
2020-03-14 17:06:39 +01:00
} else if ( I - > get ( ) = = " --single-window " ) { // force single window
2022-08-13 21:52:03 +02:00
single_window = true ;
2019-05-19 01:33:13 +02:00
} else if ( I - > get ( ) = = " -t " | | I - > get ( ) = = " --always-on-top " ) { // force always-on-top window
init_always_on_top = true ;
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --resolution " ) { // force resolution
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
String vm = I - > next ( ) - > get ( ) ;
2016-03-09 00:00:52 +01:00
2022-02-03 17:03:38 +01:00
if ( ! vm . contains ( " x " ) ) { // invalid parameter format
2016-03-09 00:00:52 +01:00
2020-07-20 18:35:34 +02:00
OS : : get_singleton ( ) - > print ( " Invalid resolution '%s', it should be e.g. '1280x720'. \n " ,
vm . utf8 ( ) . get_data ( ) ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
int w = vm . get_slice ( " x " , 0 ) . to_int ( ) ;
int h = vm . get_slice ( " x " , 1 ) . to_int ( ) ;
2016-03-09 00:00:52 +01:00
2017-08-19 16:45:03 +02:00
if ( w < = 0 | | h < = 0 ) {
2020-07-20 18:35:34 +02:00
OS : : get_singleton ( ) - > print ( " Invalid resolution '%s', width and height must be above 0. \n " ,
vm . utf8 ( ) . get_data ( ) ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2016-03-09 00:00:52 +01:00
2020-03-03 14:36:29 +01:00
window_size . width = w ;
window_size . height = h ;
2017-03-05 16:44:50 +01:00
force_res = true ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing resolution argument, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2019-05-19 01:33:13 +02:00
2023-01-04 23:00:02 +01:00
} else if ( I - > get ( ) = = " --screen " ) { // set window screen
if ( I - > next ( ) ) {
init_screen = I - > next ( ) - > get ( ) . to_int ( ) ;
2023-01-19 09:28:53 +01:00
init_use_custom_screen = true ;
2023-01-04 23:00:02 +01:00
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing screen argument, aborting. \n " ) ;
goto error ;
}
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --position " ) { // set window position
2015-08-31 04:36:46 +02:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
String vm = I - > next ( ) - > get ( ) ;
2015-08-31 04:36:46 +02:00
2022-02-03 17:03:38 +01:00
if ( ! vm . contains ( " , " ) ) { // invalid parameter format
2015-08-31 04:36:46 +02:00
2020-07-20 18:35:34 +02:00
OS : : get_singleton ( ) - > print ( " Invalid position '%s', it should be e.g. '80,128'. \n " ,
vm . utf8 ( ) . get_data ( ) ) ;
2015-08-31 04:36:46 +02:00
goto error ;
}
2017-06-21 11:09:30 +02:00
int x = vm . get_slice ( " , " , 0 ) . to_int ( ) ;
int y = vm . get_slice ( " , " , 1 ) . to_int ( ) ;
2015-08-31 04:36:46 +02:00
2017-03-05 16:44:50 +01:00
init_custom_pos = Point2 ( x , y ) ;
init_use_custom_pos = true ;
2015-08-31 04:36:46 +02:00
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2015-08-31 04:36:46 +02:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing position argument, aborting. \n " ) ;
2015-08-31 04:36:46 +02:00
goto error ;
}
2021-08-03 16:59:18 +02:00
} else if ( I - > get ( ) = = " --headless " ) { // enable headless mode (no audio, no rendering).
2022-12-20 22:49:11 +01:00
audio_driver = NULL_AUDIO_DRIVER ;
display_driver = NULL_DISPLAY_DRIVER ;
2017-12-27 20:51:19 +01:00
2024-01-19 14:39:00 +01:00
} else if ( I - > get ( ) = = " --log-file " ) { // write to log file
if ( I - > next ( ) ) {
log_file = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing log file path argument, aborting. \n " ) ;
goto error ;
}
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --profiling " ) { // enable profiling
2015-12-12 16:06:53 +01:00
2017-03-05 16:44:50 +01:00
use_debug_profiler = true ;
2016-03-09 00:00:52 +01:00
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " -l " | | I - > get ( ) = = " --language " ) { // language
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
locale = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing language argument, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2016-05-30 05:28:29 +02:00
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --remote-fs " ) { // remote filesystem
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
remotefs = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing remote filesystem address, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --remote-fs-password " ) { // remote filesystem password
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
remotefs_pass = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing remote filesystem password, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --render-thread " ) { // render thread mode
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2020-05-14 16:41:43 +02:00
if ( I - > next ( ) - > get ( ) = = " safe " ) {
2017-03-05 16:44:50 +01:00
rtm = OS : : RENDER_THREAD_SAFE ;
2020-05-14 16:41:43 +02:00
} else if ( I - > next ( ) - > get ( ) = = " unsafe " ) {
2017-03-05 16:44:50 +01:00
rtm = OS : : RENDER_THREAD_UNSAFE ;
2020-05-14 16:41:43 +02:00
} else if ( I - > next ( ) - > get ( ) = = " separate " ) {
2017-03-05 16:44:50 +01:00
rtm = OS : : RENDER_SEPARATE_THREAD ;
2023-03-26 19:42:00 +02:00
} else {
OS : : get_singleton ( ) - > print ( " Unknown render thread mode, aborting. \n Valid options are 'unsafe', 'safe' and 'separate'. \n " ) ;
goto error ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing render thread mode argument, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2018-02-16 19:40:22 +01:00
# ifdef TOOLS_ENABLED
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " -e " | | I - > get ( ) = = " --editor " ) { // starts editor
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
editor = true ;
2018-02-13 18:56:38 +01:00
} else if ( I - > get ( ) = = " -p " | | I - > get ( ) = = " --project-manager " ) { // starts project manager
project_manager = true ;
2021-08-29 01:58:15 +02:00
} else if ( I - > get ( ) = = " --debug-server " ) {
if ( I - > next ( ) ) {
debug_server_uri = I - > next ( ) - > get ( ) ;
2022-02-03 17:03:38 +01:00
if ( ! debug_server_uri . contains ( " :// " ) ) { // wrong address
2021-08-29 01:58:15 +02:00
OS : : get_singleton ( ) - > print ( " Invalid debug server uri. It should be of the form <protocol>://<bind_address>:<port>. \n " ) ;
goto error ;
}
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing remote debug server uri, aborting. \n " ) ;
goto error ;
}
2023-04-10 18:45:53 +02:00
} else if ( I - > get ( ) = = " --single-threaded-scene " ) {
single_threaded_scene = true ;
2018-02-14 16:23:04 +01:00
} else if ( I - > get ( ) = = " --build-solutions " ) { // Build the scripting solution such C#
auto_build_solutions = true ;
2018-06-16 00:08:59 +02:00
editor = true ;
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
cmdline_tool = true ;
2022-10-12 16:21:34 +02:00
} else if ( I - > get ( ) = = " --dump-gdextension-interface " ) {
// Register as an editor instance to use low-end fallback if relevant.
editor = true ;
cmdline_tool = true ;
2022-12-07 12:11:28 +01:00
dump_gdextension_interface = true ;
print_line ( " Dumping GDExtension interface header file " ) ;
2022-10-12 16:21:34 +02:00
// 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 ( ) ) ;
2021-06-19 17:58:49 +02:00
} else if ( I - > get ( ) = = " --dump-extension-api " ) {
// Register as an editor instance to use low-end fallback if relevant.
editor = true ;
cmdline_tool = true ;
dump_extension_api = true ;
2021-10-20 12:04:59 +02:00
print_line ( " Dumping Extension API " ) ;
2021-10-21 09:43:39 +02:00
// 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 ( ) ) ;
2023-09-25 22:22:06 +02:00
} 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 ( ) ) ;
Add a backwards-compatibility system for GDExtension method
This adds a way to ensure that methods that were modified in the Godot API will continue working in older builds of GDExtension even if the new signature is different.
```C++
// New version (changed)
ClassDB::bind_method(D_METHOD("add_sphere","radius","position"),&MyShapes::add_sphere);
// Compatibility version (still available to extensions).
ClassDB::bind_compatibility_method(D_METHOD("add_sphere","radius"),&MyShapes::_compat_add_sphere);
```
**Q**: If I add an extra argument and provide a default value (hence can still be called the same), do I still have to provide the compatibility version?
**A**: Yes, you must still provide a compatibility method. Most language bindings use the raw method pointer to do the call and process the default parameters in the binding language, hence if the actual method signature changes it will no longer work.
**Q**: If I removed a method, can I still bind a compatibility version even though the main method no longer exists?
**A**: Yes, for methods that were removed or renamed, compatibility versions can still be provided.
**Q**: Would it be possible to automate checking that methods were removed by mistake?
**A**: Yes, as part of a future PR, the idea is to add a a command line option to Godot that can be run like : `$ godot --test-api-compatibility older_api_dump.json`, which will also be integrated to the CI runs.
2023-04-25 20:53:07 +02:00
} else if ( I - > get ( ) = = " --validate-extension-api " ) {
// Register as an editor instance to use low-end fallback if relevant.
editor = true ;
cmdline_tool = true ;
validate_extension_api = true ;
// 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 ( ) ) ;
if ( I - > next ( ) ) {
validate_extension_api_file = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing file to load argument after --validate-extension-api, aborting. " ) ;
goto error ;
}
2022-04-15 17:11:53 +02:00
} else if ( I - > get ( ) = = " --export-release " | | I - > get ( ) = = " --export-debug " | |
2021-10-28 15:19:35 +02:00
I - > get ( ) = = " --export-pack " ) { // Export project
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
// Actually handling is done in start().
2019-06-28 14:34:09 +02:00
editor = true ;
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
cmdline_tool = true ;
main_args . push_back ( I - > get ( ) ) ;
2023-02-10 09:07:01 +01:00
# ifndef DISABLE_DEPRECATED
2023-02-22 22:20:57 +01:00
} else if ( I - > get ( ) = = " --export " ) { // For users used to 3.x syntax.
OS : : get_singleton ( ) - > print ( " The Godot 3 --export option was changed to more explicit --export-release / --export-debug / --export-pack options. \n See the --help output for details. \n " ) ;
goto error ;
2022-03-10 16:21:22 +01:00
} else if ( I - > get ( ) = = " --convert-3to4 " ) {
// Actually handling is done in start().
cmdline_tool = true ;
main_args . push_back ( I - > get ( ) ) ;
2022-08-13 22:17:35 +02:00
if ( I - > next ( ) & & ! I - > next ( ) - > get ( ) . begins_with ( " - " ) ) {
if ( itos ( I - > next ( ) - > get ( ) . to_int ( ) ) = = I - > next ( ) - > get ( ) ) {
converter_max_kb_file = I - > next ( ) - > get ( ) . to_int ( ) ;
}
if ( I - > next ( ) - > next ( ) & & ! I - > next ( ) - > next ( ) - > get ( ) . begins_with ( " - " ) ) {
if ( itos ( I - > next ( ) - > next ( ) - > get ( ) . to_int ( ) ) = = I - > next ( ) - > next ( ) - > get ( ) ) {
converter_max_line_length = I - > next ( ) - > next ( ) - > get ( ) . to_int ( ) ;
}
}
}
2022-03-10 16:21:22 +01:00
} else if ( I - > get ( ) = = " --validate-conversion-3to4 " ) {
// Actually handling is done in start().
cmdline_tool = true ;
main_args . push_back ( I - > get ( ) ) ;
2022-08-13 22:17:35 +02:00
if ( I - > next ( ) & & ! I - > next ( ) - > get ( ) . begins_with ( " - " ) ) {
if ( itos ( I - > next ( ) - > get ( ) . to_int ( ) ) = = I - > next ( ) - > get ( ) ) {
converter_max_kb_file = I - > next ( ) - > get ( ) . to_int ( ) ;
}
if ( I - > next ( ) - > next ( ) & & ! I - > next ( ) - > next ( ) - > get ( ) . begins_with ( " - " ) ) {
if ( itos ( I - > next ( ) - > next ( ) - > get ( ) . to_int ( ) ) = = I - > next ( ) - > next ( ) - > get ( ) ) {
converter_max_line_length = I - > next ( ) - > next ( ) - > get ( ) . to_int ( ) ;
}
}
}
2023-02-10 09:07:01 +01:00
# endif // DISABLE_DEPRECATED
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
} else if ( I - > get ( ) = = " --doctool " ) {
// Actually handling is done in start().
cmdline_tool = true ;
2022-02-17 22:35:37 +01:00
// `--doctool` implies `--headless` to avoid spawning an unnecessary window
// and speed up class reference generation.
2022-12-20 22:49:11 +01:00
audio_driver = NULL_AUDIO_DRIVER ;
display_driver = NULL_DISPLAY_DRIVER ;
2019-06-28 14:34:09 +02:00
main_args . push_back ( I - > get ( ) ) ;
2023-09-22 14:37:12 +02:00
# 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
2023-02-10 09:07:01 +01:00
# endif // TOOLS_ENABLED
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --path " ) { // set path of project to start or edit
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
String p = I - > next ( ) - > get ( ) ;
2022-07-19 00:27:05 +02:00
if ( OS : : get_singleton ( ) - > set_cwd ( p ) ! = OK ) {
OS : : get_singleton ( ) - > print ( " Invalid project path specified: \" %s \" , aborting. \n " , p . utf8 ( ) . get_data ( ) ) ;
goto error ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing relative or absolute path, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2017-10-10 14:45:54 +02:00
} else if ( I - > get ( ) = = " -u " | | I - > get ( ) = = " --upwards " ) { // scan folders upwards
upwards = true ;
2021-12-07 18:06:40 +01:00
} else if ( I - > get ( ) = = " --quit " ) { // Auto quit at the end of the first main loop iteration
2023-02-20 08:44:33 +01:00
quit_after = 1 ;
} else if ( I - > get ( ) = = " --quit-after " ) { // Quit after the given number of iterations
if ( I - > next ( ) ) {
quit_after = I - > next ( ) - > get ( ) . to_int ( ) ;
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing number of iterations, aborting. \n " ) ;
goto error ;
}
2017-05-01 17:44:52 +02:00
} else if ( I - > get ( ) . ends_with ( " project.godot " ) ) {
String path ;
String file = I - > get ( ) ;
2020-07-03 15:26:22 +02:00
int sep = MAX ( file . rfind ( " / " ) , file . rfind ( " \\ " ) ) ;
2020-05-14 16:41:43 +02:00
if ( sep = = - 1 ) {
2017-05-01 17:44:52 +02:00
path = " . " ;
2020-05-14 16:41:43 +02:00
} else {
2017-05-01 17:44:52 +02:00
path = file . substr ( 0 , sep ) ;
}
if ( OS : : get_singleton ( ) - > set_cwd ( path ) = = OK ) {
// path already specified, don't override
} else {
2018-05-12 13:21:26 +02:00
project_path = path ;
2017-05-01 17:44:52 +02:00
}
# ifdef TOOLS_ENABLED
editor = true ;
# endif
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " -b " | | I - > get ( ) = = " --breakpoints " ) { // add breakpoints
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
String bplist = I - > next ( ) - > get ( ) ;
2017-03-05 16:44:50 +01:00
breakpoints = bplist . split ( " , " ) ;
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing list of breakpoints, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2023-06-08 19:33:10 +02:00
} 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 ;
}
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --frame-delay " ) { // force frame delay
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
frame_delay = I - > next ( ) - > get ( ) . to_int ( ) ;
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing frame delay argument, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --time-scale " ) { // force time scale
2014-09-21 06:43:42 +02:00
if ( I - > next ( ) ) {
2020-07-24 20:07:57 +02:00
Engine : : get_singleton ( ) - > set_time_scale ( I - > next ( ) - > get ( ) . to_float ( ) ) ;
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2014-09-21 06:43:42 +02:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing time scale argument, aborting. \n " ) ;
2014-09-21 06:43:42 +02:00
goto error ;
}
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --main-pack " ) {
2014-06-28 04:21:45 +02:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
main_pack = I - > next ( ) - > get ( ) ;
2014-06-28 04:21:45 +02:00
N = I - > next ( ) - > next ( ) ;
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing path to main pack file, aborting. \n " ) ;
2014-06-28 04:21:45 +02:00
goto error ;
} ;
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " -d " | | I - > get ( ) = = " --debug " ) {
2020-02-27 03:30:20 +01:00
debug_uri = " local:// " ;
2020-07-09 09:32:42 +02:00
OS : : get_singleton ( ) - > _debug_stdout = true ;
2021-07-20 22:01:18 +02:00
# if defined(DEBUG_ENABLED)
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --debug-collisions " ) {
2017-03-05 16:44:50 +01:00
debug_collisions = true ;
2022-06-15 23:24:06 +02:00
} else if ( I - > get ( ) = = " --debug-paths " ) {
debug_paths = true ;
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --debug-navigation " ) {
2017-03-05 16:44:50 +01:00
debug_navigation = true ;
2023-01-10 07:14:16 +01:00
} else if ( I - > get ( ) = = " --debug-avoidance " ) {
debug_avoidance = true ;
2023-07-07 19:35:54 +02:00
} else if ( I - > get ( ) = = " --debug-canvas-item-redraw " ) {
debug_canvas_item_redraw = true ;
2021-07-20 22:01:18 +02:00
} else if ( I - > get ( ) = = " --debug-stringnames " ) {
StringName : : set_debug_stringnames ( true ) ;
2017-04-07 16:17:16 +02:00
# endif
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --remote-debug " ) {
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2020-02-27 03:30:20 +01:00
debug_uri = I - > next ( ) - > get ( ) ;
2022-02-03 17:03:38 +01:00
if ( ! debug_uri . contains ( " :// " ) ) { // wrong address
2020-07-20 18:35:34 +02:00
OS : : get_singleton ( ) - > print (
" Invalid debug host address, it should be of the form <protocol>://<host/IP>:<port>. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
2015-09-10 05:10:54 +02:00
}
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing remote debug host address, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
2016-09-14 04:02:18 +02:00
}
2022-07-21 21:41:02 +02:00
} else if ( I - > get ( ) = = " --editor-pid " ) { // not exposed to user
2016-09-14 04:02:18 +02:00
if ( I - > next ( ) ) {
2022-07-21 21:41:02 +02:00
editor_pid = I - > next ( ) - > get ( ) . to_int ( ) ;
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2016-09-14 04:02:18 +02:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing editor PID argument, aborting. \n " ) ;
2016-09-14 04:02:18 +02:00
goto error ;
2014-02-10 02:10:30 +01:00
}
2017-08-30 12:40:35 +02:00
} else if ( I - > get ( ) = = " --disable-render-loop " ) {
disable_render_loop = true ;
} else if ( I - > get ( ) = = " --fixed-fps " ) {
if ( I - > next ( ) ) {
fixed_fps = I - > next ( ) - > get ( ) . to_int ( ) ;
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing fixed-fps argument, aborting. \n " ) ;
goto error ;
}
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
} else if ( I - > get ( ) = = " --write-movie " ) {
if ( I - > next ( ) ) {
2022-06-26 01:38:20 +02:00
Engine : : get_singleton ( ) - > set_write_movie_path ( I - > next ( ) - > get ( ) ) ;
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
N = I - > next ( ) - > next ( ) ;
if ( fixed_fps = = - 1 ) {
fixed_fps = 60 ;
}
OS : : get_singleton ( ) - > _writing_movie = true ;
} else {
OS : : get_singleton ( ) - > print ( " Missing write-movie argument, aborting. \n " ) ;
goto error ;
}
} else if ( I - > get ( ) = = " --disable-vsync " ) {
disable_vsync = true ;
2018-03-21 08:46:05 +01:00
} else if ( I - > get ( ) = = " --print-fps " ) {
print_fps = true ;
2021-01-23 00:50:24 +01:00
} else if ( I - > get ( ) = = " --profile-gpu " ) {
profile_gpu = true ;
2017-09-08 03:01:49 +02:00
} else if ( I - > get ( ) = = " --disable-crash-handler " ) {
OS : : get_singleton ( ) - > disable_crash_handler ( ) ;
2019-07-29 20:09:22 +02:00
} else if ( I - > get ( ) = = " --skip-breakpoints " ) {
skip_breakpoints = true ;
2022-07-24 12:43:30 +02:00
} else if ( I - > get ( ) = = " --xr-mode " ) {
if ( I - > next ( ) ) {
String xr_mode = I - > next ( ) - > get ( ) . to_lower ( ) ;
N = I - > next ( ) - > next ( ) ;
if ( xr_mode = = " default " ) {
XRServer : : set_xr_mode ( XRServer : : XRMODE_DEFAULT ) ;
} else if ( xr_mode = = " off " ) {
XRServer : : set_xr_mode ( XRServer : : XRMODE_OFF ) ;
} else if ( xr_mode = = " on " ) {
XRServer : : set_xr_mode ( XRServer : : XRMODE_ON ) ;
} else {
OS : : get_singleton ( ) - > print ( " Unknown --xr-mode argument \" %s \" , aborting. \n " , xr_mode . ascii ( ) . get_data ( ) ) ;
goto error ;
}
} else {
OS : : get_singleton ( ) - > print ( " Missing --xr-mode argument, aborting. \n " ) ;
goto error ;
}
2022-08-19 14:21:43 +02:00
2023-01-13 20:24:12 +01:00
} else if ( I - > get ( ) = = " --benchmark " ) {
OS : : get_singleton ( ) - > set_use_benchmark ( true ) ;
} else if ( I - > get ( ) = = " --benchmark-file " ) {
2022-08-19 14:21:43 +02:00
if ( I - > next ( ) ) {
2023-01-13 20:24:12 +01:00
OS : : get_singleton ( ) - > set_use_benchmark ( true ) ;
String benchmark_file = I - > next ( ) - > get ( ) ;
OS : : get_singleton ( ) - > set_benchmark_file ( benchmark_file ) ;
2022-08-19 14:21:43 +02:00
N = I - > next ( ) - > next ( ) ;
} else {
2023-01-13 20:24:12 +01:00
OS : : get_singleton ( ) - > print ( " Missing <path> argument for --benchmark-file <path>. \n " ) ;
2022-08-19 14:21:43 +02:00
goto error ;
}
2023-10-08 02:29:04 +02:00
# if defined(TOOLS_ENABLED) && defined(MODULE_GDSCRIPT_ENABLED) && !defined(GDSCRIPT_NO_LSP)
2023-09-18 05:09:18 +02:00
} 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 ;
}
2023-10-08 02:29:04 +02:00
# endif // TOOLS_ENABLED && MODULE_GDSCRIPT_ENABLED && !GDSCRIPT_NO_LSP
2022-11-11 18:05:39 +01:00
} else if ( I - > get ( ) = = " -- " | | I - > get ( ) = = " ++ " ) {
2022-07-29 15:30:52 +02:00
adding_user_args = true ;
2014-02-10 02:10:30 +01:00
} else {
2018-05-12 12:51:41 +02:00
main_args . push_back ( I - > get ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
I = N ;
2014-02-10 02:10:30 +01:00
}
2020-01-10 09:48:03 +01:00
# ifdef TOOLS_ENABLED
if ( editor & & project_manager ) {
2020-07-20 18:35:34 +02:00
OS : : get_singleton ( ) - > print (
" Error: Command line arguments implied opening both editor and project manager, which is not possible. Aborting. \n " ) ;
2020-01-10 09:48:03 +01:00
goto error ;
}
# endif
2018-11-08 18:42:41 +01:00
// Network file system needs to be configured before globals, since globals are based on the
// 'project.godot' file which will only be available through the network if this is enabled
2021-12-09 10:42:46 +01:00
if ( ! remotefs . is_empty ( ) ) {
2018-11-08 18:42:41 +01:00
int port ;
2022-02-03 17:03:38 +01:00
if ( remotefs . contains ( " : " ) ) {
2018-11-08 18:42:41 +01:00
port = remotefs . get_slicec ( ' : ' , 1 ) . to_int ( ) ;
remotefs = remotefs . get_slicec ( ' : ' , 0 ) ;
} else {
port = 6010 ;
}
2023-04-28 13:15:36 +02:00
Error err = OS : : get_singleton ( ) - > setup_remote_filesystem ( remotefs , port , remotefs_pass , project_path ) ;
2018-11-08 18:42:41 +01:00
if ( err ) {
OS : : get_singleton ( ) - > printerr ( " Could not connect to remotefs: %s:%i. \n " , remotefs . utf8 ( ) . get_data ( ) , port ) ;
goto error ;
}
}
2021-11-22 16:10:31 +01:00
if ( globals - > setup ( project_path , main_pack , upwards , editor ) = = OK ) {
2019-02-18 20:28:40 +01:00
# ifdef TOOLS_ENABLED
2018-03-15 12:22:10 +01:00
found_project = true ;
2019-02-18 20:28:40 +01:00
# endif
2018-03-15 12:22:10 +01:00
} else {
# ifdef TOOLS_ENABLED
editor = false ;
# else
2020-01-28 00:10:31 +01:00
const String error_msg = " Error: Couldn't load project data at path \" " + project_path + " \" . Is the .pck file missing? \n If you've renamed the executable, the associated .pck file should also be renamed to match the executable's name (without the extension). \n " ;
2021-09-01 16:19:25 +02:00
OS : : get_singleton ( ) - > print ( " %s " , error_msg . utf8 ( ) . get_data ( ) ) ;
2021-07-22 18:23:48 +02:00
OS : : get_singleton ( ) - > alert ( error_msg ) ;
2018-03-15 12:22:10 +01:00
goto error ;
# endif
}
2023-05-11 12:24:59 +02:00
// Initialize WorkerThreadPool.
2023-12-01 19:39:09 +01:00
{
# ifdef THREADS_ENABLED
if ( editor | | project_manager ) {
WorkerThreadPool : : get_singleton ( ) - > init ( - 1 , 0.75 ) ;
} else {
int worker_threads = GLOBAL_GET ( " threading/worker_pool/max_threads " ) ;
float low_priority_ratio = GLOBAL_GET ( " threading/worker_pool/low_priority_thread_ratio " ) ;
WorkerThreadPool : : get_singleton ( ) - > init ( worker_threads , low_priority_ratio ) ;
}
# else
WorkerThreadPool : : get_singleton ( ) - > init ( 0 , 0 ) ;
# endif
2023-05-11 12:24:59 +02:00
}
2023-08-02 22:14:03 +02:00
# ifdef TOOLS_ENABLED
if ( editor ) {
Engine : : get_singleton ( ) - > set_editor_hint ( true ) ;
2023-08-05 03:34:14 +02:00
Engine : : get_singleton ( ) - > set_extension_reloading_enabled ( true ) ;
2023-08-02 22:14:03 +02:00
}
# endif
2020-06-15 14:32:46 +02:00
// Initialize user data dir.
OS : : get_singleton ( ) - > ensure_user_data_dir ( ) ;
2022-05-03 11:56:08 +02:00
initialize_modules ( MODULE_INITIALIZATION_LEVEL_CORE ) ;
2022-02-16 18:02:38 +01:00
register_core_extensions ( ) ; // core extensions must be registered after globals setup and before display
2021-07-23 21:01:18 +02:00
ResourceUID : : get_singleton ( ) - > load_from_cache ( ) ; // load UUIDs from cache.
2022-12-20 22:49:11 +01:00
if ( ProjectSettings : : get_singleton ( ) - > has_custom_feature ( " dedicated_server " ) ) {
audio_driver = NULL_AUDIO_DRIVER ;
display_driver = NULL_DISPLAY_DRIVER ;
}
2022-11-08 19:53:22 +01:00
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " network/limits/debugger/max_chars_per_second " , PROPERTY_HINT_RANGE , " 0, 4096, 1, or_greater " ) , 32768 ) ;
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " network/limits/debugger/max_queued_messages " , PROPERTY_HINT_RANGE , " 0, 8192, 1, or_greater " ) , 2048 ) ;
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " network/limits/debugger/max_errors_per_second " , PROPERTY_HINT_RANGE , " 0, 200, 1, or_greater " ) , 400 ) ;
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " network/limits/debugger/max_warnings_per_second " , PROPERTY_HINT_RANGE , " 0, 200, 1, or_greater " ) , 400 ) ;
2014-02-10 02:10:30 +01:00
2022-07-21 21:41:02 +02:00
EngineDebugger : : initialize ( debug_uri , skip_breakpoints , breakpoints , [ ] ( ) {
if ( editor_pid ) {
DisplayServer : : get_singleton ( ) - > enable_for_stealing_focus ( editor_pid ) ;
}
} ) ;
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
if ( editor ) {
packed_data - > set_disabled ( true ) ;
2017-06-21 11:09:30 +02:00
main_args . push_back ( " --editor " ) ;
2023-09-13 10:19:11 +02:00
if ( ! init_windowed & & ! init_fullscreen ) {
2017-12-29 20:10:15 +01:00
init_maximized = true ;
2020-03-03 14:36:29 +01:00
window_mode = DisplayServer : : WINDOW_MODE_MAXIMIZED ;
2017-12-29 20:10:15 +01:00
}
2014-02-10 02:10:30 +01:00
}
2020-01-10 09:48:03 +01:00
if ( ! project_manager & & ! editor ) {
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
// If we didn't find a project, we fall back to the project manager.
project_manager = ! found_project & & ! cmdline_tool ;
2018-02-13 18:56:38 +01:00
}
2022-02-12 20:55:11 +01:00
if ( project_manager ) {
Engine : : get_singleton ( ) - > set_project_manager_hint ( true ) ;
}
2014-02-10 02:10:30 +01:00
# endif
2021-02-17 17:44:49 +01:00
GLOBAL_DEF ( " debug/file_logging/enable_file_logging " , false ) ;
2020-07-12 14:22:06 +02:00
// Only file logging by default on desktop platforms as logs can't be
// accessed easily on mobile/Web platforms (if at all).
// This also prevents logs from being created for the editor instance, as feature tags
// are disabled while in the editor (even if they should logically apply).
2021-02-17 17:44:49 +01:00
GLOBAL_DEF ( " debug/file_logging/enable_file_logging.pc " , true ) ;
GLOBAL_DEF ( " debug/file_logging/log_path " , " user://logs/godot.log " ) ;
2022-11-08 19:53:22 +01:00
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " debug/file_logging/max_log_files " , PROPERTY_HINT_RANGE , " 0,20,1,or_greater " ) , 5 ) ;
2024-01-19 14:39:00 +01:00
// If `--log-file` is used to override the log path, allow creating logs for the project manager or editor
// and even if file logging is disabled in the Project Settings.
// `--log-file` can be used with any path (including absolute paths outside the project folder),
// so check for filesystem access if it's used.
if ( FileAccess : : get_create_func ( ! log_file . is_empty ( ) ? FileAccess : : ACCESS_FILESYSTEM : FileAccess : : ACCESS_USERDATA ) & &
( ! log_file . is_empty ( ) | | ( ! project_manager & & ! editor & & GLOBAL_GET ( " debug/file_logging/enable_file_logging " ) ) ) ) {
2020-07-12 14:22:06 +02:00
// Don't create logs for the project manager as they would be written to
// the current working directory, which is inconvenient.
2024-01-19 14:39:00 +01:00
String base_path ;
int max_files ;
if ( ! log_file . is_empty ( ) ) {
base_path = log_file ;
// Ensure log file name respects the specified override by disabling log rotation.
max_files = 1 ;
} else {
base_path = GLOBAL_GET ( " debug/file_logging/log_path " ) ;
max_files = GLOBAL_GET ( " debug/file_logging/max_log_files " ) ;
}
2020-07-12 14:22:06 +02:00
OS : : get_singleton ( ) - > add_logger ( memnew ( RotatedFileLogger ( base_path , max_files ) ) ) ;
}
2021-02-17 17:44:49 +01:00
if ( main_args . size ( ) = = 0 & & String ( GLOBAL_GET ( " application/run/main_scene " ) ) = = " " ) {
2018-02-26 17:16:29 +01:00
# ifdef TOOLS_ENABLED
if ( ! editor & & ! project_manager ) {
# endif
2021-09-01 16:19:25 +02:00
const String error_msg = " Error: Can't run project: no main scene defined in the project. \n " ;
OS : : get_singleton ( ) - > print ( " %s " , error_msg . utf8 ( ) . get_data ( ) ) ;
OS : : get_singleton ( ) - > alert ( error_msg ) ;
2018-02-26 17:16:29 +01:00
goto error ;
# ifdef TOOLS_ENABLED
}
# endif
}
2018-02-19 13:31:06 +01:00
if ( editor | | project_manager ) {
2019-03-09 01:04:53 +01:00
Engine : : get_singleton ( ) - > set_editor_hint ( true ) ;
2018-02-19 13:31:06 +01:00
use_custom_res = false ;
2016-06-05 06:19:42 +02:00
input_map - > load_default ( ) ; //keys for editor
2018-02-19 13:31:06 +01:00
} else {
2020-10-02 09:04:09 +02:00
input_map - > load_from_project_settings ( ) ; //keys for game
2018-02-19 13:31:06 +01:00
}
2022-10-18 16:43:37 +02:00
if ( bool ( GLOBAL_GET ( " application/run/disable_stdout " ) ) ) {
2018-02-19 13:31:06 +01:00
quiet_stdout = true ;
}
2022-10-18 16:43:37 +02:00
if ( bool ( GLOBAL_GET ( " application/run/disable_stderr " ) ) ) {
2022-05-20 14:28:44 +02:00
CoreGlobals : : print_error_enabled = false ;
2021-11-12 13:49:49 +01:00
}
2018-02-19 13:31:06 +01:00
2020-05-14 16:41:43 +02:00
if ( quiet_stdout ) {
2022-05-20 14:28:44 +02:00
CoreGlobals : : print_line_enabled = false ;
2020-05-14 16:41:43 +02:00
}
2018-02-19 13:31:06 +01:00
2022-10-18 16:43:37 +02:00
Logger : : set_flush_stdout_on_print ( GLOBAL_GET ( " application/run/flush_stdout_on_print " ) ) ;
2021-02-28 23:26:14 +01:00
2022-07-29 15:30:52 +02:00
OS : : get_singleton ( ) - > set_cmdline ( execpath , main_args , user_args ) ;
2022-02-18 14:18:24 +01:00
2022-09-08 02:44:36 +02:00
{
String driver_hints = " " ;
2023-01-09 16:56:16 +01:00
String driver_hints_with_d3d12 = " " ;
{
Vector < String > driver_hints_arr ;
2022-09-08 02:44:36 +02:00
# ifdef VULKAN_ENABLED
2023-01-09 16:56:16 +01:00
driver_hints_arr . push_back ( " vulkan " ) ;
2022-09-08 02:44:36 +02:00
# endif
2023-01-09 16:56:16 +01:00
driver_hints = String ( " , " ) . join ( driver_hints_arr ) ;
# ifdef D3D12_ENABLED
driver_hints_arr . push_back ( " d3d12 " ) ;
# endif
driver_hints_with_d3d12 = String ( " , " ) . join ( driver_hints_arr ) ;
}
2022-09-08 02:44:36 +02:00
String default_driver = driver_hints . get_slice ( " , " , 0 ) ;
2023-01-09 16:56:16 +01:00
String default_driver_with_d3d12 = driver_hints_with_d3d12 . get_slice ( " , " , 0 ) ;
2022-09-08 02:44:36 +02:00
// For now everything defaults to vulkan when available. This can change in future updates.
2023-10-21 21:08:59 +02:00
GLOBAL_DEF_RST_NOVAL ( " rendering/rendering_device/driver " , default_driver ) ;
2023-01-09 16:56:16 +01:00
GLOBAL_DEF_RST_NOVAL ( PropertyInfo ( Variant : : STRING , " rendering/rendering_device/driver.windows " , PROPERTY_HINT_ENUM , driver_hints_with_d3d12 ) , default_driver_with_d3d12 ) ;
2023-10-21 21:08:59 +02:00
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 ) ;
2021-11-12 13:49:49 +01:00
}
2022-09-08 02:44:36 +02:00
2021-11-12 13:49:49 +01:00
{
String driver_hints = " " ;
String driver_hints_angle = " " ;
2023-09-22 09:55:55 +02:00
String driver_hints_egl = " " ;
2022-09-08 02:44:36 +02:00
# ifdef GLES3_ENABLED
2021-11-12 13:49:49 +01:00
driver_hints = " opengl3 " ;
2023-11-14 18:00:33 +01:00
driver_hints_angle = " opengl3,opengl3_angle " ; // macOS, Windows.
driver_hints_egl = " opengl3,opengl3_es " ; // Linux.
2022-09-08 02:44:36 +02:00
# endif
2020-11-18 19:11:30 +01:00
2021-11-12 13:49:49 +01:00
String default_driver = driver_hints . get_slice ( " , " , 0 ) ;
2022-09-08 02:44:36 +02:00
2023-10-21 21:08:59 +02:00
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 ) ;
2023-12-05 14:39:40 +01:00
GLOBAL_DEF_RST_NOVAL ( PropertyInfo ( Variant : : STRING , " rendering/gl_compatibility/driver.macos " , PROPERTY_HINT_ENUM , driver_hints_angle ) , default_driver ) ;
2023-09-22 09:55:55 +02:00
2023-01-15 10:42:49 +01:00
GLOBAL_DEF_RST ( " rendering/gl_compatibility/nvidia_disable_threaded_optimization " , true ) ;
2023-09-26 13:19:41 +02:00
GLOBAL_DEF_RST ( " rendering/gl_compatibility/fallback_to_angle " , true ) ;
2023-10-21 21:08:59 +02:00
GLOBAL_DEF_RST ( " rendering/gl_compatibility/fallback_to_native " , true ) ;
2023-11-06 11:17:14 +01:00
GLOBAL_DEF_RST ( " rendering/gl_compatibility/fallback_to_gles " , true ) ;
2023-09-26 13:19:41 +02:00
2023-11-07 09:59:40 +01:00
Array device_blocklist ;
# define BLOCK_DEVICE(m_vendor, m_name) \
{ \
Dictionary device ; \
device [ " vendor " ] = m_vendor ; \
device [ " name " ] = m_name ; \
device_blocklist . push_back ( device ) ; \
}
// AMD GPUs.
2023-11-23 18:15:25 +01:00
BLOCK_DEVICE ( " ATI " , " Radeon 9 " ) ; // ATI Radeon 9000 Series
BLOCK_DEVICE ( " ATI " , " Radeon X " ) ; // ATI Radeon X500-X2000 Series
BLOCK_DEVICE ( " ATI " , " Radeon HD 2 " ) ; // AMD/ATI (Mobility) Radeon HD 2xxx Series
BLOCK_DEVICE ( " ATI " , " Radeon HD 3 " ) ; // AMD/ATI (Mobility) Radeon HD 3xxx Series
BLOCK_DEVICE ( " ATI " , " Radeon HD 4 " ) ; // AMD/ATI (Mobility) Radeon HD 4xxx Series
BLOCK_DEVICE ( " ATI " , " Radeon HD 5 " ) ; // AMD/ATI (Mobility) Radeon HD 5xxx Series
BLOCK_DEVICE ( " ATI " , " Radeon HD 6 " ) ; // AMD/ATI (Mobility) Radeon HD 6xxx Series
BLOCK_DEVICE ( " ATI " , " Radeon HD 7 " ) ; // AMD/ATI (Mobility) Radeon HD 7xxx Series
BLOCK_DEVICE ( " ATI " , " Radeon HD 8 " ) ; // AMD/ATI (Mobility) Radeon HD 8xxx Series
BLOCK_DEVICE ( " ATI " , " Radeon(TM) R2 Graphics " ) ; // APUs
BLOCK_DEVICE ( " ATI " , " Radeon(TM) R3 Graphics " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon(TM) R4 Graphics " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon(TM) R5 Graphics " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon(TM) R6 Graphics " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon(TM) R7 Graphics " ) ;
BLOCK_DEVICE ( " AMD " , " Radeon(TM) R7 Graphics " ) ;
BLOCK_DEVICE ( " AMD " , " Radeon(TM) R8 Graphics " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon R5 Graphics " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon R6 Graphics " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon R7 Graphics " ) ;
BLOCK_DEVICE ( " AMD " , " Radeon R7 Graphics " ) ;
BLOCK_DEVICE ( " AMD " , " Radeon R8 Graphics " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon R5 2 " ) ; // Rx 2xx Series
BLOCK_DEVICE ( " ATI " , " Radeon R7 2 " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon R9 2 " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon R5 M2 " ) ; // Rx M2xx Series
BLOCK_DEVICE ( " ATI " , " Radeon R7 M2 " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon R9 M2 " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon (TM) R9 Fury " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon (TM) R5 3 " ) ; // Rx 3xx Series
BLOCK_DEVICE ( " AMD " , " Radeon (TM) R5 3 " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon (TM) R7 3 " ) ;
BLOCK_DEVICE ( " AMD " , " Radeon (TM) R7 3 " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon (TM) R9 3 " ) ;
BLOCK_DEVICE ( " AMD " , " Radeon (TM) R9 3 " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon (TM) R5 M3 " ) ; // Rx M3xx Series
BLOCK_DEVICE ( " AMD " , " Radeon (TM) R5 M3 " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon (TM) R7 M3 " ) ;
BLOCK_DEVICE ( " AMD " , " Radeon (TM) R7 M3 " ) ;
BLOCK_DEVICE ( " ATI " , " Radeon (TM) R9 M3 " ) ;
BLOCK_DEVICE ( " AMD " , " Radeon (TM) R9 M3 " ) ;
2023-11-07 09:59:40 +01:00
# undef BLOCK_DEVICE
GLOBAL_DEF_RST_NOVAL ( PropertyInfo ( Variant : : ARRAY , " rendering/gl_compatibility/force_angle_on_devices " , PROPERTY_HINT_ARRAY_TYPE , vformat ( " %s/%s:%s " , Variant : : DICTIONARY , PROPERTY_HINT_NONE , String ( ) ) ) , device_blocklist ) ;
2022-09-08 02:44:36 +02:00
}
2022-05-09 01:25:49 +02:00
2023-12-19 12:48:02 +01:00
// Start with RenderingDevice-based backends.
# ifdef RD_ENABLED
2022-09-08 02:44:36 +02:00
renderer_hints = " forward_plus,mobile " ;
2022-09-30 04:16:13 +02:00
default_renderer_mobile = " mobile " ;
2022-05-09 01:25:49 +02:00
# endif
2022-09-08 02:44:36 +02:00
// And Compatibility next, or first if Vulkan is disabled.
2022-05-09 01:25:49 +02:00
# ifdef GLES3_ENABLED
if ( ! renderer_hints . is_empty ( ) ) {
renderer_hints + = " , " ;
}
2022-09-08 02:44:36 +02:00
renderer_hints + = " gl_compatibility " ;
2022-09-30 04:16:13 +02:00
if ( default_renderer_mobile . is_empty ( ) ) {
default_renderer_mobile = " gl_compatibility " ;
}
2022-10-18 19:42:54 +02:00
// Default to Compatibility when using the project manager.
if ( rendering_driver . is_empty ( ) & & rendering_method . is_empty ( ) & & project_manager ) {
rendering_driver = " opengl3 " ;
rendering_method = " gl_compatibility " ;
2022-11-12 00:30:06 +01:00
default_renderer_mobile = " gl_compatibility " ;
2022-10-18 19:42:54 +02:00
}
2022-05-09 01:25:49 +02:00
# endif
if ( renderer_hints . is_empty ( ) ) {
2022-09-08 02:44:36 +02:00
ERR_PRINT ( " No renderers available. " ) ;
}
if ( ! rendering_method . is_empty ( ) ) {
if ( rendering_method ! = " forward_plus " & &
rendering_method ! = " mobile " & &
rendering_method ! = " gl_compatibility " ) {
OS : : get_singleton ( ) - > print ( " Unknown renderer name '%s', aborting. Valid options are: %s \n " , rendering_method . utf8 ( ) . get_data ( ) , renderer_hints . utf8 ( ) . get_data ( ) ) ;
goto error ;
}
}
if ( ! rendering_driver . is_empty ( ) ) {
// As the rendering drivers available may depend on the display driver and renderer
// selected, we can't do an exhaustive check here, but we can look through all
// the options in all the display drivers for a match.
bool found = false ;
for ( int i = 0 ; i < DisplayServer : : get_create_function_count ( ) ; i + + ) {
Vector < String > r_drivers = DisplayServer : : get_create_function_rendering_drivers ( i ) ;
for ( int d = 0 ; d < r_drivers . size ( ) ; d + + ) {
if ( rendering_driver = = r_drivers [ d ] ) {
found = true ;
break ;
}
}
}
if ( ! found ) {
OS : : get_singleton ( ) - > print ( " Unknown rendering driver '%s', aborting. \n Valid options are " ,
rendering_driver . utf8 ( ) . get_data ( ) ) ;
for ( int i = 0 ; i < DisplayServer : : get_create_function_count ( ) ; i + + ) {
Vector < String > r_drivers = DisplayServer : : get_create_function_rendering_drivers ( i ) ;
for ( int d = 0 ; d < r_drivers . size ( ) ; d + + ) {
OS : : get_singleton ( ) - > print ( " '%s', " , r_drivers [ d ] . utf8 ( ) . get_data ( ) ) ;
}
}
OS : : get_singleton ( ) - > print ( " . \n " ) ;
goto error ;
}
// Set a default renderer if none selected. Try to choose one that matches the driver.
if ( rendering_method . is_empty ( ) ) {
2023-09-22 09:55:55 +02:00
if ( rendering_driver = = " opengl3 " | | rendering_driver = = " opengl3_angle " | | rendering_driver = = " opengl3_es " ) {
2022-09-08 02:44:36 +02:00
rendering_method = " gl_compatibility " ;
} else {
rendering_method = " forward_plus " ;
}
}
// Now validate whether the selected driver matches with the renderer.
bool valid_combination = false ;
Vector < String > available_drivers ;
if ( rendering_method = = " forward_plus " | | rendering_method = = " mobile " ) {
2023-01-09 16:56:16 +01:00
# ifdef VULKAN_ENABLED
2022-09-08 02:44:36 +02:00
available_drivers . push_back ( " vulkan " ) ;
2022-10-25 21:20:54 +02:00
# endif
2023-01-09 16:56:16 +01:00
# ifdef D3D12_ENABLED
available_drivers . push_back ( " d3d12 " ) ;
# endif
}
2022-10-25 21:20:54 +02:00
# ifdef GLES3_ENABLED
if ( rendering_method = = " gl_compatibility " ) {
2022-09-08 02:44:36 +02:00
available_drivers . push_back ( " opengl3 " ) ;
2021-11-12 13:49:49 +01:00
available_drivers . push_back ( " opengl3_angle " ) ;
2023-09-22 09:55:55 +02:00
available_drivers . push_back ( " opengl3_es " ) ;
2022-10-25 21:20:54 +02:00
}
# endif
if ( available_drivers . is_empty ( ) ) {
2022-09-08 02:44:36 +02:00
OS : : get_singleton ( ) - > print ( " Unknown renderer name '%s', aborting. \n " , rendering_method . utf8 ( ) . get_data ( ) ) ;
goto error ;
}
for ( int i = 0 ; i < available_drivers . size ( ) ; i + + ) {
if ( rendering_driver = = available_drivers [ i ] ) {
valid_combination = true ;
break ;
}
}
if ( ! valid_combination ) {
OS : : get_singleton ( ) - > print ( " Invalid renderer/driver combination '%s' and '%s', aborting. %s only supports the following drivers " , rendering_method . utf8 ( ) . get_data ( ) , rendering_driver . utf8 ( ) . get_data ( ) , rendering_method . utf8 ( ) . get_data ( ) ) ;
for ( int d = 0 ; d < available_drivers . size ( ) ; d + + ) {
OS : : get_singleton ( ) - > print ( " '%s', " , available_drivers [ d ] . utf8 ( ) . get_data ( ) ) ;
}
OS : : get_singleton ( ) - > print ( " . \n " ) ;
goto error ;
}
2022-05-09 01:25:49 +02:00
}
default_renderer = renderer_hints . get_slice ( " , " , 0 ) ;
2022-11-08 19:53:22 +01:00
GLOBAL_DEF_RST_BASIC ( PropertyInfo ( Variant : : STRING , " rendering/renderer/rendering_method " , PROPERTY_HINT_ENUM , renderer_hints ) , default_renderer ) ;
2022-09-30 04:16:13 +02:00
GLOBAL_DEF_RST_BASIC ( " rendering/renderer/rendering_method.mobile " , default_renderer_mobile ) ;
2022-09-08 02:44:36 +02:00
GLOBAL_DEF_RST_BASIC ( " rendering/renderer/rendering_method.web " , " gl_compatibility " ) ; // This is a bit of a hack until we have WebGPU support.
2022-05-09 01:25:49 +02:00
2022-09-08 02:44:36 +02:00
// Default to ProjectSettings default if nothing set on the command line.
if ( rendering_method . is_empty ( ) ) {
rendering_method = GLOBAL_GET ( " rendering/renderer/rendering_method " ) ;
}
2021-12-09 10:42:46 +01:00
if ( rendering_driver . is_empty ( ) ) {
2022-09-08 02:44:36 +02:00
if ( rendering_method = = " gl_compatibility " ) {
rendering_driver = GLOBAL_GET ( " rendering/gl_compatibility/driver " ) ;
} else {
rendering_driver = GLOBAL_GET ( " rendering/rendering_device/driver " ) ;
}
2020-11-18 19:11:30 +01:00
}
// note this is the desired rendering driver, it doesn't mean we will get it.
// TODO - make sure this is updated in the case of fallbacks, so that the user interface
// shows the correct driver string.
OS : : get_singleton ( ) - > set_current_rendering_driver_name ( rendering_driver ) ;
2022-09-08 02:44:36 +02:00
OS : : get_singleton ( ) - > set_current_rendering_method ( rendering_method ) ;
2020-11-18 19:11:30 +01:00
2021-09-27 01:07:10 +02:00
// always convert to lower case for consistency in the code
rendering_driver = rendering_driver . to_lower ( ) ;
2014-02-10 02:10:30 +01:00
2017-11-09 17:01:29 +01:00
if ( use_custom_res ) {
if ( ! force_res ) {
2021-03-31 13:50:24 +02:00
window_size . width = GLOBAL_GET ( " display/window/size/viewport_width " ) ;
window_size . height = GLOBAL_GET ( " display/window/size/viewport_height " ) ;
if ( globals - > has_setting ( " display/window/size/window_width_override " ) & &
globals - > has_setting ( " display/window/size/window_height_override " ) ) {
int desired_width = globals - > get ( " display/window/size/window_width_override " ) ;
if ( desired_width > 0 ) {
window_size . width = desired_width ;
2019-10-04 15:26:02 +02:00
}
2021-03-31 13:50:24 +02:00
int desired_height = globals - > get ( " display/window/size/window_height_override " ) ;
if ( desired_height > 0 ) {
window_size . height = desired_height ;
2017-11-09 17:01:29 +01:00
}
}
2014-09-15 16:33:30 +02:00
}
2017-11-09 17:01:29 +01:00
2020-03-03 14:36:29 +01:00
if ( ! bool ( GLOBAL_GET ( " display/window/size/resizable " ) ) ) {
window_flags | = DisplayServer : : WINDOW_FLAG_RESIZE_DISABLED_BIT ;
}
if ( bool ( GLOBAL_GET ( " display/window/size/borderless " ) ) ) {
window_flags | = DisplayServer : : WINDOW_FLAG_BORDERLESS_BIT ;
}
if ( bool ( GLOBAL_GET ( " display/window/size/always_on_top " ) ) ) {
2020-08-15 16:53:06 +02:00
window_flags | = DisplayServer : : WINDOW_FLAG_ALWAYS_ON_TOP_BIT ;
2020-03-03 14:36:29 +01:00
}
2022-09-15 09:05:41 +02:00
if ( bool ( GLOBAL_GET ( " display/window/size/transparent " ) ) ) {
window_flags | = DisplayServer : : WINDOW_FLAG_TRANSPARENT_BIT ;
}
if ( bool ( GLOBAL_GET ( " display/window/size/extend_to_title " ) ) ) {
window_flags | = DisplayServer : : WINDOW_FLAG_EXTEND_TO_TITLE_BIT ;
}
if ( bool ( GLOBAL_GET ( " display/window/size/no_focus " ) ) ) {
window_flags | = DisplayServer : : WINDOW_FLAG_NO_FOCUS_BIT ;
}
window_mode = ( DisplayServer : : WindowMode ) ( GLOBAL_GET ( " display/window/size/mode " ) . operator int ( ) ) ;
2023-01-19 09:28:53 +01:00
int initial_position_type = GLOBAL_GET ( " display/window/size/initial_position_type " ) . operator int ( ) ;
2023-10-23 08:56:02 +02:00
if ( initial_position_type = = 0 ) { // Absolute.
2023-01-19 09:28:53 +01:00
if ( ! init_use_custom_pos ) {
init_custom_pos = GLOBAL_GET ( " display/window/size/initial_position " ) . operator Vector2i ( ) ;
init_use_custom_pos = true ;
}
2023-10-23 08:56:02 +02:00
} else if ( initial_position_type = = 1 ) { // Center of Primary Screen.
2023-01-19 09:28:53 +01:00
if ( ! init_use_custom_screen ) {
init_screen = DisplayServer : : SCREEN_PRIMARY ;
init_use_custom_screen = true ;
}
2023-10-23 08:56:02 +02:00
} else if ( initial_position_type = = 2 ) { // Center of Other Screen.
2023-01-19 09:28:53 +01:00
if ( ! init_use_custom_screen ) {
init_screen = GLOBAL_GET ( " display/window/size/initial_screen " ) . operator int ( ) ;
init_use_custom_screen = true ;
}
2023-10-23 08:56:02 +02:00
} 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 ;
}
2023-01-19 09:28:53 +01:00
}
2014-09-15 16:33:30 +02:00
}
2014-02-10 02:10:30 +01:00
2021-04-22 14:08:59 +02:00
GLOBAL_DEF ( " internationalization/locale/include_text_server_data " , false ) ;
2020-09-03 13:22:16 +02:00
2021-12-29 02:21:06 +01:00
OS : : get_singleton ( ) - > _allow_hidpi = GLOBAL_DEF ( " display/window/dpi/allow_hidpi " , true ) ;
2022-09-03 12:40:53 +02:00
OS : : get_singleton ( ) - > _allow_layered = GLOBAL_DEF ( " display/window/per_pixel_transparency/allowed " , false ) ;
2021-10-28 15:43:36 +02:00
2023-01-16 14:38:14 +01:00
# ifdef TOOLS_ENABLED
2018-02-13 18:56:38 +01:00
if ( editor | | project_manager ) {
2023-01-16 14:38:14 +01:00
// The editor and project manager always detect and use hiDPI if needed.
2018-02-13 18:56:38 +01:00
OS : : get_singleton ( ) - > _allow_hidpi = true ;
2023-01-16 14:38:14 +01:00
// Disable Vulkan overlays in editor, they cause various issues.
OS : : get_singleton ( ) - > set_environment ( " DISABLE_MANGOHUD " , " 1 " ) ; // GH-57403.
OS : : get_singleton ( ) - > set_environment ( " DISABLE_RTSS_LAYER " , " 1 " ) ; // GH-57937.
OS : : get_singleton ( ) - > set_environment ( " DISABLE_VKBASALT " , " 1 " ) ;
} else {
// Re-allow using Vulkan overlays, disabled while using the editor.
OS : : get_singleton ( ) - > unset_environment ( " DISABLE_MANGOHUD " ) ;
OS : : get_singleton ( ) - > unset_environment ( " DISABLE_RTSS_LAYER " ) ;
OS : : get_singleton ( ) - > unset_environment ( " DISABLE_VKBASALT " ) ;
2017-10-05 21:41:42 +02:00
}
2023-01-16 14:38:14 +01:00
# endif
2018-02-13 18:56:38 +01:00
2017-03-05 16:44:50 +01:00
if ( rtm = = - 1 ) {
2021-02-17 17:44:49 +01:00
rtm = GLOBAL_DEF ( " rendering/driver/threads/thread_model " , OS : : RENDER_THREAD_SAFE ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
if ( rtm > = 0 & & rtm < 3 ) {
2023-03-26 19:42:00 +02:00
if ( editor | | project_manager ) {
// Editor and project manager cannot run with rendering in a separate thread (they will crash on startup).
2017-03-05 16:44:50 +01:00
rtm = OS : : RENDER_THREAD_SAFE ;
2015-12-31 20:24:27 +01:00
}
2017-03-05 16:44:50 +01:00
OS : : get_singleton ( ) - > _render_thread_mode = OS : : RenderThreadMode ( rtm ) ;
2015-12-31 20:24:27 +01:00
}
2014-02-10 02:10:30 +01:00
2017-08-19 16:45:03 +02:00
/* Determine audio and video drivers */
2016-03-09 00:00:52 +01:00
2020-11-18 19:11:30 +01:00
// Display driver, e.g. X11, Wayland.
2022-06-30 15:41:19 +02:00
// Make sure that headless is the last one, which it is assumed to be by design.
2022-12-20 22:49:11 +01:00
DEV_ASSERT ( NULL_DISPLAY_DRIVER = = DisplayServer : : get_create_function_name ( DisplayServer : : get_create_function_count ( ) - 1 ) ) ;
2014-02-10 02:10:30 +01:00
Add Wayland support
Not everything is yet implemented, either for Godot or personal
limitations (I don't have all hardware in the world). A brief list of
the most important issues follows:
- Single-window only: the `DisplayServer` API doesn't expose enough
information for properly creating XDG shell windows.
- Very dumb rendering loop: this is very complicated, just know that
the low consumption mode is forced to 2000 Hz and some clever hacks are
in place to overcome a specific Wayland limitation. This will be
improved to the extent possible both downstream and upstream.
- Features to implement yet: IME, touch input, native file dialog,
drawing tablet (commented out due to a refactor), screen recording.
- Mouse passthrough can't be implement through a poly API, we need a
rect-based one.
- The cursor doesn't yet support fractional scaling.
- Auto scale is rounded up when using fractional scaling as we don't
have a per-window scale query API (basically we need
`DisplayServer::window_get_scale`).
- Building with `x11=no wayland=yes opengl=yes openxr=yes` fails.
This also adds a new project property and editor setting for selecting the
default DisplayServer to start, to allow this backend to start first in
exported projects (X11 is still the default for now). The editor setting
always overrides the project setting.
Special thanks to Drew Devault, toger5, Sebastian Krzyszkowiak, Leandro
Benedet Garcia, Subhransu, Yury Zhuravlev and Mara Huldra.
2023-12-15 02:55:34 +01:00
GLOBAL_DEF_RST_NOVAL ( " display/display_server/driver " , " default " ) ;
GLOBAL_DEF_RST_NOVAL ( PropertyInfo ( Variant : : STRING , " display/display_server/driver.windows " , PROPERTY_HINT_ENUM_SUGGESTION , " default,windows,headless " ) , " default " ) ;
GLOBAL_DEF_RST_NOVAL ( PropertyInfo ( Variant : : STRING , " display/display_server/driver.linuxbsd " , PROPERTY_HINT_ENUM_SUGGESTION , " default,x11,wayland,headless " ) , " default " ) ;
GLOBAL_DEF_RST_NOVAL ( PropertyInfo ( Variant : : STRING , " display/display_server/driver.android " , PROPERTY_HINT_ENUM_SUGGESTION , " default,android,headless " ) , " default " ) ;
GLOBAL_DEF_RST_NOVAL ( PropertyInfo ( Variant : : STRING , " display/display_server/driver.ios " , PROPERTY_HINT_ENUM_SUGGESTION , " default,iOS,headless " ) , " default " ) ;
GLOBAL_DEF_RST_NOVAL ( PropertyInfo ( Variant : : STRING , " display/display_server/driver.macos " , PROPERTY_HINT_ENUM_SUGGESTION , " default,macos,headless " ) , " default " ) ;
2020-11-18 19:11:30 +01:00
2021-10-20 16:37:19 +02:00
GLOBAL_DEF_RST_NOVAL ( " audio/driver/driver " , AudioDriverManager : : get_driver ( 0 ) - > get_name ( ) ) ;
2021-12-09 10:42:46 +01:00
if ( audio_driver . is_empty ( ) ) { // Specified in project.godot.
2021-10-20 16:37:19 +02:00
audio_driver = GLOBAL_GET ( " audio/driver/driver " ) ;
2017-08-19 16:45:03 +02:00
}
2022-06-30 15:41:19 +02:00
// Make sure that dummy is the last one, which it is assumed to be by design.
2022-12-20 22:49:11 +01:00
DEV_ASSERT ( NULL_AUDIO_DRIVER = = AudioDriverManager : : get_driver ( AudioDriverManager : : get_driver_count ( ) - 1 ) - > get_name ( ) ) ;
2020-03-03 14:36:29 +01:00
for ( int i = 0 ; i < AudioDriverManager : : get_driver_count ( ) ; i + + ) {
if ( audio_driver = = AudioDriverManager : : get_driver ( i ) - > get_name ( ) ) {
2017-03-05 16:44:50 +01:00
audio_driver_idx = i ;
2014-02-10 02:10:30 +01:00
break ;
}
}
2017-03-05 16:44:50 +01:00
if ( audio_driver_idx < 0 ) {
2022-06-30 15:41:19 +02:00
// If the requested driver wasn't found, pick the first entry.
// If all else failed it would be the dummy driver (no sound).
audio_driver_idx = 0 ;
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
}
2022-06-26 01:38:20 +02:00
if ( Engine : : get_singleton ( ) - > get_write_movie_path ( ) ! = String ( ) ) {
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
// Always use dummy driver for audio driver (which is last), also in no threaded mode.
audio_driver_idx = AudioDriverManager : : get_driver_count ( ) - 1 ;
AudioDriverDummy : : get_dummy_singleton ( ) - > set_use_threads ( false ) ;
2014-02-10 02:10:30 +01:00
}
{
2021-05-21 21:29:24 +02:00
window_orientation = DisplayServer : : ScreenOrientation ( int ( GLOBAL_DEF_BASIC ( " display/window/handheld/orientation " , DisplayServer : : ScreenOrientation : : SCREEN_LANDSCAPE ) ) ) ;
2014-02-10 02:10:30 +01:00
}
2021-06-19 17:44:59 +02:00
{
2023-02-18 18:06:26 +01:00
window_vsync_mode = DisplayServer : : VSyncMode ( int ( GLOBAL_DEF_BASIC ( " display/window/vsync/vsync_mode " , DisplayServer : : VSyncMode : : VSYNC_ENABLED ) ) ) ;
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
if ( disable_vsync ) {
window_vsync_mode = DisplayServer : : VSyncMode : : VSYNC_DISABLED ;
}
2021-06-19 17:44:59 +02:00
}
2022-11-08 19:53:22 +01:00
Engine : : get_singleton ( ) - > set_physics_ticks_per_second ( GLOBAL_DEF_BASIC ( PropertyInfo ( Variant : : INT , " physics/common/physics_ticks_per_second " , PROPERTY_HINT_RANGE , " 1,1000,1 " ) , 60 ) ) ;
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 ) ) ;
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
Engine : : get_singleton ( ) - > set_physics_jitter_fix ( GLOBAL_DEF ( " physics/common/physics_jitter_fix " , 0.5 ) ) ;
2022-11-08 19:53:22 +01:00
Engine : : get_singleton ( ) - > set_max_fps ( GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " application/run/max_fps " , PROPERTY_HINT_RANGE , " 0,1000,1 " ) , 0 ) ) ;
2023-06-08 19:46:05 +02:00
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 ) ;
2017-01-05 13:16:00 +01:00
2018-03-21 08:46:05 +01:00
GLOBAL_DEF ( " debug/settings/stdout/print_fps " , false ) ;
2021-08-11 02:50:28 +02:00
GLOBAL_DEF ( " debug/settings/stdout/print_gpu_profile " , false ) ;
2020-04-20 12:29:34 +02:00
GLOBAL_DEF ( " debug/settings/stdout/verbose_stdout " , false ) ;
2014-02-10 02:10:30 +01:00
2020-04-20 12:29:34 +02:00
if ( ! OS : : get_singleton ( ) - > _verbose_stdout ) { // Not manually overridden.
OS : : get_singleton ( ) - > _verbose_stdout = GLOBAL_GET ( " debug/settings/stdout/verbose_stdout " ) ;
}
2014-02-10 02:10:30 +01:00
2023-07-05 14:34:18 +02:00
# 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
2023-06-08 19:33:10 +02:00
if ( max_fps > = 0 ) {
Engine : : get_singleton ( ) - > set_max_fps ( max_fps ) ;
}
2017-03-05 16:44:50 +01:00
if ( frame_delay = = 0 ) {
2022-11-08 19:53:22 +01:00
frame_delay = GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " application/run/frame_delay_msec " , PROPERTY_HINT_RANGE , " 0,100,1,or_greater " ) , 0 ) ;
2023-10-06 21:51:26 +02:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
frame_delay = 0 ;
}
2016-07-09 17:34:30 +02:00
}
2023-06-08 19:46:05 +02:00
if ( audio_output_latency > = 1 ) {
Engine : : get_singleton ( ) - > set_audio_output_latency ( audio_output_latency ) ;
}
2017-11-22 18:40:43 +01:00
OS : : get_singleton ( ) - > set_low_processor_usage_mode ( GLOBAL_DEF ( " application/run/low_processor_mode " , false ) ) ;
2020-07-20 18:35:34 +02:00
OS : : get_singleton ( ) - > set_low_processor_usage_mode_sleep_usec (
2022-11-08 19:53:22 +01:00
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " application/run/low_processor_mode_sleep_usec " , PROPERTY_HINT_RANGE , " 0,33200,1,or_greater " ) , 6900 ) ) ; // Roughly 144 FPS
2017-11-22 18:40:43 +01:00
2021-09-01 16:47:12 +02:00
GLOBAL_DEF ( " application/run/delta_smoothing " , true ) ;
if ( ! delta_smoothing_override ) {
OS : : get_singleton ( ) - > set_delta_smoothing ( GLOBAL_GET ( " application/run/delta_smoothing " ) ) ;
}
2022-10-30 04:31:13 +01:00
GLOBAL_DEF ( " display/window/ios/allow_high_refresh_rate " , true ) ;
2019-12-09 20:38:22 +01:00
GLOBAL_DEF ( " display/window/ios/hide_home_indicator " , true ) ;
2022-10-12 21:17:36 +02:00
GLOBAL_DEF ( " display/window/ios/hide_status_bar " , true ) ;
GLOBAL_DEF ( " display/window/ios/suppress_ui_gesture " , true ) ;
2019-12-09 20:38:22 +01:00
2022-03-25 08:27:46 +01:00
// XR project settings.
2022-03-17 00:24:47 +01:00
GLOBAL_DEF_RST_BASIC ( " xr/openxr/enabled " , false ) ;
2022-11-08 19:53:22 +01:00
GLOBAL_DEF_BASIC ( PropertyInfo ( Variant : : STRING , " xr/openxr/default_action_map " , PROPERTY_HINT_FILE , " *.tres " ) , " res://openxr_action_map.tres " ) ;
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"
2024-01-15 23:26:55 +01:00
GLOBAL_DEF_BASIC ( PropertyInfo ( Variant : : INT , " xr/openxr/reference_space " , PROPERTY_HINT_ENUM , " Local,Stage,Local Floor " ) , " 1 " ) ;
2023-09-12 04:39:48 +02:00
GLOBAL_DEF_BASIC ( PropertyInfo ( Variant : : INT , " xr/openxr/environment_blend_mode " , PROPERTY_HINT_ENUM , " Opaque,Additive,Alpha " ) , " 0 " ) ;
2023-08-21 09:45:28 +02:00
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 ) ;
2022-03-25 08:27:46 +01:00
2022-12-06 12:20:51 +01:00
GLOBAL_DEF_BASIC ( " xr/openxr/submit_depth_buffer " , false ) ;
2023-02-12 05:10:50 +01:00
GLOBAL_DEF_BASIC ( " xr/openxr/startup_alert " , true ) ;
2022-12-06 12:20:51 +01:00
2023-10-03 13:38:43 +02:00
// OpenXR project extensions settings.
GLOBAL_DEF_BASIC ( " xr/openxr/extensions/hand_tracking " , true ) ;
2023-06-08 04:05:20 +02:00
GLOBAL_DEF_BASIC ( " xr/openxr/extensions/eye_gaze_interaction " , false ) ;
2022-03-25 08:27:46 +01:00
# ifdef TOOLS_ENABLED
// Disabled for now, using XR inside of the editor we'll be working on during the coming months.
// editor settings (it seems we're too early in the process when setting up rendering, to access editor settings...)
// EDITOR_DEF_RST("xr/openxr/in_editor", false);
// GLOBAL_DEF("xr/openxr/in_editor", false);
# endif
2017-01-13 16:51:14 +01:00
Engine : : get_singleton ( ) - > set_frame_delay ( frame_delay ) ;
2016-07-09 17:34:30 +02:00
2017-03-05 16:44:50 +01:00
message_queue = memnew ( MessageQueue ) ;
2014-02-10 02:10:30 +01:00
2023-04-22 15:34:16 +02:00
Thread : : release_main_thread ( ) ; // If setup2() is called from another thread, that one will become main thread, so preventively release this one.
2023-05-23 23:28:47 +02:00
set_current_thread_safe_for_nodes ( false ) ;
2023-04-22 15:34:16 +02:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Core " ) ;
2020-05-14 16:41:43 +02:00
if ( p_second_phase ) {
2014-02-10 02:10:30 +01:00
return setup2 ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Setup " ) ;
2014-02-10 02:10:30 +01:00
return OK ;
2017-03-05 16:44:50 +01:00
error :
2016-03-09 00:00:52 +01:00
2020-08-05 08:25:28 +02:00
text_driver = " " ;
2020-03-03 14:36:29 +01:00
display_driver = " " ;
2017-03-05 16:44:50 +01:00
audio_driver = " " ;
2020-05-19 22:34:26 +02:00
tablet_driver = " " ;
2022-06-26 01:38:20 +02:00
Engine : : get_singleton ( ) - > set_write_movie_path ( String ( ) ) ;
2018-05-12 13:21:26 +02:00
project_path = " " ;
2016-03-09 00:00:52 +01:00
args . clear ( ) ;
2014-02-10 02:10:30 +01:00
main_args . clear ( ) ;
2016-03-09 00:00:52 +01:00
2020-05-14 16:41:43 +02:00
if ( show_help ) {
2017-08-19 16:45:03 +02:00
print_help ( execpath ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-02-27 03:30:20 +01:00
EngineDebugger : : deinitialize ( ) ;
2020-05-14 16:41:43 +02:00
if ( performance ) {
2014-02-10 02:10:30 +01:00
memdelete ( performance ) ;
2020-05-14 16:41:43 +02:00
}
if ( input_map ) {
2014-02-10 02:10:30 +01:00
memdelete ( input_map ) ;
2020-05-14 16:41:43 +02:00
}
2021-05-24 13:54:05 +02:00
if ( time_singleton ) {
memdelete ( time_singleton ) ;
}
2020-05-14 16:41:43 +02:00
if ( translation_server ) {
2017-03-05 16:44:50 +01:00
memdelete ( translation_server ) ;
2020-05-14 16:41:43 +02:00
}
if ( globals ) {
2014-02-10 02:10:30 +01:00
memdelete ( globals ) ;
2020-05-14 16:41:43 +02:00
}
if ( engine ) {
2017-01-13 16:51:14 +01:00
memdelete ( engine ) ;
2020-05-14 16:41:43 +02:00
}
if ( packed_data ) {
2014-02-10 02:10:30 +01:00
memdelete ( packed_data ) ;
2020-05-14 16:41:43 +02:00
}
2015-04-21 00:38:02 +02:00
2015-10-30 12:56:07 +01:00
unregister_core_driver_types ( ) ;
2022-02-16 18:02:38 +01:00
unregister_core_extensions ( ) ;
2014-02-10 02:10:30 +01:00
unregister_core_types ( ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > _cmdline . clear ( ) ;
2022-07-29 15:30:52 +02:00
OS : : get_singleton ( ) - > _user_args . clear ( ) ;
2014-02-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
if ( message_queue ) {
2017-03-05 16:44:50 +01:00
memdelete ( message_queue ) ;
2020-05-14 16:41:43 +02:00
}
2023-01-13 20:24:12 +01:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Core " ) ;
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Setup " ) ;
2023-01-13 20:24:12 +01:00
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > finalize_core ( ) ;
2017-03-05 16:44:50 +01:00
locale = String ( ) ;
2016-03-09 00:00:52 +01:00
2022-06-30 13:55:15 +02:00
return exit_code ;
2014-02-10 02:10:30 +01:00
}
2023-06-09 18:04:50 +02:00
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 ;
}
2023-04-22 15:34:16 +02:00
Error Main : : setup2 ( ) {
Thread : : make_main_thread ( ) ; // Make whatever thread call this the main thread.
2023-05-23 23:28:47 +02:00
set_current_thread_safe_for_nodes ( true ) ;
2023-04-22 15:34:16 +02:00
2022-11-16 16:05:00 +01:00
// Print engine name and version
print_line ( String ( VERSION_NAME ) + " v " + get_full_version_string ( ) + " - " + String ( VERSION_WEBSITE ) ) ;
2021-05-25 02:25:11 +02:00
# ifdef TOOLS_ENABLED
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
if ( editor | | project_manager | | cmdline_tool ) {
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Initialize Early Settings " ) ;
2021-06-09 10:47:32 +02:00
EditorPaths : : create ( ) ;
2023-03-21 12:08:46 +01:00
// 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 ( ) ) ;
2023-09-26 04:07:43 +02:00
ERR_FAIL_COND_V ( dir . is_null ( ) , FAILED ) ;
2023-03-21 12:08:46 +01:00
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 ) ) {
Error err ;
Ref < FileAccess > f = FileAccess : : open ( config_file_path , FileAccess : : READ , & err ) ;
if ( f . is_valid ( ) ) {
VariantParser : : StreamFile stream ;
stream . f = f ;
String assign ;
Variant value ;
VariantParser : : Tag next_tag ;
int lines = 0 ;
String error_text ;
2023-06-09 18:04:50 +02:00
VariantParser : : ResourceParser rp_new ;
rp_new . ext_func = _parse_resource_dummy ;
rp_new . sub_func = _parse_resource_dummy ;
Add Wayland support
Not everything is yet implemented, either for Godot or personal
limitations (I don't have all hardware in the world). A brief list of
the most important issues follows:
- Single-window only: the `DisplayServer` API doesn't expose enough
information for properly creating XDG shell windows.
- Very dumb rendering loop: this is very complicated, just know that
the low consumption mode is forced to 2000 Hz and some clever hacks are
in place to overcome a specific Wayland limitation. This will be
improved to the extent possible both downstream and upstream.
- Features to implement yet: IME, touch input, native file dialog,
drawing tablet (commented out due to a refactor), screen recording.
- Mouse passthrough can't be implement through a poly API, we need a
rect-based one.
- The cursor doesn't yet support fractional scaling.
- Auto scale is rounded up when using fractional scaling as we don't
have a per-window scale query API (basically we need
`DisplayServer::window_get_scale`).
- Building with `x11=no wayland=yes opengl=yes openxr=yes` fails.
This also adds a new project property and editor setting for selecting the
default DisplayServer to start, to allow this backend to start first in
exported projects (X11 is still the default for now). The editor setting
always overrides the project setting.
Special thanks to Drew Devault, toger5, Sebastian Krzyszkowiak, Leandro
Benedet Garcia, Subhransu, Yury Zhuravlev and Mara Huldra.
2023-12-15 02:55:34 +01:00
bool screen_found = false ;
String screen_property ;
bool prefer_wayland_found = false ;
if ( editor ) {
screen_property = " interface/editor/editor_screen " ;
} else if ( project_manager ) {
screen_property = " interface/editor/project_manager_screen " ;
} else {
// Skip.
screen_found = true ;
}
if ( ! display_driver . is_empty ( ) ) {
// Skip.
prefer_wayland_found = true ;
}
while ( ! screen_found | | ! prefer_wayland_found ) {
2023-03-21 12:08:46 +01:00
assign = Variant ( ) ;
next_tag . fields . clear ( ) ;
next_tag . name = String ( ) ;
2023-06-09 18:04:50 +02:00
err = VariantParser : : parse_tag_assign_eof ( & stream , lines , error_text , next_tag , assign , value , & rp_new , true ) ;
2023-03-21 12:08:46 +01:00
if ( err = = ERR_FILE_EOF ) {
break ;
}
Add Wayland support
Not everything is yet implemented, either for Godot or personal
limitations (I don't have all hardware in the world). A brief list of
the most important issues follows:
- Single-window only: the `DisplayServer` API doesn't expose enough
information for properly creating XDG shell windows.
- Very dumb rendering loop: this is very complicated, just know that
the low consumption mode is forced to 2000 Hz and some clever hacks are
in place to overcome a specific Wayland limitation. This will be
improved to the extent possible both downstream and upstream.
- Features to implement yet: IME, touch input, native file dialog,
drawing tablet (commented out due to a refactor), screen recording.
- Mouse passthrough can't be implement through a poly API, we need a
rect-based one.
- The cursor doesn't yet support fractional scaling.
- Auto scale is rounded up when using fractional scaling as we don't
have a per-window scale query API (basically we need
`DisplayServer::window_get_scale`).
- Building with `x11=no wayland=yes opengl=yes openxr=yes` fails.
This also adds a new project property and editor setting for selecting the
default DisplayServer to start, to allow this backend to start first in
exported projects (X11 is still the default for now). The editor setting
always overrides the project setting.
Special thanks to Drew Devault, toger5, Sebastian Krzyszkowiak, Leandro
Benedet Garcia, Subhransu, Yury Zhuravlev and Mara Huldra.
2023-12-15 02:55:34 +01:00
2023-03-21 12:08:46 +01:00
if ( err = = OK & & ! assign . is_empty ( ) ) {
Add Wayland support
Not everything is yet implemented, either for Godot or personal
limitations (I don't have all hardware in the world). A brief list of
the most important issues follows:
- Single-window only: the `DisplayServer` API doesn't expose enough
information for properly creating XDG shell windows.
- Very dumb rendering loop: this is very complicated, just know that
the low consumption mode is forced to 2000 Hz and some clever hacks are
in place to overcome a specific Wayland limitation. This will be
improved to the extent possible both downstream and upstream.
- Features to implement yet: IME, touch input, native file dialog,
drawing tablet (commented out due to a refactor), screen recording.
- Mouse passthrough can't be implement through a poly API, we need a
rect-based one.
- The cursor doesn't yet support fractional scaling.
- Auto scale is rounded up when using fractional scaling as we don't
have a per-window scale query API (basically we need
`DisplayServer::window_get_scale`).
- Building with `x11=no wayland=yes opengl=yes openxr=yes` fails.
This also adds a new project property and editor setting for selecting the
default DisplayServer to start, to allow this backend to start first in
exported projects (X11 is still the default for now). The editor setting
always overrides the project setting.
Special thanks to Drew Devault, toger5, Sebastian Krzyszkowiak, Leandro
Benedet Garcia, Subhransu, Yury Zhuravlev and Mara Huldra.
2023-12-15 02:55:34 +01:00
if ( ! screen_found & & assign = = screen_property ) {
init_screen = value ;
screen_found = true ;
}
if ( ! prefer_wayland_found & & assign = = " run/platforms/linuxbsd/prefer_wayland " ) {
if ( value ) {
display_driver = " wayland " ;
} else {
display_driver = " default " ;
2023-03-21 12:08:46 +01:00
}
Add Wayland support
Not everything is yet implemented, either for Godot or personal
limitations (I don't have all hardware in the world). A brief list of
the most important issues follows:
- Single-window only: the `DisplayServer` API doesn't expose enough
information for properly creating XDG shell windows.
- Very dumb rendering loop: this is very complicated, just know that
the low consumption mode is forced to 2000 Hz and some clever hacks are
in place to overcome a specific Wayland limitation. This will be
improved to the extent possible both downstream and upstream.
- Features to implement yet: IME, touch input, native file dialog,
drawing tablet (commented out due to a refactor), screen recording.
- Mouse passthrough can't be implement through a poly API, we need a
rect-based one.
- The cursor doesn't yet support fractional scaling.
- Auto scale is rounded up when using fractional scaling as we don't
have a per-window scale query API (basically we need
`DisplayServer::window_get_scale`).
- Building with `x11=no wayland=yes opengl=yes openxr=yes` fails.
This also adds a new project property and editor setting for selecting the
default DisplayServer to start, to allow this backend to start first in
exported projects (X11 is still the default for now). The editor setting
always overrides the project setting.
Special thanks to Drew Devault, toger5, Sebastian Krzyszkowiak, Leandro
Benedet Garcia, Subhransu, Yury Zhuravlev and Mara Huldra.
2023-12-15 02:55:34 +01:00
prefer_wayland_found = true ;
2023-03-21 12:08:46 +01:00
}
}
}
}
}
}
2022-09-24 18:49:53 +02:00
if ( found_project & & EditorPaths : : get_singleton ( ) - > is_self_contained ( ) ) {
2022-09-21 08:34:26 +02:00
if ( ProjectSettings : : get_singleton ( ) - > get_resource_path ( ) = = OS : : get_singleton ( ) - > get_executable_path ( ) . get_base_dir ( ) ) {
ERR_PRINT ( " You are trying to run a self-contained editor at the same location as a project. This is not allowed, since editor files will mix with project files. " ) ;
OS : : get_singleton ( ) - > set_exit_code ( EXIT_FAILURE ) ;
return FAILED ;
}
}
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Initialize Early Settings " ) ;
2021-05-25 02:25:11 +02:00
}
# endif
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Servers " ) ;
tsman = memnew ( TextServerManager ) ;
if ( tsman ) {
Ref < TextServerDummy > ts ;
ts . instantiate ( ) ;
tsman - > add_interface ( ts ) ;
}
physics_server_3d_manager = memnew ( PhysicsServer3DManager ) ;
physics_server_2d_manager = memnew ( PhysicsServer2DManager ) ;
register_server_types ( ) ;
{
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Servers " , " Modules and Extensions " ) ;
initialize_modules ( MODULE_INITIALIZATION_LEVEL_SERVERS ) ;
GDExtensionManager : : get_singleton ( ) - > initialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_SERVERS ) ;
OS : : get_singleton ( ) - > benchmark_end_measure ( " Servers " , " Modules and Extensions " ) ;
}
2020-03-03 14:36:29 +01:00
/* Initialize Input */
2023-12-08 12:52:49 +01:00
{
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Servers " , " Input " ) ;
input = memnew ( Input ) ;
OS : : get_singleton ( ) - > initialize_joypads ( ) ;
OS : : get_singleton ( ) - > benchmark_end_measure ( " Servers " , " Input " ) ;
}
2020-03-03 14:36:29 +01:00
2021-03-12 14:35:16 +01:00
/* Initialize Display Server */
2020-03-03 14:36:29 +01:00
{
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Servers " , " Display " ) ;
Add Wayland support
Not everything is yet implemented, either for Godot or personal
limitations (I don't have all hardware in the world). A brief list of
the most important issues follows:
- Single-window only: the `DisplayServer` API doesn't expose enough
information for properly creating XDG shell windows.
- Very dumb rendering loop: this is very complicated, just know that
the low consumption mode is forced to 2000 Hz and some clever hacks are
in place to overcome a specific Wayland limitation. This will be
improved to the extent possible both downstream and upstream.
- Features to implement yet: IME, touch input, native file dialog,
drawing tablet (commented out due to a refactor), screen recording.
- Mouse passthrough can't be implement through a poly API, we need a
rect-based one.
- The cursor doesn't yet support fractional scaling.
- Auto scale is rounded up when using fractional scaling as we don't
have a per-window scale query API (basically we need
`DisplayServer::window_get_scale`).
- Building with `x11=no wayland=yes opengl=yes openxr=yes` fails.
This also adds a new project property and editor setting for selecting the
default DisplayServer to start, to allow this backend to start first in
exported projects (X11 is still the default for now). The editor setting
always overrides the project setting.
Special thanks to Drew Devault, toger5, Sebastian Krzyszkowiak, Leandro
Benedet Garcia, Subhransu, Yury Zhuravlev and Mara Huldra.
2023-12-15 02:55:34 +01:00
if ( display_driver . is_empty ( ) ) {
display_driver = GLOBAL_GET ( " display/display_server/driver " ) ;
}
int display_driver_idx = - 1 ;
if ( display_driver . is_empty ( ) | | display_driver = = " default " ) {
display_driver_idx = 0 ;
} else {
for ( int i = 0 ; i < DisplayServer : : get_create_function_count ( ) ; i + + ) {
String name = DisplayServer : : get_create_function_name ( i ) ;
if ( display_driver = = name ) {
display_driver_idx = i ;
break ;
}
}
if ( display_driver_idx < 0 ) {
// If the requested driver wasn't found, pick the first entry.
// If all else failed it would be the headless server.
display_driver_idx = 0 ;
}
}
// Store this in a globally accessible place, so we can retrieve the rendering drivers
// list from the display driver for the editor UI.
OS : : get_singleton ( ) - > set_display_driver_id ( display_driver_idx ) ;
2020-03-03 14:36:29 +01:00
2022-10-23 12:34:41 +02:00
Vector2i * window_position = nullptr ;
Vector2i position = init_custom_pos ;
if ( init_use_custom_pos ) {
window_position = & position ;
}
2023-01-11 19:14:43 +01:00
Color boot_bg_color = GLOBAL_DEF_BASIC ( " application/boot_splash/bg_color " , boot_splash_bg_color ) ;
DisplayServer : : set_early_window_clear_color_override ( true , boot_bg_color ) ;
2020-11-18 19:11:30 +01:00
// rendering_driver now held in static global String in main and initialized in setup()
2020-03-03 14:36:29 +01:00
Error err ;
2023-01-04 23:00:02 +01:00
display_server = DisplayServer : : create ( display_driver_idx , rendering_driver , window_mode , window_vsync_mode , window_flags , window_position , window_size , init_screen , err ) ;
2020-08-05 08:25:28 +02:00
if ( err ! = OK | | display_server = = nullptr ) {
2022-06-30 15:41:19 +02:00
// We can't use this display server, try other ones as fallback.
// Skip headless (always last registered) because that's not what users
// would expect if they didn't request it explicitly.
for ( int i = 0 ; i < DisplayServer : : get_create_function_count ( ) - 1 ; i + + ) {
2020-03-03 14:36:29 +01:00
if ( i = = display_driver_idx ) {
2022-06-30 15:41:19 +02:00
continue ; // Don't try the same twice.
2020-03-03 14:36:29 +01:00
}
2023-01-04 23:00:02 +01:00
display_server = DisplayServer : : create ( i , rendering_driver , window_mode , window_vsync_mode , window_flags , window_position , window_size , init_screen , err ) ;
2020-08-05 08:25:28 +02:00
if ( err = = OK & & display_server ! = nullptr ) {
2020-03-03 14:36:29 +01:00
break ;
}
}
}
2020-08-05 08:25:28 +02:00
if ( err ! = OK | | display_server = = nullptr ) {
2023-12-21 23:42:39 +01:00
ERR_PRINT ( " Unable to create DisplayServer, all display drivers failed. \n Use \" --headless \" command line argument to run the engine in headless mode if this is desired (e.g. for continuous integration). " ) ;
2020-03-03 14:36:29 +01:00
return err ;
}
2023-12-08 12:52:49 +01:00
if ( display_server - > has_feature ( DisplayServer : : FEATURE_ORIENTATION ) ) {
display_server - > screen_set_orientation ( window_orientation ) ;
}
OS : : get_singleton ( ) - > benchmark_end_measure ( " Servers " , " Display " ) ;
2018-01-03 18:26:44 +01:00
}
2018-08-25 00:04:25 +02:00
2021-12-20 19:49:04 +01:00
if ( GLOBAL_GET ( " debug/settings/stdout/print_fps " ) | | print_fps ) {
// Print requested V-Sync mode at startup to diagnose the printed FPS not going above the monitor refresh rate.
switch ( window_vsync_mode ) {
case DisplayServer : : VSyncMode : : VSYNC_DISABLED :
print_line ( " Requested V-Sync mode: Disabled " ) ;
break ;
case DisplayServer : : VSyncMode : : VSYNC_ENABLED :
print_line ( " Requested V-Sync mode: Enabled - FPS will likely be capped to the monitor refresh rate. " ) ;
break ;
case DisplayServer : : VSyncMode : : VSYNC_ADAPTIVE :
print_line ( " Requested V-Sync mode: Adaptive " ) ;
break ;
case DisplayServer : : VSyncMode : : VSYNC_MAILBOX :
print_line ( " Requested V-Sync mode: Mailbox " ) ;
break ;
}
}
2023-03-26 19:42:00 +02:00
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. " ) ;
}
2021-03-12 14:35:16 +01:00
/* Initialize Pen Tablet Driver */
2021-02-17 15:07:56 +01:00
{
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Servers " , " Tablet Driver " ) ;
2021-02-17 15:07:56 +01:00
GLOBAL_DEF_RST_NOVAL ( " input_devices/pen_tablet/driver " , " " ) ;
2023-11-10 12:17:20 +01:00
GLOBAL_DEF_RST_NOVAL ( PropertyInfo ( Variant : : STRING , " input_devices/pen_tablet/driver.windows " , PROPERTY_HINT_ENUM , " winink,wintab,dummy " ) , " " ) ;
2021-02-17 15:07:56 +01:00
2023-12-08 12:52:49 +01:00
if ( tablet_driver . is_empty ( ) ) { // specified in project.godot
tablet_driver = GLOBAL_GET ( " input_devices/pen_tablet/driver " ) ;
if ( tablet_driver . is_empty ( ) ) {
tablet_driver = DisplayServer : : get_singleton ( ) - > tablet_get_driver_name ( 0 ) ;
}
2021-02-17 15:07:56 +01:00
}
2023-12-08 12:52:49 +01:00
for ( int i = 0 ; i < DisplayServer : : get_singleton ( ) - > tablet_get_driver_count ( ) ; i + + ) {
if ( tablet_driver = = DisplayServer : : get_singleton ( ) - > tablet_get_driver_name ( i ) ) {
DisplayServer : : get_singleton ( ) - > tablet_set_current_driver ( DisplayServer : : get_singleton ( ) - > tablet_get_driver_name ( i ) ) ;
break ;
}
2021-02-17 15:07:56 +01:00
}
2023-12-08 12:52:49 +01:00
if ( DisplayServer : : get_singleton ( ) - > tablet_get_current_driver ( ) . is_empty ( ) ) {
DisplayServer : : get_singleton ( ) - > tablet_set_current_driver ( DisplayServer : : get_singleton ( ) - > tablet_get_driver_name ( 0 ) ) ;
}
2021-02-17 15:07:56 +01:00
2023-12-08 12:52:49 +01:00
print_verbose ( " Using \" " + tablet_driver + " \" pen tablet driver... " ) ;
2021-02-17 15:07:56 +01:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Servers " , " Tablet Driver " ) ;
}
2021-02-17 15:07:56 +01:00
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
/* Initialize Rendering Server */
2020-03-03 14:36:29 +01:00
2023-12-08 12:52:49 +01:00
{
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Servers " , " Rendering " ) ;
2020-03-03 14:36:29 +01:00
2023-12-08 12:52:49 +01:00
rendering_server = memnew ( RenderingServerDefault ( OS : : get_singleton ( ) - > get_render_thread_mode ( ) = = OS : : RENDER_SEPARATE_THREAD ) ) ;
2020-03-03 14:36:29 +01:00
2023-12-08 12:52:49 +01:00
rendering_server - > init ( ) ;
//rendering_server->call_set_use_vsync(OS::get_singleton()->_use_vsync);
rendering_server - > set_render_loop_enabled ( ! disable_render_loop ) ;
2020-03-03 14:36:29 +01:00
2023-12-08 12:52:49 +01:00
if ( profile_gpu | | ( ! editor & & bool ( GLOBAL_GET ( " debug/settings/stdout/print_gpu_profile " ) ) ) ) {
rendering_server - > set_print_gpu_profile ( true ) ;
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
}
2021-01-23 00:50:24 +01:00
2023-12-08 12:52:49 +01:00
if ( Engine : : get_singleton ( ) - > get_write_movie_path ( ) ! = String ( ) ) {
movie_writer = MovieWriter : : find_writer_for_file ( Engine : : get_singleton ( ) - > get_write_movie_path ( ) ) ;
if ( movie_writer = = nullptr ) {
ERR_PRINT ( " Can't find movie writer for file type, aborting: " + Engine : : get_singleton ( ) - > get_write_movie_path ( ) ) ;
Engine : : get_singleton ( ) - > set_write_movie_path ( String ( ) ) ;
}
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
}
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Servers " , " Rendering " ) ;
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
}
2021-07-31 16:23:26 +02:00
# ifdef UNIX_ENABLED
// Print warning after initializing the renderer but before initializing audio.
if ( OS : : get_singleton ( ) - > get_environment ( " USER " ) = = " root " & & ! OS : : get_singleton ( ) - > has_environment ( " GODOT_SILENCE_ROOT_WARNING " ) ) {
WARN_PRINT ( " Started the engine as `root`/superuser. This is a security risk, and subsystems like audio may not work correctly. \n Set the environment variable `GODOT_SILENCE_ROOT_WARNING` to 1 to silence this warning. " ) ;
}
# endif
2020-03-03 14:36:29 +01:00
/* Initialize Audio Driver */
2023-12-08 12:52:49 +01:00
{
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Servers " , " Audio " ) ;
AudioDriverManager : : initialize ( audio_driver_idx ) ;
2020-03-03 14:36:29 +01:00
2023-12-08 12:52:49 +01:00
print_line ( " " ) ; // Add a blank line for readability.
2020-03-03 14:36:29 +01:00
2023-12-08 12:52:49 +01:00
// Right moment to create and initialize the audio server.
audio_server = memnew ( AudioServer ) ;
audio_server - > init ( ) ;
2017-01-15 20:06:14 +01:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Servers " , " Audio " ) ;
}
/* Initialize XR Server */
2017-01-15 20:06:14 +01:00
2023-12-08 12:52:49 +01:00
{
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Servers " , " XR " ) ;
2019-06-04 15:20:37 +02:00
2023-12-08 12:52:49 +01:00
xr_server = memnew ( XRServer ) ;
2017-01-15 20:06:14 +01:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Servers " , " XR " ) ;
}
2017-01-15 20:06:14 +01:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Servers " ) ;
2017-10-07 15:51:17 +02:00
2014-02-10 02:10:30 +01:00
register_core_singletons ( ) ;
2023-12-08 12:52:49 +01:00
/* Initialize the main window and boot screen */
{
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Setup Window and Boot " ) ;
MAIN_PRINT ( " Main: Setup Logo " ) ;
2014-02-10 02:10:30 +01:00
2022-12-16 19:49:28 +01:00
# if !defined(TOOLS_ENABLED) && (defined(WEB_ENABLED) || defined(ANDROID_ENABLED))
2023-12-08 12:52:49 +01:00
bool show_logo = false ;
2017-08-21 21:15:36 +02:00
# else
2023-12-08 12:52:49 +01:00
bool show_logo = true ;
2014-02-10 02:10:30 +01:00
# endif
2023-12-08 12:52:49 +01:00
if ( init_windowed ) {
//do none..
} else if ( init_maximized ) {
DisplayServer : : get_singleton ( ) - > window_set_mode ( DisplayServer : : WINDOW_MODE_MAXIMIZED ) ;
} else if ( init_fullscreen ) {
DisplayServer : : get_singleton ( ) - > window_set_mode ( DisplayServer : : WINDOW_MODE_FULLSCREEN ) ;
}
if ( init_always_on_top ) {
DisplayServer : : get_singleton ( ) - > window_set_flag ( DisplayServer : : WINDOW_FLAG_ALWAYS_ON_TOP , true ) ;
}
2017-04-10 01:02:04 +02:00
2023-12-08 12:52:49 +01:00
MAIN_PRINT ( " Main: Load Boot Image " ) ;
2015-09-04 04:24:55 +02:00
2023-12-08 12:52:49 +01:00
Color clear = GLOBAL_DEF_BASIC ( " rendering/environment/defaults/default_clear_color " , Color ( 0.3 , 0.3 , 0.3 ) ) ;
RenderingServer : : get_singleton ( ) - > set_default_clear_color ( clear ) ;
2017-01-05 13:16:00 +01:00
2023-12-08 12:52:49 +01:00
if ( show_logo ) { //boot logo!
const bool boot_logo_image = GLOBAL_DEF_BASIC ( " application/boot_splash/show_image " , true ) ;
const String boot_logo_path = String ( GLOBAL_DEF_BASIC ( PropertyInfo ( Variant : : STRING , " application/boot_splash/image " , PROPERTY_HINT_FILE , " *.png " ) , String ( ) ) ) . strip_edges ( ) ;
const bool boot_logo_scale = GLOBAL_DEF_BASIC ( " application/boot_splash/fullsize " , true ) ;
const bool boot_logo_filter = GLOBAL_DEF_BASIC ( " application/boot_splash/use_filter " , true ) ;
2015-04-12 22:55:01 +02:00
2023-12-08 12:52:49 +01:00
Ref < Image > boot_logo ;
2015-04-12 22:55:01 +02:00
2023-12-08 12:52:49 +01:00
if ( boot_logo_image ) {
if ( ! boot_logo_path . is_empty ( ) ) {
boot_logo . instantiate ( ) ;
Error load_err = ImageLoader : : load_image ( boot_logo_path , boot_logo ) ;
if ( load_err ) {
ERR_PRINT ( " Non-existing or invalid boot splash at ' " + boot_logo_path + " '. Loading default splash. " ) ;
}
2021-04-02 15:33:50 +02:00
}
2023-12-08 12:52:49 +01:00
} else {
// Create a 1× 1 transparent image. This will effectively hide the splash image.
boot_logo . instantiate ( ) ;
boot_logo - > initialize_data ( 1 , 1 , false , Image : : FORMAT_RGBA8 ) ;
boot_logo - > set_pixel ( 0 , 0 , Color ( 0 , 0 , 0 , 0 ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-12-08 12:52:49 +01:00
Color boot_bg_color = GLOBAL_GET ( " application/boot_splash/bg_color " ) ;
2022-10-20 15:43:17 +02:00
2021-03-17 22:56:58 +01:00
# if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
2023-12-08 12:52:49 +01:00
boot_bg_color =
GLOBAL_DEF_BASIC ( " application/boot_splash/bg_color " ,
( editor | | project_manager ) ? boot_splash_editor_bg_color : boot_splash_bg_color ) ;
2021-03-17 22:56:58 +01:00
# endif
2023-12-08 12:52:49 +01:00
if ( boot_logo . is_valid ( ) ) {
RenderingServer : : get_singleton ( ) - > set_boot_image ( boot_logo , boot_bg_color , boot_logo_scale ,
boot_logo_filter ) ;
2022-01-19 16:09:52 +01:00
2023-12-08 12:52:49 +01:00
} else {
2014-02-10 02:10:30 +01:00
# ifndef NO_DEFAULT_BOOT_LOGO
2023-12-08 12:52:49 +01:00
MAIN_PRINT ( " Main: Create bootsplash " ) ;
2017-12-16 20:11:13 +01:00
# if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
2023-12-08 12:52:49 +01:00
Ref < Image > splash = ( editor | | project_manager ) ? memnew ( Image ( boot_splash_editor_png ) ) : memnew ( Image ( boot_splash_png ) ) ;
2017-12-16 20:11:13 +01:00
# else
2023-12-08 12:52:49 +01:00
Ref < Image > splash = memnew ( Image ( boot_splash_png ) ) ;
2017-12-16 20:11:13 +01:00
# endif
2014-02-10 02:10:30 +01:00
2023-12-08 12:52:49 +01:00
MAIN_PRINT ( " Main: ClearColor " ) ;
RenderingServer : : get_singleton ( ) - > set_default_clear_color ( boot_bg_color ) ;
MAIN_PRINT ( " Main: Image " ) ;
RenderingServer : : get_singleton ( ) - > set_boot_image ( splash , boot_bg_color , false ) ;
2014-02-10 02:10:30 +01:00
# endif
2023-12-08 12:52:49 +01:00
}
2014-02-10 02:10:30 +01:00
2023-01-19 08:50:01 +01:00
# if defined(TOOLS_ENABLED) && defined(MACOS_ENABLED)
2023-12-08 12:52:49 +01:00
if ( OS : : get_singleton ( ) - > get_bundle_icon_path ( ) . is_empty ( ) ) {
Ref < Image > icon = memnew ( Image ( app_icon_png ) ) ;
DisplayServer : : get_singleton ( ) - > set_icon ( icon ) ;
}
2017-09-15 18:41:11 +02:00
# endif
2023-12-08 12:52:49 +01:00
}
2016-04-08 01:30:00 +02:00
2023-12-08 12:52:49 +01:00
MAIN_PRINT ( " Main: Clear Color " ) ;
2016-04-08 01:30:00 +02:00
2023-12-08 12:52:49 +01:00
DisplayServer : : set_early_window_clear_color_override ( false ) ;
RenderingServer : : get_singleton ( ) - > set_default_clear_color (
GLOBAL_GET ( " rendering/environment/defaults/default_clear_color " ) ) ;
2023-01-11 19:14:43 +01:00
2023-12-08 12:52:49 +01:00
GLOBAL_DEF_BASIC ( PropertyInfo ( Variant : : STRING , " application/config/icon " , PROPERTY_HINT_FILE , " *.png,*.webp,*.svg " ) , String ( ) ) ;
GLOBAL_DEF ( PropertyInfo ( Variant : : STRING , " application/config/macos_native_icon " , PROPERTY_HINT_FILE , " *.icns " ) , String ( ) ) ;
GLOBAL_DEF ( PropertyInfo ( Variant : : STRING , " application/config/windows_native_icon " , PROPERTY_HINT_FILE , " *.ico " ) , String ( ) ) ;
2016-04-08 01:30:00 +02:00
2023-12-08 12:52:49 +01:00
MAIN_PRINT ( " Main: Touch Input " ) ;
2019-05-17 15:43:56 +02:00
2023-12-08 12:52:49 +01:00
Input * id = Input : : get_singleton ( ) ;
if ( id ) {
agile_input_event_flushing = GLOBAL_DEF ( " input_devices/buffering/agile_event_flushing " , false ) ;
2020-09-21 01:35:20 +02:00
2023-12-08 12:52:49 +01:00
if ( bool ( GLOBAL_DEF_BASIC ( " input_devices/pointing/emulate_touch_from_mouse " , false ) ) & &
! ( editor | | project_manager ) ) {
if ( ! DisplayServer : : get_singleton ( ) - > is_touchscreen_available ( ) ) {
//only if no touchscreen ui hint, set emulation
id - > set_emulate_touch_from_mouse ( true ) ;
}
2018-02-24 03:04:30 +01:00
}
2023-12-08 12:52:49 +01:00
id - > set_emulate_mouse_from_touch ( bool ( GLOBAL_DEF_BASIC ( " input_devices/pointing/emulate_mouse_from_touch " , true ) ) ) ;
2015-08-29 22:16:11 +02:00
}
2018-02-24 03:04:30 +01:00
2023-12-08 12:52:49 +01:00
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 ) ;
2015-09-24 23:06:15 +02:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Setup Window and Boot " ) ;
}
2023-10-03 03:27:47 +02:00
2021-02-02 15:15:13 +01:00
MAIN_PRINT ( " Main: Load Translations and Remaps " ) ;
2023-12-08 12:52:49 +01:00
/* Setup translations and remaps */
2021-02-02 15:15:13 +01:00
2023-12-08 12:52:49 +01:00
{
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Translations and Remaps " ) ;
2021-08-27 23:19:51 +02:00
2023-12-08 12:52:49 +01:00
translation_server - > setup ( ) ; //register translations, load them, etc.
if ( ! locale . is_empty ( ) ) {
translation_server - > set_locale ( locale ) ;
2022-08-13 12:51:07 +02:00
}
2023-12-08 12:52:49 +01:00
translation_server - > load_translations ( ) ;
ResourceLoader : : load_translation_remaps ( ) ; //load remaps for resources
2021-08-27 23:19:51 +02:00
2023-12-08 12:52:49 +01:00
ResourceLoader : : load_path_remaps ( ) ;
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Translations and Remaps " ) ;
2021-08-27 23:19:51 +02:00
}
2023-12-08 12:52:49 +01:00
MAIN_PRINT ( " Main: Load TextServer " ) ;
/* Setup Text Server */
{
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Text Server " ) ;
/* Enum text drivers */
GLOBAL_DEF_RST ( " internationalization/rendering/text_driver " , " " ) ;
String text_driver_options ;
2021-08-27 23:19:51 +02:00
for ( int i = 0 ; i < TextServerManager : : get_singleton ( ) - > get_interface_count ( ) ; i + + ) {
2023-12-08 12:52:49 +01:00
const String driver_name = TextServerManager : : get_singleton ( ) - > get_interface ( i ) - > get_name ( ) ;
if ( driver_name = = " Dummy " ) {
// Dummy text driver cannot draw any text, making the editor unusable if selected.
continue ;
2021-08-27 23:19:51 +02:00
}
2023-12-08 12:52:49 +01:00
if ( ! text_driver_options . is_empty ( ) & & text_driver_options . find ( " , " ) = = - 1 ) {
// Not the first option; add a comma before it as a separator for the property hint.
text_driver_options + = " , " ;
2021-08-27 23:19:51 +02:00
}
2023-12-08 12:52:49 +01:00
text_driver_options + = driver_name ;
2021-08-27 23:19:51 +02:00
}
2023-12-08 12:52:49 +01:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( PropertyInfo ( Variant : : STRING , " internationalization/rendering/text_driver " , PROPERTY_HINT_ENUM , text_driver_options ) ) ;
2021-08-27 23:19:51 +02:00
2023-12-08 12:52:49 +01:00
/* Determine text driver */
if ( text_driver . is_empty ( ) ) {
text_driver = GLOBAL_GET ( " internationalization/rendering/text_driver " ) ;
}
if ( ! text_driver . is_empty ( ) ) {
/* Load user selected text server. */
for ( int i = 0 ; i < TextServerManager : : get_singleton ( ) - > get_interface_count ( ) ; i + + ) {
if ( TextServerManager : : get_singleton ( ) - > get_interface ( i ) - > get_name ( ) = = text_driver ) {
text_driver_idx = i ;
break ;
}
2021-08-27 23:19:51 +02:00
}
2023-12-08 12:52:49 +01:00
}
if ( text_driver_idx < 0 ) {
/* If not selected, use one with the most features available. */
int max_features = 0 ;
for ( int i = 0 ; i < TextServerManager : : get_singleton ( ) - > get_interface_count ( ) ; i + + ) {
uint32_t features = TextServerManager : : get_singleton ( ) - > get_interface ( i ) - > get_features ( ) ;
int feature_number = 0 ;
while ( features ) {
feature_number + = features & 1 ;
features > > = 1 ;
}
if ( feature_number > = max_features ) {
max_features = feature_number ;
text_driver_idx = i ;
}
2021-08-27 23:19:51 +02:00
}
}
2023-12-08 12:52:49 +01:00
if ( text_driver_idx > = 0 ) {
Ref < TextServer > ts = TextServerManager : : get_singleton ( ) - > get_interface ( text_driver_idx ) ;
TextServerManager : : get_singleton ( ) - > set_primary_interface ( ts ) ;
if ( ts - > has_feature ( TextServer : : FEATURE_USE_SUPPORT_DATA ) ) {
ts - > load_support_data ( " res:// " + ts - > get_support_data_filename ( ) ) ;
}
} else {
ERR_FAIL_V_MSG ( ERR_CANT_CREATE , " TextServer: Unable to create TextServer interface. " ) ;
2023-01-23 20:10:42 +01:00
}
2021-08-27 23:19:51 +02:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Text Server " ) ;
}
2022-08-19 14:21:43 +02:00
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: Load Scene Types " ) ;
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Scene " ) ;
2022-08-19 14:21:43 +02:00
2023-09-04 18:07:16 +02:00
// 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 ( ) ;
2014-02-10 02:10:30 +01:00
register_scene_types ( ) ;
2022-02-28 14:50:43 +01:00
register_driver_types ( ) ;
2023-09-04 18:07:16 +02:00
register_scene_singletons ( ) ;
2023-12-08 12:52:49 +01:00
{
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Scene " , " Modules and Extensions " ) ;
initialize_modules ( MODULE_INITIALIZATION_LEVEL_SCENE ) ;
GDExtensionManager : : get_singleton ( ) - > initialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_SCENE ) ;
OS : : get_singleton ( ) - > benchmark_end_measure ( " Scene " , " Modules and Extensions " ) ;
}
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Scene " ) ;
2022-05-03 11:56:08 +02:00
2021-03-05 17:22:06 +01:00
# ifdef TOOLS_ENABLED
ClassDB : : set_current_api ( ClassDB : : API_EDITOR ) ;
2022-05-01 11:57:36 +02:00
register_editor_types ( ) ;
2023-12-08 12:52:49 +01:00
{
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Editor " , " Modules and Extensions " ) ;
initialize_modules ( MODULE_INITIALIZATION_LEVEL_EDITOR ) ;
GDExtensionManager : : get_singleton ( ) - > initialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_EDITOR ) ;
OS : : get_singleton ( ) - > benchmark_end_measure ( " Editor " , " Modules and Extensions " ) ;
}
2021-03-05 17:22:06 +01:00
ClassDB : : set_current_api ( ClassDB : : API_CORE ) ;
# endif
2023-12-08 12:52:49 +01:00
MAIN_PRINT ( " Main: Load Platforms " ) ;
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Platforms " ) ;
2021-03-05 17:22:06 +01:00
register_platform_apis ( ) ;
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Platforms " ) ;
2022-11-08 19:53:22 +01:00
GLOBAL_DEF_BASIC ( PropertyInfo ( Variant : : STRING , " display/mouse_cursor/custom_image " , PROPERTY_HINT_FILE , " *.png,*.webp " ) , String ( ) ) ;
2022-06-12 19:50:14 +02:00
GLOBAL_DEF_BASIC ( " display/mouse_cursor/custom_image_hotspot " , Vector2 ( ) ) ;
GLOBAL_DEF_BASIC ( " display/mouse_cursor/tooltip_position_offset " , Point2 ( 10 , 10 ) ) ;
2015-09-24 23:06:15 +02:00
2022-10-18 16:43:37 +02:00
if ( String ( GLOBAL_GET ( " display/mouse_cursor/custom_image " ) ) ! = String ( ) ) {
2020-07-20 18:35:34 +02:00
Ref < Texture2D > cursor = ResourceLoader : : load (
2022-10-18 16:43:37 +02:00
GLOBAL_GET ( " display/mouse_cursor/custom_image " ) ) ;
2015-09-24 23:06:15 +02:00
if ( cursor . is_valid ( ) ) {
2022-10-18 16:43:37 +02:00
Vector2 hotspot = GLOBAL_GET ( " display/mouse_cursor/custom_image_hotspot " ) ;
2020-04-28 15:19:37 +02:00
Input : : get_singleton ( ) - > set_custom_mouse_cursor ( cursor , Input : : CURSOR_ARROW , hotspot ) ;
2015-09-24 23:06:15 +02:00
}
}
2017-10-21 13:02:06 +02:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Finalize Setup " ) ;
2019-11-29 07:54:39 +01:00
camera_server = CameraServer : : create ( ) ;
2022-02-28 14:50:43 +01:00
MAIN_PRINT ( " Main: Load Physics " ) ;
2021-08-27 23:19:51 +02:00
2017-10-21 13:02:06 +02:00
initialize_physics ( ) ;
2023-12-08 12:52:49 +01:00
MAIN_PRINT ( " Main: Load Navigation " ) ;
2020-01-10 12:22:34 +01:00
initialize_navigation_server ( ) ;
2023-12-08 12:52:49 +01:00
2017-10-21 13:02:06 +02:00
register_server_singletons ( ) ;
2018-06-11 02:59:53 +02:00
// This loads global classes, so it must happen before custom loaders and savers are registered
2014-11-13 04:53:12 +01:00
ScriptServer : : init_languages ( ) ;
2023-03-07 19:10:54 +01:00
theme_db - > initialize_theme ( ) ;
2017-01-25 18:30:40 +01:00
audio_server - > load_default_bus_layout ( ) ;
2014-02-10 02:10:30 +01:00
2023-03-07 19:10:54 +01:00
# if defined(MODULE_MONO_ENABLED) && defined(TOOLS_ENABLED)
// Hacky to have it here, but we don't have good facility yet to let modules
// register command line options to call at the right time. This needs to happen
// after init'ing the ScriptServer, but also after init'ing the ThemeDB,
// for the C# docs generation in the bindings.
List < String > cmdline_args = OS : : get_singleton ( ) - > get_cmdline_args ( ) ;
BindingsGenerator : : handle_cmdline_args ( cmdline_args ) ;
# endif
2020-02-27 03:30:20 +01:00
if ( use_debug_profiler & & EngineDebugger : : is_active ( ) ) {
// Start the "scripts" profiler, used in local debugging.
// We could add more, and make the CLI arg require a comma-separated list of profilers.
EngineDebugger : : get_singleton ( ) - > profiler_enable ( " scripts " , true ) ;
2016-05-22 02:18:16 +02:00
}
2020-04-17 04:52:00 +02:00
if ( ! project_manager ) {
// If not running the project manager, and now that the engine is
// able to load resources, load the global shader variables.
2021-03-12 14:35:16 +01:00
// If running on editor, don't load the textures because the editor
2020-04-17 04:52:00 +02:00
// may want to import them first. Editor will reload those later.
2022-08-27 11:22:43 +02:00
rendering_server - > global_shader_parameters_load_settings ( ! editor ) ;
2020-04-17 04:52:00 +02:00
}
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Finalize Setup " ) ;
2017-03-05 16:44:50 +01:00
_start_success = true ;
2014-02-10 02:10:30 +01:00
2021-03-12 14:35:16 +01:00
ClassDB : : set_current_api ( ClassDB : : API_NONE ) ; //no more APIs are registered at this point
2016-09-15 00:37:37 +02:00
2019-11-01 16:16:31 +01:00
print_verbose ( " CORE API HASH: " + uitos ( ClassDB : : get_api_hash ( ClassDB : : API_CORE ) ) ) ;
print_verbose ( " EDITOR API HASH: " + uitos ( ClassDB : : get_api_hash ( ClassDB : : API_EDITOR ) ) ) ;
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: Done " ) ;
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Setup " ) ;
2022-08-19 14:21:43 +02:00
2014-02-10 02:10:30 +01:00
return OK ;
}
2021-12-14 02:44:12 +01:00
String Main : : get_rendering_driver_name ( ) {
return rendering_driver ;
}
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
// everything the main loop needs to know about frame timings
2018-05-15 22:12:35 +02:00
static MainTimerSync main_timer_sync ;
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
2014-02-10 02:10:30 +01:00
bool Main : : start ( ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! _start_success , false ) ;
2014-02-10 02:10:30 +01:00
2023-04-05 02:05:37 +02:00
bool has_icon = false ;
2019-10-29 01:42:57 +01:00
String positional_arg ;
2014-02-10 02:10:30 +01:00
String game_path ;
String script ;
2023-06-13 17:43:17 +02:00
String main_loop_type ;
2020-01-08 14:22:50 +01:00
bool check_only = false ;
# ifdef TOOLS_ENABLED
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
String doc_tool_path ;
2023-10-31 18:27:17 +01:00
BitField < DocTools : : GenerateFlags > gen_flags ;
2017-08-14 15:15:06 +02:00
String _export_preset ;
2017-03-05 16:44:50 +01:00
bool export_debug = false ;
2020-01-08 14:22:50 +01:00
bool export_pack_only = false ;
2023-12-06 05:35:52 +01:00
bool install_android_build_template = false ;
2023-04-26 23:32:03 +02:00
# ifdef MODULE_GDSCRIPT_ENABLED
String gdscript_docs_path ;
# endif
2023-02-01 22:29:33 +01:00
# ifndef DISABLE_DEPRECATED
2022-03-10 16:21:22 +01:00
bool converting_project = false ;
bool validating_converting_project = false ;
2023-02-01 22:29:33 +01:00
# endif // DISABLE_DEPRECATED
2023-02-10 09:07:01 +01:00
# endif // TOOLS_ENABLED
2017-08-19 16:45:03 +02:00
2018-05-15 22:12:35 +02:00
main_timer_sync . init ( OS : : get_singleton ( ) - > get_ticks_usec ( ) ) ;
2014-02-10 02:10:30 +01:00
List < String > args = OS : : get_singleton ( ) - > get_cmdline_args ( ) ;
2020-07-20 18:35:34 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < args . size ( ) ; i + + ) {
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
// First check parameters that do not have an argument to the right.
2020-07-20 18:35:34 +02:00
// Doctest Unit Testing Handler
// Designed to override and pass arguments to the unit test handler.
2019-02-18 20:28:40 +01:00
if ( args [ i ] = = " --check-only " ) {
check_only = true ;
2018-02-16 19:40:22 +01:00
# ifdef TOOLS_ENABLED
2019-02-18 20:28:40 +01:00
} else if ( args [ i ] = = " --no-docbase " ) {
2023-10-31 18:27:17 +01:00
gen_flags . set_flag ( DocTools : : GENERATE_FLAG_SKIP_BASIC_TYPES ) ;
2023-02-01 22:29:33 +01:00
# ifndef DISABLE_DEPRECATED
2022-03-10 16:21:22 +01:00
} else if ( args [ i ] = = " --convert-3to4 " ) {
converting_project = true ;
} else if ( args [ i ] = = " --validate-conversion-3to4 " ) {
validating_converting_project = true ;
2023-02-01 22:29:33 +01:00
# endif // DISABLE_DEPRECATED
2017-08-19 16:45:03 +02:00
} else if ( args [ i ] = = " -e " | | args [ i ] = = " --editor " ) {
2017-03-05 16:44:50 +01:00
editor = true ;
2017-08-19 16:45:03 +02:00
} else if ( args [ i ] = = " -p " | | args [ i ] = = " --project-manager " ) {
2018-02-13 18:56:38 +01:00
project_manager = true ;
2023-12-06 05:35:52 +01:00
} else if ( args [ i ] = = " --install-android-build-template " ) {
install_android_build_template = true ;
2023-02-10 09:07:01 +01:00
# endif // TOOLS_ENABLED
2021-12-09 10:42:46 +01:00
} else if ( args [ i ] . length ( ) & & args [ i ] [ 0 ] ! = ' - ' & & positional_arg . is_empty ( ) ) {
2019-10-29 01:42:57 +01:00
positional_arg = args [ i ] ;
2020-05-06 19:59:29 +02:00
if ( args [ i ] . ends_with ( " .scn " ) | |
args [ i ] . ends_with ( " .tscn " ) | |
args [ i ] . ends_with ( " .escn " ) | |
args [ i ] . ends_with ( " .res " ) | |
args [ i ] . ends_with ( " .tres " ) ) {
2019-10-29 01:42:57 +01:00
// Only consider the positional argument to be a scene path if it ends with
// a file extension associated with Godot scenes. This makes it possible
// for projects to parse command-line arguments for custom CLI arguments
// or other file extensions without trouble. This can be used to implement
// "drag-and-drop onto executable" logic, which can prove helpful
// for non-game applications.
game_path = args [ i ] ;
}
2015-11-01 17:50:44 +01:00
}
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
// Then parameters that have an argument to the right.
2017-03-05 16:44:50 +01:00
else if ( i < ( args . size ( ) - 1 ) ) {
bool parsed_pair = true ;
2018-02-16 19:40:22 +01:00
if ( args [ i ] = = " -s " | | args [ i ] = = " --script " ) {
2017-03-05 16:44:50 +01:00
script = args [ i + 1 ] ;
2023-06-13 17:43:17 +02:00
} else if ( args [ i ] = = " --main-loop " ) {
main_loop_type = args [ i + 1 ] ;
2018-02-16 19:40:22 +01:00
# ifdef TOOLS_ENABLED
} else if ( args [ i ] = = " --doctool " ) {
2021-04-05 15:35:19 +02:00
doc_tool_path = args [ i + 1 ] ;
if ( doc_tool_path . begins_with ( " - " ) ) {
// Assuming other command line arg, so default to cwd.
doc_tool_path = " . " ;
parsed_pair = false ;
2020-05-14 16:41:43 +02:00
}
2023-04-26 23:32:03 +02:00
# ifdef MODULE_GDSCRIPT_ENABLED
} else if ( args [ i ] = = " --gdscript-docs " ) {
gdscript_docs_path = args [ i + 1 ] ;
# endif
2022-04-15 17:11:53 +02:00
} else if ( args [ i ] = = " --export-release " ) {
2017-03-05 16:44:50 +01:00
editor = true ; //needs editor
2019-06-28 14:34:09 +02:00
_export_preset = args [ i + 1 ] ;
2017-06-21 11:09:30 +02:00
} else if ( args [ i ] = = " --export-debug " ) {
2017-03-05 16:44:50 +01:00
editor = true ; //needs editor
2019-06-28 14:34:09 +02:00
_export_preset = args [ i + 1 ] ;
2017-03-05 16:44:50 +01:00
export_debug = true ;
2020-01-08 14:22:50 +01:00
} else if ( args [ i ] = = " --export-pack " ) {
editor = true ;
_export_preset = args [ i + 1 ] ;
export_pack_only = true ;
2018-02-16 19:40:22 +01:00
# endif
2015-11-01 17:50:44 +01:00
} else {
// The parameter does not match anything known, don't skip the next argument
2017-03-05 16:44:50 +01:00
parsed_pair = false ;
2015-11-01 17:50:44 +01:00
}
if ( parsed_pair ) {
i + + ;
2015-09-16 22:51:19 +02:00
}
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
}
# ifdef TOOLS_ENABLED
// Handle case where no path is given to --doctool.
else if ( args [ i ] = = " --doctool " ) {
2021-04-05 15:35:19 +02:00
doc_tool_path = " . " ;
2014-02-10 02:10:30 +01:00
}
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
# endif
2014-02-10 02:10:30 +01:00
}
2022-11-08 19:53:22 +01:00
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 ) ;
2023-07-12 20:56:50 +02:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) ) {
minimum_time_msec = 0 ;
}
2022-06-28 17:13:00 +02:00
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
2023-10-08 02:29:04 +02:00
# ifdef MODULE_GDSCRIPT_ENABLED
2023-09-22 14:37:12 +02:00
if ( ! doc_tool_path . is_empty ( ) & & gdscript_docs_path . is_empty ( ) ) {
2023-10-08 02:29:04 +02:00
# else
if ( ! doc_tool_path . is_empty ( ) ) {
# endif
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
// Needed to instance editor-only classes for their default values
Engine : : get_singleton ( ) - > set_editor_hint ( true ) ;
2019-06-01 15:42:22 +02:00
2021-12-15 16:01:06 +01:00
// Translate the class reference only when `-l LOCALE` parameter is given.
if ( ! locale . is_empty ( ) & & locale ! = " en " ) {
load_doc_translations ( locale ) ;
}
2017-09-12 22:42:36 +02:00
{
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : open ( doc_tool_path ) ;
ERR_FAIL_COND_V_MSG ( da . is_null ( ) , false , " Argument supplied to --doctool must be a valid directory path. " ) ;
2017-09-12 22:42:36 +02:00
}
2020-04-20 17:57:38 +02:00
2023-01-20 13:10:00 +01:00
# ifndef MODULE_MONO_ENABLED
// Hack to define .NET-specific project settings even on non-.NET builds,
// so that we don't lose their descriptions and default values in DocTools.
// Default values should be synced with mono_gd/gd_mono.cpp.
GLOBAL_DEF ( " dotnet/project/assembly_name " , " " ) ;
GLOBAL_DEF ( " dotnet/project/solution_directory " , " " ) ;
2023-03-31 11:53:16 +02:00
GLOBAL_DEF ( PropertyInfo ( Variant : : INT , " dotnet/project/assembly_reload_attempts " , PROPERTY_HINT_RANGE , " 1,16,1,or_greater " ) , 3 ) ;
2023-01-20 13:10:00 +01:00
# endif
2022-01-17 23:54:53 +01:00
Error err ;
2020-11-29 04:42:06 +01:00
DocTools doc ;
2023-10-31 18:27:17 +01:00
doc . generate ( gen_flags ) ;
2014-02-10 02:10:30 +01:00
2020-11-29 04:42:06 +01:00
DocTools docsrc ;
2022-05-13 15:04:37 +02:00
HashMap < String , String > doc_data_classes ;
2022-05-19 17:00:06 +02:00
HashSet < String > checked_paths ;
2018-04-22 19:36:01 +02:00
print_line ( " Loading docs... " ) ;
2017-09-12 22:42:36 +02:00
2017-09-13 09:13:23 +02:00
for ( int i = 0 ; i < _doc_data_class_path_count ; i + + ) {
2020-03-08 17:34:09 +01:00
// Custom modules are always located by absolute path.
String path = _doc_data_class_paths [ i ] . path ;
2021-08-30 01:43:47 +02:00
if ( path . is_relative_path ( ) ) {
2022-08-30 02:34:01 +02:00
path = doc_tool_path . path_join ( path ) ;
2020-03-08 17:34:09 +01:00
}
2017-09-12 22:42:36 +02:00
String name = _doc_data_class_paths [ i ] . name ;
2017-09-13 09:13:23 +02:00
doc_data_classes [ name ] = path ;
2017-09-12 22:42:36 +02:00
if ( ! checked_paths . has ( path ) ) {
checked_paths . insert ( path ) ;
2019-06-08 21:13:16 +02:00
// Create the module documentation directory if it doesn't exist
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create_for_path ( path ) ;
2022-01-17 23:54:53 +01:00
err = da - > make_dir_recursive ( path ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , false , " Error: Can't create directory: " + path + " : " + itos ( err ) ) ;
2019-06-08 21:13:16 +02:00
2017-09-13 09:13:23 +02:00
print_line ( " Loading docs from: " + path ) ;
2022-01-17 23:54:53 +01:00
err = docsrc . load_classes ( path ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , false , " Error loading docs from: " + path + " : " + itos ( err ) ) ;
2017-09-12 22:42:36 +02:00
}
2014-02-10 02:10:30 +01:00
}
2022-08-30 02:34:01 +02:00
String index_path = doc_tool_path . path_join ( " doc/classes " ) ;
2019-06-08 21:13:16 +02:00
// Create the main documentation directory if it doesn't exist
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create_for_path ( index_path ) ;
2022-01-17 23:54:53 +01:00
err = da - > make_dir_recursive ( index_path ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , false , " Error: Can't create index directory: " + index_path + " : " + itos ( err ) ) ;
2019-06-08 21:13:16 +02:00
2022-01-17 23:54:53 +01:00
print_line ( " Loading classes from: " + index_path ) ;
err = docsrc . load_classes ( index_path ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , false , " Error loading classes from: " + index_path + " : " + itos ( err ) ) ;
2017-09-12 22:42:36 +02:00
checked_paths . insert ( index_path ) ;
2018-04-22 19:36:01 +02:00
print_line ( " Merging docs... " ) ;
2017-09-12 22:42:36 +02:00
doc . merge_from ( docsrc ) ;
2022-01-17 23:54:53 +01:00
2022-05-19 01:43:40 +02:00
for ( const String & E : checked_paths ) {
print_line ( " Erasing old docs at: " + E ) ;
err = DocTools : : erase_classes ( E ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , false , " Error erasing old docs at: " + E + " : " + itos ( err ) ) ;
2016-12-16 12:12:22 +01:00
}
2018-04-22 19:36:01 +02:00
print_line ( " Generating new docs... " ) ;
2022-01-17 23:54:53 +01:00
err = doc . save_classes ( index_path , doc_data_classes ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , false , " Error saving new docs: " + itos ( err ) ) ;
2014-02-10 02:10:30 +01:00
2023-02-07 21:14:00 +01:00
print_line ( " Deleting docs cache... " ) ;
if ( FileAccess : : exists ( EditorHelp : : get_cache_full_path ( ) ) ) {
DirAccess : : remove_file_or_error ( EditorHelp : : get_cache_full_path ( ) ) ;
}
2022-01-17 23:54:53 +01:00
OS : : get_singleton ( ) - > set_exit_code ( EXIT_SUCCESS ) ;
2020-07-24 15:16:02 +02:00
return false ;
2014-02-10 02:10:30 +01:00
}
2021-06-19 17:58:49 +02:00
2023-12-04 16:43:00 +01:00
// GDExtension API and interface.
{
if ( dump_gdextension_interface ) {
GDExtensionInterfaceDump : : generate_gdextension_interface_file ( " gdextension_interface.h " ) ;
}
2022-10-12 16:21:34 +02:00
2023-12-04 16:43:00 +01:00
if ( dump_extension_api ) {
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 ) ;
}
2022-10-12 16:21:34 +02:00
2023-12-04 16:43:00 +01:00
if ( dump_gdextension_interface | | dump_extension_api ) {
OS : : get_singleton ( ) - > set_exit_code ( EXIT_SUCCESS ) ;
return false ;
}
2022-03-10 16:21:22 +01:00
2023-12-04 16:43:00 +01:00
if ( validate_extension_api ) {
Engine : : get_singleton ( ) - > set_editor_hint ( true ) ; // "extension_api.json" should always contains editor singletons.
bool valid = GDExtensionAPIDump : : validate_extension_json_file ( validate_extension_api_file ) = = OK ;
OS : : get_singleton ( ) - > set_exit_code ( valid ? EXIT_SUCCESS : EXIT_FAILURE ) ;
return false ;
}
Add a backwards-compatibility system for GDExtension method
This adds a way to ensure that methods that were modified in the Godot API will continue working in older builds of GDExtension even if the new signature is different.
```C++
// New version (changed)
ClassDB::bind_method(D_METHOD("add_sphere","radius","position"),&MyShapes::add_sphere);
// Compatibility version (still available to extensions).
ClassDB::bind_compatibility_method(D_METHOD("add_sphere","radius"),&MyShapes::_compat_add_sphere);
```
**Q**: If I add an extra argument and provide a default value (hence can still be called the same), do I still have to provide the compatibility version?
**A**: Yes, you must still provide a compatibility method. Most language bindings use the raw method pointer to do the call and process the default parameters in the binding language, hence if the actual method signature changes it will no longer work.
**Q**: If I removed a method, can I still bind a compatibility version even though the main method no longer exists?
**A**: Yes, for methods that were removed or renamed, compatibility versions can still be provided.
**Q**: Would it be possible to automate checking that methods were removed by mistake?
**A**: Yes, as part of a future PR, the idea is to add a a command line option to Godot that can be run like : `$ godot --test-api-compatibility older_api_dump.json`, which will also be integrated to the CI runs.
2023-04-25 20:53:07 +02:00
}
2023-02-01 22:29:33 +01:00
# ifndef DISABLE_DEPRECATED
2022-03-10 16:21:22 +01:00
if ( converting_project ) {
2023-02-10 09:07:01 +01:00
int ret = ProjectConverter3To4 ( converter_max_kb_file , converter_max_line_length ) . convert ( ) ;
if ( ret ) {
OS : : get_singleton ( ) - > set_exit_code ( EXIT_SUCCESS ) ;
}
2022-03-10 16:21:22 +01:00
return false ;
}
if ( validating_converting_project ) {
2023-02-10 09:07:01 +01:00
bool ret = ProjectConverter3To4 ( converter_max_kb_file , converter_max_line_length ) . validate_conversion ( ) ;
if ( ret ) {
OS : : get_singleton ( ) - > set_exit_code ( EXIT_SUCCESS ) ;
}
2022-03-10 16:21:22 +01:00
return false ;
}
2023-02-01 22:29:33 +01:00
# endif // DISABLE_DEPRECATED
2022-03-10 16:21:22 +01:00
2023-02-10 09:07:01 +01:00
# endif // TOOLS_ENABLED
2015-11-26 21:59:25 +01:00
2021-12-09 10:42:46 +01:00
if ( script . is_empty ( ) & & game_path . is_empty ( ) & & String ( GLOBAL_GET ( " application/run/main_scene " ) ) ! = " " ) {
2021-02-17 17:44:49 +01:00
game_path = GLOBAL_GET ( " application/run/main_scene " ) ;
2014-02-10 02:10:30 +01:00
}
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
# ifdef TOOLS_ENABLED
2021-12-09 10:42:46 +01:00
if ( ! editor & & ! project_manager & & ! cmdline_tool & & script . is_empty ( ) & & game_path . is_empty ( ) ) {
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
// If we end up here, it means we didn't manage to detect what we want to run.
// Let's throw an error gently. The code leading to this is pretty brittle so
// this might end up triggered by valid usage, in which case we'll have to
// fine-tune further.
2021-07-22 18:23:48 +02:00
OS : : get_singleton ( ) - > alert ( " Couldn't detect whether to run the editor, the project manager or a specific project. Aborting. " ) ;
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
ERR_FAIL_V_MSG ( false , " Couldn't detect whether to run the editor, the project manager or a specific project. Aborting. " ) ;
}
# endif
2020-04-02 01:20:12 +02:00
MainLoop * main_loop = nullptr ;
2014-02-10 02:10:30 +01:00
if ( editor ) {
2014-11-06 01:20:42 +01:00
main_loop = memnew ( SceneTree ) ;
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
}
2023-06-13 17:43:17 +02:00
if ( main_loop_type . is_empty ( ) ) {
main_loop_type = GLOBAL_GET ( " application/run/main_loop_type " ) ;
}
2014-02-10 02:10:30 +01:00
2021-12-09 10:42:46 +01:00
if ( ! script . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
Ref < Script > script_res = ResourceLoader : : load ( script ) ;
2019-08-08 22:08:27 +02:00
ERR_FAIL_COND_V_MSG ( script_res . is_null ( ) , false , " Can't load script: " + script ) ;
2016-03-09 00:00:52 +01:00
2018-05-31 00:23:23 +02:00
if ( check_only ) {
2019-11-25 22:39:51 +01:00
if ( ! script_res - > is_valid ( ) ) {
2020-06-04 22:03:45 +02:00
OS : : get_singleton ( ) - > set_exit_code ( EXIT_FAILURE ) ;
2021-10-21 20:34:43 +02:00
} else {
OS : : get_singleton ( ) - > set_exit_code ( EXIT_SUCCESS ) ;
2019-11-25 22:39:51 +01:00
}
2020-07-24 15:16:02 +02:00
return false ;
2018-05-31 00:23:23 +02:00
}
2021-06-18 00:03:09 +02:00
if ( script_res - > can_instantiate ( ) ) {
2017-03-05 16:44:50 +01:00
StringName instance_type = script_res - > get_instance_base_type ( ) ;
2021-06-18 00:03:09 +02:00
Object * obj = ClassDB : : instantiate ( instance_type ) ;
2017-08-24 22:58:51 +02:00
MainLoop * script_loop = Object : : cast_to < MainLoop > ( obj ) ;
2014-02-10 02:10:30 +01:00
if ( ! script_loop ) {
2020-05-14 16:41:43 +02:00
if ( obj ) {
2014-02-10 02:10:30 +01:00
memdelete ( obj ) ;
2020-05-14 16:41:43 +02:00
}
2021-07-22 18:23:48 +02:00
OS : : get_singleton ( ) - > alert ( vformat ( " Can't load the script \" %s \" as it doesn't inherit from SceneTree or MainLoop. " , script ) ) ;
ERR_FAIL_V_MSG ( false , vformat ( " Can't load the script \" %s \" as it doesn't inherit from SceneTree or MainLoop. " , script ) ) ;
2014-02-10 02:10:30 +01:00
}
2022-12-31 14:46:55 +01:00
script_loop - > set_script ( script_res ) ;
2017-03-05 16:44:50 +01:00
main_loop = script_loop ;
2014-02-10 02:10:30 +01:00
} else {
2020-07-24 15:16:02 +02:00
return false ;
2014-02-10 02:10:30 +01:00
}
2020-08-11 19:20:30 +02:00
} else { // Not based on script path.
if ( ! editor & & ! ClassDB : : class_exists ( main_loop_type ) & & ScriptServer : : is_global_class ( main_loop_type ) ) {
String script_path = ScriptServer : : get_global_class_path ( main_loop_type ) ;
Ref < Script > script_res = ResourceLoader : : load ( script_path ) ;
2022-11-25 11:21:15 +01:00
if ( script_res . is_null ( ) ) {
OS : : get_singleton ( ) - > alert ( " Error: Could not load MainLoop script type: " + main_loop_type ) ;
ERR_FAIL_V_MSG ( false , vformat ( " Could not load global class %s. " , main_loop_type ) ) ;
}
StringName script_base = script_res - > get_instance_base_type ( ) ;
2021-06-18 00:03:09 +02:00
Object * obj = ClassDB : : instantiate ( script_base ) ;
2020-08-11 19:20:30 +02:00
MainLoop * script_loop = Object : : cast_to < MainLoop > ( obj ) ;
if ( ! script_loop ) {
if ( obj ) {
memdelete ( obj ) ;
}
2021-07-22 18:23:48 +02:00
OS : : get_singleton ( ) - > alert ( " Error: Invalid MainLoop script base type: " + script_base ) ;
2020-08-11 19:20:30 +02:00
ERR_FAIL_V_MSG ( false , vformat ( " The global class %s does not inherit from SceneTree or MainLoop. " , main_loop_type ) ) ;
}
2022-12-31 14:46:55 +01:00
script_loop - > set_script ( script_res ) ;
2020-08-11 19:20:30 +02:00
main_loop = script_loop ;
}
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2021-12-09 10:42:46 +01:00
if ( ! main_loop & & main_loop_type . is_empty ( ) ) {
2017-03-05 16:44:50 +01:00
main_loop_type = " SceneTree " ;
2020-05-14 16:41:43 +02:00
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( ! main_loop ) {
2017-01-03 03:03:46 +01:00
if ( ! ClassDB : : class_exists ( main_loop_type ) ) {
2021-07-22 18:23:48 +02:00
OS : : get_singleton ( ) - > alert ( " Error: MainLoop type doesn't exist: " + main_loop_type ) ;
2020-07-24 15:16:02 +02:00
return false ;
2014-02-10 02:10:30 +01:00
} else {
2021-06-18 00:03:09 +02:00
Object * ml = ClassDB : : instantiate ( main_loop_type ) ;
2023-09-09 17:52:40 +02:00
ERR_FAIL_NULL_V_MSG ( ml , false , " Can't instance MainLoop type. " ) ;
2014-02-10 02:10:30 +01:00
2017-08-24 22:58:51 +02:00
main_loop = Object : : cast_to < MainLoop > ( ml ) ;
2014-02-10 02:10:30 +01:00
if ( ! main_loop ) {
memdelete ( ml ) ;
2019-08-08 22:08:27 +02:00
ERR_FAIL_V_MSG ( false , " Invalid MainLoop type. " ) ;
2014-02-10 02:10:30 +01:00
}
}
}
2022-12-31 14:46:55 +01:00
OS : : get_singleton ( ) - > set_main_loop ( main_loop ) ;
2022-02-06 14:12:19 +01:00
SceneTree * sml = Object : : cast_to < SceneTree > ( main_loop ) ;
if ( sml ) {
2017-04-07 16:17:16 +02:00
# ifdef DEBUG_ENABLED
2015-09-19 04:10:58 +02:00
if ( debug_collisions ) {
sml - > set_debug_collisions_hint ( true ) ;
}
2022-06-15 23:24:06 +02:00
if ( debug_paths ) {
sml - > set_debug_paths_hint ( true ) ;
}
2015-09-20 18:03:46 +02:00
if ( debug_navigation ) {
sml - > set_debug_navigation_hint ( true ) ;
2023-06-16 17:01:06 +02:00
NavigationServer3D : : get_singleton ( ) - > set_debug_navigation_enabled ( true ) ;
2023-01-10 07:14:16 +01:00
}
if ( debug_avoidance ) {
2023-06-16 17:01:06 +02:00
NavigationServer3D : : get_singleton ( ) - > set_debug_avoidance_enabled ( true ) ;
2023-01-10 07:14:16 +01:00
}
if ( debug_navigation | | debug_avoidance ) {
2022-07-01 18:58:03 +02:00
NavigationServer3D : : get_singleton ( ) - > set_active ( true ) ;
2022-12-21 23:21:43 +01:00
NavigationServer3D : : get_singleton ( ) - > set_debug_enabled ( true ) ;
2015-09-20 18:03:46 +02:00
}
2023-07-07 19:35:54 +02:00
if ( debug_canvas_item_redraw ) {
RenderingServer : : get_singleton ( ) - > canvas_item_set_debug_redraw ( true ) ;
}
2017-04-07 16:17:16 +02:00
# endif
2023-04-10 18:45:53 +02:00
if ( single_threaded_scene ) {
sml - > set_disable_node_threading ( true ) ;
}
2023-03-10 15:09:56 +01:00
bool embed_subwindows = GLOBAL_GET ( " display/window/subwindows/embed_subwindows " ) ;
2020-03-28 21:56:50 +01:00
2022-08-13 21:52:03 +02:00
if ( single_window | | ( ! project_manager & & ! editor & & embed_subwindows ) | | ! DisplayServer : : get_singleton ( ) - > has_feature ( DisplayServer : : Feature : : FEATURE_SUBWINDOWS ) ) {
2022-03-13 16:18:44 +01:00
sml - > get_root ( ) - > set_embedding_subwindows ( true ) ;
2020-03-14 17:06:39 +01:00
}
2021-06-25 15:45:16 +02:00
2018-06-11 02:59:53 +02:00
ResourceLoader : : add_custom_loaders ( ) ;
ResourceSaver : : add_custom_savers ( ) ;
2018-05-22 18:26:13 +02:00
if ( ! project_manager & & ! editor ) { // game
2021-12-09 10:42:46 +01:00
if ( ! game_path . is_empty ( ) | | ! script . is_empty ( ) ) {
2018-05-01 16:06:23 +02:00
//autoload
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Load Autoloads " ) ;
2022-05-08 10:09:19 +02:00
HashMap < StringName , ProjectSettings : : AutoloadInfo > autoloads = ProjectSettings : : get_singleton ( ) - > get_autoload_list ( ) ;
2018-05-01 16:06:23 +02:00
//first pass, add the constants so they exist before any script is loaded
2022-05-08 10:09:19 +02:00
for ( const KeyValue < StringName , ProjectSettings : : AutoloadInfo > & E : autoloads ) {
const ProjectSettings : : AutoloadInfo & info = E . value ;
2018-05-01 16:06:23 +02:00
2020-06-18 01:45:08 +02:00
if ( info . is_singleton ) {
2018-05-01 16:06:23 +02:00
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
2020-06-18 01:45:08 +02:00
ScriptServer : : get_language ( i ) - > add_global_constant ( info . name , Variant ( ) ) ;
2018-05-01 16:06:23 +02:00
}
}
}
//second pass, load into global constants
List < Node * > to_add ;
2022-05-08 10:09:19 +02:00
for ( const KeyValue < StringName , ProjectSettings : : AutoloadInfo > & E : autoloads ) {
const ProjectSettings : : AutoloadInfo & info = E . value ;
2018-05-01 16:06:23 +02:00
2020-04-02 01:20:12 +02:00
Node * n = nullptr ;
2022-11-24 00:13:13 +01:00
if ( ResourceLoader : : get_resource_type ( info . path ) = = " PackedScene " ) {
// Cache the scene reference before loading it (for cyclic references)
Ref < PackedScene > scn ;
scn . instantiate ( ) ;
scn - > set_path ( info . path ) ;
scn - > reload_from_file ( ) ;
2023-11-23 16:19:24 +01:00
ERR_CONTINUE_MSG ( ! scn . is_valid ( ) , vformat ( " Failed to instantiate an autoload, can't load from path: %s. " , info . path ) ) ;
2022-11-24 00:13:13 +01:00
if ( scn . is_valid ( ) ) {
n = scn - > instantiate ( ) ;
}
} else {
Ref < Resource > res = ResourceLoader : : load ( info . path ) ;
2023-11-23 16:19:24 +01:00
ERR_CONTINUE_MSG ( res . is_null ( ) , vformat ( " Failed to instantiate an autoload, can't load from path: %s. " , info . path ) ) ;
2022-11-24 00:13:13 +01:00
Ref < Script > script_res = res ;
if ( script_res . is_valid ( ) ) {
StringName ibt = script_res - > get_instance_base_type ( ) ;
bool valid_type = ClassDB : : is_parent_class ( ibt , " Node " ) ;
2023-11-23 16:19:24 +01:00
ERR_CONTINUE_MSG ( ! valid_type , vformat ( " Failed to instantiate an autoload, script '%s' does not inherit from 'Node'. " , info . path ) ) ;
2018-05-01 16:06:23 +02:00
2022-11-24 00:13:13 +01:00
Object * obj = ClassDB : : instantiate ( ibt ) ;
2023-11-23 16:19:24 +01:00
ERR_CONTINUE_MSG ( ! obj , vformat ( " Failed to instantiate an autoload, cannot instantiate '%s'. " , ibt ) ) ;
2018-05-01 16:06:23 +02:00
2022-11-24 00:13:13 +01:00
n = Object : : cast_to < Node > ( obj ) ;
n - > set_script ( script_res ) ;
}
2018-05-01 16:06:23 +02:00
}
2023-11-23 16:19:24 +01:00
ERR_CONTINUE_MSG ( ! n , vformat ( " Failed to instantiate an autoload, path is not pointing to a scene or a script: %s. " , info . path ) ) ;
2020-06-18 01:45:08 +02:00
n - > set_name ( info . name ) ;
2018-05-01 16:06:23 +02:00
//defer so references are all valid on _ready()
to_add . push_back ( n ) ;
2020-06-18 01:45:08 +02:00
if ( info . is_singleton ) {
2018-05-01 16:06:23 +02:00
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
2020-06-18 01:45:08 +02:00
ScriptServer : : get_language ( i ) - > add_global_constant ( info . name , n ) ;
2018-05-01 16:06:23 +02:00
}
}
}
2021-07-16 05:45:57 +02:00
for ( Node * E : to_add ) {
sml - > get_root ( ) - > add_child ( E ) ;
2018-05-01 16:06:23 +02:00
}
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Load Autoloads " ) ;
2018-05-01 16:06:23 +02:00
}
}
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
2023-09-22 14:37:12 +02:00
# 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
2020-04-02 01:20:12 +02:00
EditorNode * editor_node = nullptr ;
2014-02-10 02:10:30 +01:00
if ( editor ) {
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Editor " ) ;
2017-03-05 16:44:50 +01:00
editor_node = memnew ( EditorNode ) ;
2014-02-10 02:10:30 +01:00
sml - > get_root ( ) - > add_child ( editor_node ) ;
2021-12-09 10:42:46 +01:00
if ( ! _export_preset . is_empty ( ) ) {
2023-12-06 05:35:52 +01:00
editor_node - > export_preset ( _export_preset , positional_arg , export_debug , export_pack_only , install_android_build_template ) ;
2020-01-07 13:29:02 +01:00
game_path = " " ; // Do not load anything.
2014-02-10 02:10:30 +01:00
}
2022-08-19 14:21:43 +02:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Editor " ) ;
2014-02-10 02:10:30 +01:00
}
# endif
2023-03-10 15:09:56 +01:00
sml - > set_auto_accept_quit ( GLOBAL_GET ( " application/config/auto_accept_quit " ) ) ;
sml - > set_quit_on_go_back ( GLOBAL_GET ( " application/config/quit_on_go_back " ) ) ;
2014-02-10 02:10:30 +01:00
2018-02-19 13:31:06 +01:00
if ( ! editor & & ! project_manager ) {
2014-02-10 02:10:30 +01:00
//standard helpers that can be changed from main config
2022-10-20 15:43:17 +02:00
String stretch_mode = GLOBAL_GET ( " display/window/stretch/mode " ) ;
String stretch_aspect = GLOBAL_GET ( " display/window/stretch/aspect " ) ;
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 " ) ;
2023-04-06 23:41:27 +02:00
String stretch_scale_mode = GLOBAL_GET ( " display/window/stretch/scale_mode " ) ;
2014-04-15 03:43:44 +02:00
2020-03-04 02:51:12 +01:00
Window : : ContentScaleMode cs_sm = Window : : CONTENT_SCALE_MODE_DISABLED ;
2020-07-02 22:15:11 +02:00
if ( stretch_mode = = " canvas_items " ) {
cs_sm = Window : : CONTENT_SCALE_MODE_CANVAS_ITEMS ;
} else if ( stretch_mode = = " viewport " ) {
cs_sm = Window : : CONTENT_SCALE_MODE_VIEWPORT ;
2020-05-14 16:41:43 +02:00
}
2014-04-15 03:43:44 +02:00
2020-03-04 02:51:12 +01:00
Window : : ContentScaleAspect cs_aspect = Window : : CONTENT_SCALE_ASPECT_IGNORE ;
2020-05-14 16:41:43 +02:00
if ( stretch_aspect = = " keep " ) {
2020-03-04 02:51:12 +01:00
cs_aspect = Window : : CONTENT_SCALE_ASPECT_KEEP ;
2020-05-14 16:41:43 +02:00
} else if ( stretch_aspect = = " keep_width " ) {
2020-03-04 02:51:12 +01:00
cs_aspect = Window : : CONTENT_SCALE_ASPECT_KEEP_WIDTH ;
2020-05-14 16:41:43 +02:00
} else if ( stretch_aspect = = " keep_height " ) {
2020-03-04 02:51:12 +01:00
cs_aspect = Window : : CONTENT_SCALE_ASPECT_KEEP_HEIGHT ;
2020-05-14 16:41:43 +02:00
} else if ( stretch_aspect = = " expand " ) {
2020-03-04 02:51:12 +01:00
cs_aspect = Window : : CONTENT_SCALE_ASPECT_EXPAND ;
2020-05-14 16:41:43 +02:00
}
2014-04-15 03:43:44 +02:00
2023-04-06 23:41:27 +02:00
Window : : ContentScaleStretch cs_stretch = Window : : CONTENT_SCALE_STRETCH_FRACTIONAL ;
if ( stretch_scale_mode = = " integer " ) {
cs_stretch = Window : : CONTENT_SCALE_STRETCH_INTEGER ;
}
2020-03-04 02:51:12 +01:00
sml - > get_root ( ) - > set_content_scale_mode ( cs_sm ) ;
sml - > get_root ( ) - > set_content_scale_aspect ( cs_aspect ) ;
2023-04-06 23:41:27 +02:00
sml - > get_root ( ) - > set_content_scale_stretch ( cs_stretch ) ;
2020-03-04 02:51:12 +01:00
sml - > get_root ( ) - > set_content_scale_size ( stretch_size ) ;
2021-12-17 13:11:19 +01:00
sml - > get_root ( ) - > set_content_scale_factor ( stretch_scale ) ;
2014-02-10 02:10:30 +01:00
2022-10-20 15:43:17 +02:00
sml - > set_auto_accept_quit ( GLOBAL_GET ( " application/config/auto_accept_quit " ) ) ;
sml - > set_quit_on_go_back ( GLOBAL_GET ( " application/config/quit_on_go_back " ) ) ;
2022-10-18 16:43:37 +02:00
String appname = GLOBAL_GET ( " application/config/name " ) ;
2014-02-10 02:10:30 +01:00
appname = TranslationServer : : get_singleton ( ) - > translate ( appname ) ;
2020-06-16 11:27:46 +02:00
# ifdef DEBUG_ENABLED
// Append a suffix to the window title to denote that the project is running
// from a debug build (including the editor). Since this results in lower performance,
// this should be clearly presented to the user.
DisplayServer : : get_singleton ( ) - > window_set_title ( vformat ( " %s (DEBUG) " , appname ) ) ;
# else
2020-03-03 14:36:29 +01:00
DisplayServer : : get_singleton ( ) - > window_set_title ( appname ) ;
2020-06-16 11:27:46 +02:00
# endif
2014-02-10 02:10:30 +01:00
2022-10-20 15:43:17 +02:00
bool snap_controls = GLOBAL_GET ( " gui/common/snap_controls_to_pixels " ) ;
2017-09-07 16:22:07 +02:00
sml - > get_root ( ) - > set_snap_controls_to_pixels ( snap_controls ) ;
2022-10-20 15:43:17 +02:00
bool font_oversampling = GLOBAL_GET ( " gui/fonts/dynamic_fonts/use_oversampling " ) ;
2020-03-04 02:51:12 +01:00
sml - > get_root ( ) - > set_use_font_oversampling ( font_oversampling ) ;
2017-12-19 22:48:30 +01:00
2022-10-20 15:43:17 +02:00
int texture_filter = GLOBAL_GET ( " rendering/textures/canvas_textures/default_texture_filter " ) ;
int texture_repeat = GLOBAL_GET ( " rendering/textures/canvas_textures/default_texture_repeat " ) ;
2020-07-20 18:35:34 +02:00
sml - > get_root ( ) - > set_default_canvas_item_texture_filter (
Viewport : : DefaultCanvasItemTextureFilter ( texture_filter ) ) ;
sml - > get_root ( ) - > set_default_canvas_item_texture_repeat (
Viewport : : DefaultCanvasItemTextureRepeat ( texture_repeat ) ) ;
2014-02-10 02:10:30 +01:00
}
2020-05-22 01:55:28 +02:00
# ifdef TOOLS_ENABLED
if ( editor ) {
2020-07-20 18:35:34 +02:00
bool editor_embed_subwindows = EditorSettings : : get_singleton ( ) - > get_setting (
" interface/editor/single_window_mode " ) ;
2020-05-22 01:55:28 +02:00
if ( editor_embed_subwindows ) {
2022-03-13 16:18:44 +01:00
sml - > get_root ( ) - > set_embedding_subwindows ( true ) ;
2020-05-22 01:55:28 +02:00
}
}
# endif
2016-09-06 18:45:35 +02:00
String local_game_path ;
2021-12-09 10:42:46 +01:00
if ( ! game_path . is_empty ( ) & & ! project_manager ) {
2017-03-05 16:44:50 +01:00
local_game_path = game_path . replace ( " \\ " , " / " ) ;
2014-02-10 02:10:30 +01:00
if ( ! local_game_path . begins_with ( " res:// " ) ) {
2020-07-20 18:35:34 +02:00
bool absolute =
( local_game_path . size ( ) > 1 ) & & ( local_game_path [ 0 ] = = ' / ' | | local_game_path [ 1 ] = = ' : ' ) ;
2014-02-10 02:10:30 +01:00
if ( ! absolute ) {
2017-07-19 22:00:46 +02:00
if ( ProjectSettings : : get_singleton ( ) - > is_using_datapack ( ) ) {
2017-03-05 16:44:50 +01:00
local_game_path = " res:// " + local_game_path ;
2014-02-10 02:10:30 +01:00
2014-02-19 15:57:14 +01:00
} else {
2020-07-03 15:26:22 +02:00
int sep = local_game_path . rfind ( " / " ) ;
2014-02-19 15:57:14 +01:00
2017-03-05 16:44:50 +01:00
if ( sep = = - 1 ) {
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2023-09-26 04:07:43 +02:00
ERR_FAIL_COND_V ( da . is_null ( ) , false ) ;
2022-08-30 02:34:01 +02:00
local_game_path = da - > get_current_dir ( ) . path_join ( local_game_path ) ;
2014-02-19 15:57:14 +01:00
} else {
2022-03-23 10:08:58 +01:00
Ref < DirAccess > da = DirAccess : : open ( local_game_path . substr ( 0 , sep ) ) ;
if ( da . is_valid ( ) ) {
2022-08-30 02:34:01 +02:00
local_game_path = da - > get_current_dir ( ) . path_join (
2020-07-20 18:35:34 +02:00
local_game_path . substr ( sep + 1 , local_game_path . length ( ) ) ) ;
2014-02-19 15:57:14 +01:00
}
2014-02-10 02:10:30 +01:00
}
}
}
}
2017-07-19 22:00:46 +02:00
local_game_path = ProjectSettings : : get_singleton ( ) - > localize_path ( local_game_path ) ;
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
if ( editor ) {
2020-11-05 03:01:55 +01:00
if ( game_path ! = String ( GLOBAL_GET ( " application/run/main_scene " ) ) | | ! editor_node - > has_scenes_in_session ( ) ) {
2018-09-21 05:14:04 +02:00
Error serr = editor_node - > load_scene ( local_game_path ) ;
2020-05-14 16:41:43 +02:00
if ( serr ! = OK ) {
2018-09-21 05:14:04 +02:00
ERR_PRINT ( " Failed to load scene " ) ;
2020-05-14 16:41:43 +02:00
}
2018-09-21 05:14:04 +02:00
}
2020-03-03 14:36:29 +01:00
DisplayServer : : get_singleton ( ) - > set_context ( DisplayServer : : CONTEXT_EDITOR ) ;
2021-08-29 01:58:15 +02:00
if ( ! debug_server_uri . is_empty ( ) ) {
EditorDebuggerNode : : get_singleton ( ) - > start ( debug_server_uri ) ;
2022-11-24 22:03:29 +01:00
EditorDebuggerNode : : get_singleton ( ) - > set_keep_open ( true ) ;
2021-08-29 01:58:15 +02:00
}
2016-09-06 18:45:35 +02:00
}
2014-02-10 02:10:30 +01:00
# endif
2018-10-05 22:18:10 +02:00
if ( ! editor ) {
2020-03-03 14:36:29 +01:00
DisplayServer : : get_singleton ( ) - > set_context ( DisplayServer : : CONTEXT_ENGINE ) ;
2018-10-05 22:18:10 +02:00
}
2016-09-06 18:45:35 +02:00
}
2014-02-10 02:10:30 +01:00
2018-02-19 13:31:06 +01:00
if ( ! project_manager & & ! editor ) { // game
2018-09-15 14:45:54 +02:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Load Game " ) ;
2022-08-19 14:21:43 +02:00
2019-08-08 22:08:27 +02:00
// Load SSL Certificates from Project Settings (or builtin).
2022-10-20 15:43:17 +02:00
Crypto : : load_default_certificates ( GLOBAL_GET ( " network/tls/certificate_bundle_override " ) ) ;
2018-09-15 14:45:54 +02:00
2021-12-09 10:42:46 +01:00
if ( ! game_path . is_empty ( ) ) {
2020-04-02 01:20:12 +02:00
Node * scene = nullptr ;
2014-02-10 02:10:30 +01:00
Ref < PackedScene > scenedata = ResourceLoader : : load ( local_game_path ) ;
2020-05-14 16:41:43 +02:00
if ( scenedata . is_valid ( ) ) {
2021-06-18 00:03:09 +02:00
scene = scenedata - > instantiate ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-09-09 17:52:40 +02:00
ERR_FAIL_NULL_V_MSG ( scene , false , " Failed loading scene: " + local_game_path + " . " ) ;
2015-05-17 21:33:35 +02:00
sml - > add_current_scene ( scene ) ;
2014-02-10 02:10:30 +01:00
2022-07-20 08:28:22 +02:00
# ifdef MACOS_ENABLED
2023-04-05 02:05:37 +02:00
String mac_icon_path = GLOBAL_GET ( " application/config/macos_native_icon " ) ;
if ( ! mac_icon_path . is_empty ( ) ) {
DisplayServer : : get_singleton ( ) - > set_native_icon ( mac_icon_path ) ;
has_icon = true ;
2019-05-17 15:43:56 +02:00
}
# endif
# ifdef WINDOWS_ENABLED
2023-04-05 02:05:37 +02:00
String win_icon_path = GLOBAL_GET ( " application/config/windows_native_icon " ) ;
if ( ! win_icon_path . is_empty ( ) ) {
DisplayServer : : get_singleton ( ) - > set_native_icon ( win_icon_path ) ;
has_icon = true ;
2019-05-17 15:43:56 +02:00
}
# endif
2023-04-05 02:05:37 +02:00
String icon_path = GLOBAL_GET ( " application/config/icon " ) ;
if ( ( ! icon_path . is_empty ( ) ) & & ( ! has_icon ) ) {
2017-05-17 12:36:47 +02:00
Ref < Image > icon ;
2021-06-18 00:03:09 +02:00
icon . instantiate ( ) ;
2023-04-05 02:05:37 +02:00
if ( ImageLoader : : load_image ( icon_path , icon ) = = OK ) {
2020-03-03 14:36:29 +01:00
DisplayServer : : get_singleton ( ) - > set_icon ( icon ) ;
2023-04-05 02:05:37 +02:00
has_icon = true ;
2017-09-15 18:41:11 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2022-08-19 14:21:43 +02:00
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Load Game " ) ;
2014-02-10 02:10:30 +01:00
}
# ifdef TOOLS_ENABLED
Main: Fixup bogus fallback to project manager with more bolognese
WARNING: Hacks everywhere!
The logic in `main.cpp` is due a full rewrite as it's extremely hacky,
splitting argument parsing over several functions, with a mess of global state
and assumptions about what combinations of arguments or lack thereof should
mean in terms of what we want to read: game, editor, project manager, or
command line tools such as `--doctool`, `--export` or `--script`.
Until this is fully rewritten, this patch hacks things some more to ensure
that we don't fall back to the project manager in cases where it's not
warranted, and especially not *too late*, as it can mean that we haven't
properly initialized stuff like `EditorPaths` needed by the PM (which in turn
impacts what kind of path will be used for logs and the shader cache, etc...
the rabbit hole goes deep).
Fixes #41435.
Fixes #49392.
Fixes #49658.
Fixes https://github.com/godotengine/godot/issues/38202#issuecomment-773158477.
2021-06-16 19:08:29 +02:00
if ( project_manager ) {
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Startup " , " Project Manager " ) ;
2018-09-10 14:53:31 +02:00
Engine : : get_singleton ( ) - > set_editor_hint ( true ) ;
2017-03-05 16:44:50 +01:00
ProjectManager * pmanager = memnew ( ProjectManager ) ;
ProgressDialog * progress_dialog = memnew ( ProgressDialog ) ;
2016-07-10 22:19:19 +02:00
pmanager - > add_child ( progress_dialog ) ;
2014-02-10 02:10:30 +01:00
sml - > get_root ( ) - > add_child ( pmanager ) ;
2020-03-03 14:36:29 +01:00
DisplayServer : : get_singleton ( ) - > set_context ( DisplayServer : : CONTEXT_PROJECTMAN ) ;
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Project Manager " ) ;
2014-02-10 02:10:30 +01:00
}
2018-09-15 14:45:54 +02:00
if ( project_manager | | editor ) {
2019-07-19 15:29:57 +02:00
// Load SSL Certificates from Editor Settings (or builtin)
2021-06-09 10:47:32 +02:00
Crypto : : load_default_certificates (
2022-09-07 08:25:47 +02:00
EditorSettings : : get_singleton ( ) - > get_setting ( " network/tls/editor_tls_certificates " ) . operator String ( ) ) ;
2019-07-19 15:29:57 +02:00
}
2014-02-10 02:10:30 +01:00
# endif
}
2023-04-05 02:05:37 +02:00
if ( ! has_icon & & OS : : get_singleton ( ) - > get_bundle_icon_path ( ) . is_empty ( ) ) {
2017-09-15 18:41:11 +02:00
Ref < Image > icon = memnew ( Image ( app_icon_png ) ) ;
2020-03-03 14:36:29 +01:00
DisplayServer : : get_singleton ( ) - > set_icon ( icon ) ;
2017-09-15 18:41:11 +02:00
}
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
if ( movie_writer ) {
2022-06-26 01:38:20 +02:00
movie_writer - > begin ( DisplayServer : : get_singleton ( ) - > window_get_size ( ) , fixed_fps , Engine : : get_singleton ( ) - > get_write_movie_path ( ) ) ;
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
}
2022-06-28 17:13:00 +02:00
if ( minimum_time_msec ) {
uint64_t minimum_time = 1000 * minimum_time_msec ;
uint64_t elapsed_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
if ( elapsed_time < minimum_time ) {
OS : : get_singleton ( ) - > delay_usec ( minimum_time - elapsed_time ) ;
}
}
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Startup " , " Total " ) ;
2023-01-13 20:24:12 +01:00
OS : : get_singleton ( ) - > benchmark_dump ( ) ;
2022-08-19 14:21:43 +02:00
2020-07-24 15:16:02 +02:00
return true ;
2014-02-10 02:10:30 +01:00
}
2018-09-20 11:45:05 +02:00
/* Main iteration
*
* This is the iteration of the engine ' s game loop , advancing the state of physics ,
* rendering and audio .
* It ' s called directly by the platform ' s OS : : run method , where the loop is created
* and monitored .
*
* The OS implementation can impact its draw step with the Main : : force_redraw ( ) method .
*/
2017-03-05 16:44:50 +01:00
uint64_t Main : : last_ticks = 0 ;
2018-05-28 13:47:09 +02:00
uint32_t Main : : frames = 0 ;
2022-04-12 00:23:22 +02:00
uint32_t Main : : hide_print_fps_attempts = 3 ;
2017-03-05 16:44:50 +01:00
uint32_t Main : : frame = 0 ;
2014-02-10 02:10:30 +01:00
bool Main : : force_redraw_requested = false ;
2019-01-24 17:09:05 +01:00
int Main : : iterating = 0 ;
2020-09-21 01:35:20 +02:00
bool Main : : agile_input_event_flushing = false ;
2020-07-20 18:35:34 +02:00
2019-01-22 17:17:39 +01:00
bool Main : : is_iterating ( ) {
2019-01-24 17:09:05 +01:00
return iterating > 0 ;
2019-01-22 17:17:39 +01:00
}
2014-02-10 02:10:30 +01:00
2019-08-08 22:08:27 +02:00
// For performance metrics.
2017-09-30 16:19:07 +02:00
static uint64_t physics_process_max = 0 ;
2020-12-22 10:50:29 +01:00
static uint64_t process_max = 0 ;
2022-12-30 05:19:15 +01:00
static uint64_t navigation_process_max = 0 ;
2014-02-10 02:10:30 +01:00
bool Main : : iteration ( ) {
2019-01-24 16:42:05 +01:00
//for now do not error on this
//ERR_FAIL_COND_V(iterating, false);
2019-01-22 17:17:39 +01:00
2019-01-24 17:09:05 +01:00
iterating + + ;
2019-01-22 17:17:39 +01:00
2021-09-08 06:25:35 +02:00
const uint64_t ticks = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2017-07-15 06:23:10 +02:00
Engine : : get_singleton ( ) - > _frame_ticks = ticks ;
2018-05-15 22:12:35 +02:00
main_timer_sync . set_cpu_ticks_usec ( ticks ) ;
main_timer_sync . set_fixed_fps ( fixed_fps ) ;
2017-07-15 06:23:10 +02:00
2021-09-08 06:25:35 +02:00
const uint64_t ticks_elapsed = ticks - last_ticks ;
2014-02-10 02:10:30 +01:00
2021-09-08 06:25:35 +02:00
const int physics_ticks_per_second = Engine : : get_singleton ( ) - > get_physics_ticks_per_second ( ) ;
const double physics_step = 1.0 / physics_ticks_per_second ;
2017-08-30 12:40:35 +02:00
2021-09-08 06:25:35 +02:00
const double time_scale = Engine : : get_singleton ( ) - > get_time_scale ( ) ;
2018-05-09 08:11:43 +02:00
2021-08-11 02:35:16 +02:00
MainFrameTime advance = main_timer_sync . advance ( physics_step , physics_ticks_per_second ) ;
2020-12-22 10:50:29 +01:00
double process_step = advance . process_step ;
double scaled_step = process_step * time_scale ;
2015-04-15 03:05:14 +02:00
2020-12-22 10:50:29 +01:00
Engine : : get_singleton ( ) - > _process_step = process_step ;
2019-07-01 18:42:02 +02:00
Engine : : get_singleton ( ) - > _physics_interpolation_fraction = advance . interpolation_fraction ;
2017-07-15 06:23:10 +02:00
2017-09-30 16:19:07 +02:00
uint64_t physics_process_ticks = 0 ;
2020-12-22 10:50:29 +01:00
uint64_t process_ticks = 0 ;
2022-12-30 05:19:15 +01:00
uint64_t navigation_process_ticks = 0 ;
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
frame + = ticks_elapsed ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
last_ticks = ticks ;
2014-02-10 02:10:30 +01:00
2022-09-15 18:57:34 +02:00
const int max_physics_steps = Engine : : get_singleton ( ) - > get_max_physics_steps_per_frame ( ) ;
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
if ( fixed_fps = = - 1 & & advance . physics_steps > max_physics_steps ) {
2020-12-22 10:50:29 +01:00
process_step - = ( advance . physics_steps - max_physics_steps ) * physics_step ;
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
advance . physics_steps = max_physics_steps ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
bool exit = false ;
2014-02-10 02:10:30 +01:00
2021-08-29 08:05:11 +02:00
// process all our active interfaces
XRServer : : get_singleton ( ) - > _process ( ) ;
2023-08-17 18:32:30 +02:00
NavigationServer2D : : get_singleton ( ) - > sync ( ) ;
NavigationServer3D : : get_singleton ( ) - > sync ( ) ;
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
for ( int iters = 0 ; iters < advance . physics_steps ; + + iters ) {
2020-09-21 01:35:20 +02:00
if ( Input : : get_singleton ( ) - > is_using_input_buffering ( ) & & agile_input_event_flushing ) {
Input : : get_singleton ( ) - > flush_buffered_events ( ) ;
}
Engine : : get_singleton ( ) - > _in_physics = true ;
2017-10-21 16:28:08 +02:00
uint64_t physics_begin = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2014-02-10 02:10:30 +01:00
2021-02-09 17:19:03 +01:00
PhysicsServer3D : : get_singleton ( ) - > sync ( ) ;
2020-03-27 19:21:27 +01:00
PhysicsServer3D : : get_singleton ( ) - > flush_queries ( ) ;
2014-02-10 02:10:30 +01:00
2020-03-27 19:21:27 +01:00
PhysicsServer2D : : get_singleton ( ) - > sync ( ) ;
PhysicsServer2D : : get_singleton ( ) - > flush_queries ( ) ;
2014-02-10 02:10:30 +01:00
2020-12-22 10:50:29 +01:00
if ( OS : : get_singleton ( ) - > get_main_loop ( ) - > physics_process ( physics_step * time_scale ) ) {
2023-01-17 14:04:19 +01:00
PhysicsServer3D : : get_singleton ( ) - > end_sync ( ) ;
PhysicsServer2D : : get_singleton ( ) - > end_sync ( ) ;
2017-03-05 16:44:50 +01:00
exit = true ;
2014-02-10 02:10:30 +01:00
break ;
}
2022-12-30 05:19:15 +01:00
uint64_t navigation_begin = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
NavigationServer3D : : get_singleton ( ) - > process ( physics_step * time_scale ) ;
navigation_process_ticks = MAX ( navigation_process_ticks , OS : : get_singleton ( ) - > get_ticks_usec ( ) - navigation_begin ) ; // keep the largest one for reference
navigation_process_max = MAX ( OS : : get_singleton ( ) - > get_ticks_usec ( ) - navigation_begin , navigation_process_max ) ;
2014-02-10 02:10:30 +01:00
2020-02-26 09:42:51 +01:00
message_queue - > flush ( ) ;
2020-01-10 12:22:34 +01:00
2021-02-09 17:19:03 +01:00
PhysicsServer3D : : get_singleton ( ) - > end_sync ( ) ;
2020-12-22 10:50:29 +01:00
PhysicsServer3D : : get_singleton ( ) - > step ( physics_step * time_scale ) ;
2015-05-26 06:05:08 +02:00
2020-03-27 19:21:27 +01:00
PhysicsServer2D : : get_singleton ( ) - > end_sync ( ) ;
2020-12-22 10:50:29 +01:00
PhysicsServer2D : : get_singleton ( ) - > step ( physics_step * time_scale ) ;
2014-02-10 02:10:30 +01:00
message_queue - > flush ( ) ;
2020-12-22 10:50:29 +01:00
physics_process_ticks = MAX ( physics_process_ticks , OS : : get_singleton ( ) - > get_ticks_usec ( ) - physics_begin ) ; // keep the largest one for reference
2017-10-21 16:28:08 +02:00
physics_process_max = MAX ( OS : : get_singleton ( ) - > get_ticks_usec ( ) - physics_begin , physics_process_max ) ;
2017-09-30 16:19:07 +02:00
Engine : : get_singleton ( ) - > _physics_frames + + ;
2020-09-21 01:35:20 +02:00
Engine : : get_singleton ( ) - > _in_physics = false ;
2014-02-10 02:10:30 +01:00
}
2020-09-21 01:35:20 +02:00
if ( Input : : get_singleton ( ) - > is_using_input_buffering ( ) & & agile_input_event_flushing ) {
Input : : get_singleton ( ) - > flush_buffered_events ( ) ;
}
2016-09-01 23:58:52 +02:00
2020-12-22 10:50:29 +01:00
uint64_t process_begin = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2014-02-10 02:10:30 +01:00
2020-12-22 10:50:29 +01:00
if ( OS : : get_singleton ( ) - > get_main_loop ( ) - > process ( process_step * time_scale ) ) {
2019-03-09 12:36:37 +01:00
exit = true ;
}
2014-02-10 02:10:30 +01:00
message_queue - > flush ( ) ;
2020-03-27 19:21:27 +01:00
RenderingServer : : get_singleton ( ) - > sync ( ) ; //sync if still drawing from previous frames.
2015-06-07 03:06:58 +02:00
2020-07-20 18:35:34 +02:00
if ( DisplayServer : : get_singleton ( ) - > can_any_window_draw ( ) & &
RenderingServer : : get_singleton ( ) - > is_render_loop_enabled ( ) ) {
2014-02-10 02:10:30 +01:00
if ( ( ! force_redraw_requested ) & & OS : : get_singleton ( ) - > is_in_low_processor_usage_mode ( ) ) {
2020-03-27 19:21:27 +01:00
if ( RenderingServer : : get_singleton ( ) - > has_changed ( ) ) {
RenderingServer : : get_singleton ( ) - > draw ( true , scaled_step ) ; // flush visual commands
2017-01-13 16:51:14 +01:00
Engine : : get_singleton ( ) - > frames_drawn + + ;
2014-02-10 02:10:30 +01:00
}
} else {
2020-03-27 19:21:27 +01:00
RenderingServer : : get_singleton ( ) - > draw ( true , scaled_step ) ; // flush visual commands
2017-01-13 16:51:14 +01:00
Engine : : get_singleton ( ) - > frames_drawn + + ;
2014-02-10 02:10:30 +01:00
force_redraw_requested = false ;
}
}
2020-12-22 10:50:29 +01:00
process_ticks = OS : : get_singleton ( ) - > get_ticks_usec ( ) - process_begin ;
process_max = MAX ( process_ticks , process_max ) ;
2016-05-22 02:18:16 +02:00
uint64_t frame_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) - ticks ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
ScriptServer : : get_language ( i ) - > frame ( ) ;
}
2018-06-21 02:02:02 +02:00
AudioServer : : get_singleton ( ) - > update ( ) ;
2020-05-14 16:41:43 +02:00
if ( EngineDebugger : : is_active ( ) ) {
2020-12-22 10:50:29 +01:00
EngineDebugger : : get_singleton ( ) - > iteration ( frame_time , process_ticks , physics_process_ticks , physics_step ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2018-05-28 13:47:09 +02:00
frames + + ;
2020-12-22 10:50:29 +01:00
Engine : : get_singleton ( ) - > _process_frames + + ;
2014-02-10 02:10:30 +01:00
2018-05-28 13:47:09 +02:00
if ( frame > 1000000 ) {
2022-04-12 00:23:22 +02:00
// Wait a few seconds before printing FPS, as FPS reporting just after the engine has started is inaccurate.
if ( hide_print_fps_attempts = = 0 ) {
if ( editor | | project_manager ) {
if ( print_fps ) {
print_line ( vformat ( " Editor FPS: %d (%s mspf) " , frames , rtos ( 1000.0 / frames ) . pad_decimals ( 2 ) ) ) ;
}
} else if ( print_fps | | GLOBAL_GET ( " debug/settings/stdout/print_fps " ) ) {
print_line ( vformat ( " Project FPS: %d (%s mspf) " , frames , rtos ( 1000.0 / frames ) . pad_decimals ( 2 ) ) ) ;
2018-03-21 08:46:05 +01:00
}
2022-04-12 00:23:22 +02:00
} else {
hide_print_fps_attempts - - ;
2018-03-21 08:46:05 +01:00
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Engine : : get_singleton ( ) - > _fps = frames ;
2020-12-22 10:50:29 +01:00
performance - > set_process_time ( USEC_TO_SEC ( process_max ) ) ;
2017-09-30 16:19:07 +02:00
performance - > set_physics_process_time ( USEC_TO_SEC ( physics_process_max ) ) ;
2022-12-30 05:19:15 +01:00
performance - > set_navigation_process_time ( USEC_TO_SEC ( navigation_process_max ) ) ;
2020-12-22 10:50:29 +01:00
process_max = 0 ;
2017-09-30 16:19:07 +02:00
physics_process_max = 0 ;
2022-12-30 05:19:15 +01:00
navigation_process_max = 0 ;
2014-02-10 02:10:30 +01:00
2018-05-28 13:47:09 +02:00
frame % = 1000000 ;
frames = 0 ;
2014-02-10 02:10:30 +01:00
}
2019-01-24 17:09:05 +01:00
iterating - - ;
2019-01-22 17:17:39 +01:00
2021-08-13 00:38:41 +02:00
// Needed for OSs using input buffering regardless accumulation (like Android)
2020-09-21 01:35:20 +02:00
if ( Input : : get_singleton ( ) - > is_using_input_buffering ( ) & & ! agile_input_event_flushing ) {
2021-08-13 00:38:41 +02:00
Input : : get_singleton ( ) - > flush_buffered_events ( ) ;
}
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
if ( movie_writer ) {
2023-04-30 20:55:29 +02:00
movie_writer - > add_frame ( ) ;
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
}
2023-02-20 08:44:33 +01:00
if ( ( quit_after > 0 ) & & ( Engine : : get_singleton ( ) - > _process_frames > = quit_after ) ) {
exit = true ;
}
2020-05-14 16:41:43 +02:00
if ( fixed_fps ! = - 1 ) {
2017-08-30 12:40:35 +02:00
return exit ;
2020-05-14 16:41:43 +02:00
}
2017-08-30 12:40:35 +02:00
2020-06-29 20:46:21 +02:00
OS : : get_singleton ( ) - > add_frame_delay ( DisplayServer : : get_singleton ( ) - > window_can_draw ( ) ) ;
2014-02-19 16:35:39 +01:00
2018-02-14 16:23:04 +01:00
# ifdef TOOLS_ENABLED
if ( auto_build_solutions ) {
auto_build_solutions = false ;
2020-01-13 13:55:54 +01:00
// Only relevant when running the editor.
if ( ! editor ) {
2022-10-28 22:59:25 +02:00
OS : : get_singleton ( ) - > set_exit_code ( EXIT_FAILURE ) ;
2020-07-20 18:35:34 +02:00
ERR_FAIL_V_MSG ( true ,
" Command line option --build-solutions was passed, but no project is being edited. Aborting. " ) ;
2020-01-13 13:55:54 +01:00
}
2018-02-14 16:23:04 +01:00
if ( ! EditorNode : : get_singleton ( ) - > call_build ( ) ) {
2022-10-28 22:59:25 +02:00
OS : : get_singleton ( ) - > set_exit_code ( EXIT_FAILURE ) ;
2020-07-20 18:35:34 +02:00
ERR_FAIL_V_MSG ( true ,
" Command line option --build-solutions was passed, but the build callback failed. Aborting. " ) ;
2018-02-14 16:23:04 +01:00
}
}
# endif
2023-02-20 08:44:33 +01:00
return exit ;
2014-02-10 02:10:30 +01:00
}
void Main : : force_redraw ( ) {
force_redraw_requested = true ;
2018-09-20 11:45:05 +02:00
}
/* Engine deinitialization
*
* Responsible for freeing all the memory allocated by previous setup steps ,
* so that the engine closes cleanly without leaking memory or crashing .
* The order matters as some of those steps are linked with each other .
*/
2021-02-22 11:06:33 +01:00
void Main : : cleanup ( bool p_force ) {
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_begin_measure ( " Shutdown " , " Total " ) ;
2021-02-22 11:06:33 +01:00
if ( ! p_force ) {
ERR_FAIL_COND ( ! _start_success ) ;
}
2014-02-10 02:10:30 +01:00
2022-11-21 14:04:01 +01:00
for ( int i = 0 ; i < TextServerManager : : get_singleton ( ) - > get_interface_count ( ) ; i + + ) {
TextServerManager : : get_singleton ( ) - > get_interface ( i ) - > cleanup ( ) ;
}
Implement Running Godot as Movie Writer
* Allows running the game in "movie writer" mode.
* It ensures entirely stable framerate, so your run can be saved stable and with proper sound (which is impossible if your CPU/GPU can't sustain doing this in real-time).
* If disabling vsync, it can save movies faster than the game is run, but if you want to control the interaction it can get difficult.
* Implements a simple, default MJPEG writer.
This new features has two main use cases, which have high demand:
* Saving game videos in high quality and ensuring the frame rate is *completely* stable, always.
* Using Godot as a tool to make movies and animations (which is ideal if you want interaction, or creating them procedurally. No other software is as good for this).
**Note**: This feature **IS NOT** for capturing real-time footage. Use something like OBS, SimpleScreenRecorder or FRAPS to achieve that, as they do a much better job at intercepting the compositor than Godot can probably do using Vulkan or OpenGL natively. If your game runs near real-time when capturing, you can still use this feature but it will play no sound (sound will be saved directly).
Usage:
$ godot --write-movie movie.avi [scene_file.tscn]
Missing:
* Options for configuring video writing via GLOBAL_DEF
* UI Menu for launching with this mode from the editor.
* Add to list of command line options.
* Add a feature tag to override configurations when movie writing (fantastic for saving videos with highest quality settings).
2022-06-17 00:55:19 +02:00
if ( movie_writer ) {
movie_writer - > end ( ) ;
}
2023-03-05 01:09:18 +01:00
ResourceLoader : : clear_thread_load_tasks ( ) ;
2018-06-11 02:59:53 +02:00
ResourceLoader : : remove_custom_loaders ( ) ;
ResourceSaver : : remove_custom_savers ( ) ;
2020-06-24 16:57:37 +02:00
// Flush before uninitializing the scene, but delete the MessageQueue as late as possible.
2018-01-14 13:50:52 +01:00
message_queue - > flush ( ) ;
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > delete_main_loop ( ) ;
OS : : get_singleton ( ) - > _cmdline . clear ( ) ;
2022-07-29 15:30:52 +02:00
OS : : get_singleton ( ) - > _user_args . clear ( ) ;
2017-03-05 16:44:50 +01:00
OS : : get_singleton ( ) - > _execpath = " " ;
OS : : get_singleton ( ) - > _local_clipboard = " " ;
2014-02-10 02:10:30 +01:00
2017-12-14 19:33:54 +01:00
ResourceLoader : : clear_translation_remaps ( ) ;
ResourceLoader : : clear_path_remaps ( ) ;
2017-07-22 21:11:04 +02:00
ScriptServer : : finish_languages ( ) ;
2017-01-15 20:06:14 +01:00
2020-01-13 21:46:41 +01:00
// Sync pending commands that may have been queued from a different thread during ScriptServer finalization
2020-03-27 19:21:27 +01:00
RenderingServer : : get_singleton ( ) - > sync ( ) ;
2020-01-13 21:46:41 +01:00
2021-03-12 14:35:16 +01:00
//clear global shader variables before scene and other graphics stuff are deinitialized.
2022-08-27 11:22:43 +02:00
rendering_server - > global_shader_parameters_clear ( ) ;
2020-04-17 04:52:00 +02:00
2020-04-08 16:47:36 +02:00
if ( xr_server ) {
2021-09-28 04:15:00 +02:00
// Now that we're unregistering properly in plugins we need to keep access to xr_server for a little longer
// We do however unset our primary interface
xr_server - > set_primary_interface ( Ref < XRInterface > ( ) ) ;
2017-10-07 15:51:17 +02:00
}
2021-09-11 04:08:12 +02:00
# ifdef TOOLS_ENABLED
2022-12-07 12:11:28 +01:00
GDExtensionManager : : get_singleton ( ) - > deinitialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_EDITOR ) ;
2022-05-03 11:56:08 +02:00
uninitialize_modules ( MODULE_INITIALIZATION_LEVEL_EDITOR ) ;
2022-05-01 11:57:36 +02:00
unregister_editor_types ( ) ;
2022-05-03 11:56:08 +02:00
2021-09-11 04:08:12 +02:00
# endif
2018-09-03 06:36:35 +02:00
ImageLoader : : cleanup ( ) ;
2022-12-07 12:11:28 +01:00
GDExtensionManager : : get_singleton ( ) - > deinitialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_SCENE ) ;
2022-05-03 11:56:08 +02:00
uninitialize_modules ( MODULE_INITIALIZATION_LEVEL_SCENE ) ;
2017-11-16 01:33:48 +01:00
unregister_platform_apis ( ) ;
2022-02-28 14:50:43 +01:00
unregister_driver_types ( ) ;
2016-03-09 00:00:52 +01:00
unregister_scene_types ( ) ;
2022-05-03 11:56:08 +02:00
2022-08-08 18:29:36 +02:00
finalize_theme_db ( ) ;
2022-09-06 15:35:33 +02:00
// Before deinitializing server extensions, finalize servers which may be loaded as extensions.
2022-12-08 18:23:42 +01:00
finalize_navigation_server ( ) ;
2022-09-06 15:35:33 +02:00
finalize_physics ( ) ;
2022-12-07 12:11:28 +01:00
GDExtensionManager : : get_singleton ( ) - > deinitialize_extensions ( GDExtension : : INITIALIZATION_LEVEL_SERVERS ) ;
2022-05-03 11:56:08 +02:00
uninitialize_modules ( MODULE_INITIALIZATION_LEVEL_SERVERS ) ;
2014-02-10 02:10:30 +01:00
unregister_server_types ( ) ;
2022-02-06 02:29:08 +01:00
EngineDebugger : : deinitialize ( ) ;
2021-09-28 04:15:00 +02:00
if ( xr_server ) {
memdelete ( xr_server ) ;
}
2018-01-11 11:01:35 +01:00
if ( audio_server ) {
audio_server - > finish ( ) ;
memdelete ( audio_server ) ;
}
2019-11-29 07:54:39 +01:00
if ( camera_server ) {
memdelete ( camera_server ) ;
}
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > finalize ( ) ;
2020-03-03 14:36:29 +01:00
finalize_display ( ) ;
if ( input ) {
memdelete ( input ) ;
}
2016-03-09 00:00:52 +01:00
2020-05-14 16:41:43 +02:00
if ( packed_data ) {
2014-02-10 02:10:30 +01:00
memdelete ( packed_data ) ;
2020-05-14 16:41:43 +02:00
}
if ( performance ) {
2014-02-10 02:10:30 +01:00
memdelete ( performance ) ;
2020-05-14 16:41:43 +02:00
}
if ( input_map ) {
2014-02-10 02:10:30 +01:00
memdelete ( input_map ) ;
2020-05-14 16:41:43 +02:00
}
2021-05-24 13:54:05 +02:00
if ( time_singleton ) {
memdelete ( time_singleton ) ;
}
2020-05-14 16:41:43 +02:00
if ( translation_server ) {
2017-03-05 16:44:50 +01:00
memdelete ( translation_server ) ;
2020-05-14 16:41:43 +02:00
}
2021-08-27 23:19:51 +02:00
if ( tsman ) {
memdelete ( tsman ) ;
}
2022-09-06 15:35:33 +02:00
if ( physics_server_3d_manager ) {
memdelete ( physics_server_3d_manager ) ;
}
if ( physics_server_2d_manager ) {
memdelete ( physics_server_2d_manager ) ;
}
2020-05-14 16:41:43 +02:00
if ( globals ) {
2014-02-10 02:10:30 +01:00
memdelete ( globals ) ;
2020-05-14 16:41:43 +02:00
}
if ( engine ) {
2017-01-13 16:51:14 +01:00
memdelete ( engine ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2018-07-19 23:58:15 +02:00
if ( OS : : get_singleton ( ) - > is_restart_on_exit_set ( ) ) {
//attempt to restart with arguments
2018-07-20 08:37:10 +02:00
List < String > args = OS : : get_singleton ( ) - > get_restart_on_exit_arguments ( ) ;
2021-11-01 10:12:52 +01:00
OS : : get_singleton ( ) - > create_instance ( args ) ;
2018-07-19 23:58:15 +02:00
OS : : get_singleton ( ) - > set_restart_on_exit ( false , List < String > ( ) ) ; //clear list (uses memory)
}
2020-06-24 16:57:37 +02:00
// Now should be safe to delete MessageQueue (famous last words).
message_queue - > flush ( ) ;
memdelete ( message_queue ) ;
2014-02-10 02:10:30 +01:00
unregister_core_driver_types ( ) ;
2022-02-16 18:02:38 +01:00
unregister_core_extensions ( ) ;
2022-05-03 11:56:08 +02:00
uninitialize_modules ( MODULE_INITIALIZATION_LEVEL_CORE ) ;
2014-02-10 02:10:30 +01:00
unregister_core_types ( ) ;
2023-12-08 12:52:49 +01:00
OS : : get_singleton ( ) - > benchmark_end_measure ( " Shutdown " , " Total " ) ;
2023-01-13 20:24:12 +01:00
OS : : get_singleton ( ) - > benchmark_dump ( ) ;
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > finalize_core ( ) ;
}