Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/main/main.cpp
20852 views
1
/**************************************************************************/
2
/* main.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "main.h"
32
33
#include "core/config/project_settings.h"
34
#include "core/core_globals.h"
35
#include "core/crypto/crypto.h"
36
#include "core/debugger/engine_debugger.h"
37
#include "core/extension/extension_api_dump.h"
38
#include "core/extension/gdextension_interface_dump.gen.h"
39
#include "core/extension/gdextension_interface_header_generator.h"
40
#include "core/extension/gdextension_manager.h"
41
#include "core/input/input.h"
42
#include "core/input/input_map.h"
43
#include "core/io/dir_access.h"
44
#include "core/io/file_access_pack.h"
45
#include "core/io/file_access_zip.h"
46
#include "core/io/image.h"
47
#include "core/io/image_loader.h"
48
#include "core/io/ip.h"
49
#include "core/io/resource_loader.h"
50
#include "core/object/message_queue.h"
51
#include "core/object/script_language.h"
52
#include "core/os/os.h"
53
#include "core/os/time.h"
54
#include "core/profiling/profiling.h"
55
#include "core/register_core_types.h"
56
#include "core/string/translation_server.h"
57
#include "core/version.h"
58
#include "drivers/register_driver_types.h"
59
#include "main/app_icon.gen.h"
60
#include "main/main_timer_sync.h"
61
#include "main/performance.h"
62
#include "main/splash.gen.h"
63
#include "modules/register_module_types.h"
64
#include "platform/register_platform_apis.h"
65
#include "scene/main/scene_tree.h"
66
#include "scene/main/window.h"
67
#include "scene/property_list_helper.h"
68
#include "scene/register_scene_types.h"
69
#include "scene/resources/packed_scene.h"
70
#include "scene/theme/theme_db.h"
71
#include "servers/audio/audio_driver_dummy.h"
72
#include "servers/audio/audio_server.h"
73
#include "servers/camera/camera_server.h"
74
#include "servers/display/display_server.h"
75
#include "servers/movie_writer/movie_writer.h"
76
#include "servers/register_server_types.h"
77
#include "servers/rendering/rendering_server_default.h"
78
#include "servers/text/text_server.h"
79
#include "servers/text/text_server_dummy.h"
80
81
// 2D
82
#ifndef NAVIGATION_2D_DISABLED
83
#include "servers/navigation_2d/navigation_server_2d.h"
84
#include "servers/navigation_2d/navigation_server_2d_dummy.h"
85
#endif // NAVIGATION_2D_DISABLED
86
87
#ifndef PHYSICS_2D_DISABLED
88
#include "servers/physics_2d/physics_server_2d.h"
89
#include "servers/physics_2d/physics_server_2d_dummy.h"
90
#endif // PHYSICS_2D_DISABLED
91
92
// 3D
93
#ifndef NAVIGATION_3D_DISABLED
94
#include "servers/navigation_3d/navigation_server_3d.h"
95
#include "servers/navigation_3d/navigation_server_3d_dummy.h"
96
#endif // NAVIGATION_3D_DISABLED
97
98
#ifndef PHYSICS_3D_DISABLED
99
#include "servers/physics_3d/physics_server_3d.h"
100
#include "servers/physics_3d/physics_server_3d_dummy.h"
101
#endif // PHYSICS_3D_DISABLED
102
103
#ifndef XR_DISABLED
104
#include "servers/xr/xr_server.h"
105
#endif // XR_DISABLED
106
107
#ifdef TESTS_ENABLED
108
#include "tests/test_main.h"
109
#endif
110
111
#ifdef TOOLS_ENABLED
112
#include "editor/debugger/debug_adapter/debug_adapter_server.h"
113
#include "editor/debugger/editor_debugger_node.h"
114
#include "editor/doc/doc_data_class_path.gen.h"
115
#include "editor/doc/doc_tools.h"
116
#include "editor/doc/editor_help.h"
117
#include "editor/editor_node.h"
118
#include "editor/file_system/editor_file_system.h"
119
#include "editor/file_system/editor_paths.h"
120
#include "editor/gui/progress_dialog.h"
121
#include "editor/project_manager/project_manager.h"
122
#include "editor/register_editor_types.h"
123
#include "editor/settings/editor_settings.h"
124
#include "editor/translations/editor_translation.h"
125
126
#if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
127
#include "main/splash_editor.gen.h"
128
#endif
129
130
#ifndef DISABLE_DEPRECATED
131
#include "editor/project_upgrade/project_converter_3_to_4.h"
132
#endif // DISABLE_DEPRECATED
133
#endif // TOOLS_ENABLED
134
135
#if defined(STEAMAPI_ENABLED)
136
#include "main/steam_tracker.h"
137
#endif
138
139
#include "modules/modules_enabled.gen.h" // For mono.
140
141
#if defined(MODULE_MONO_ENABLED) && defined(TOOLS_ENABLED)
142
#include "modules/mono/editor/bindings_generator.h"
143
#endif
144
145
#ifdef MODULE_GDSCRIPT_ENABLED
146
#include "modules/gdscript/gdscript.h"
147
#if defined(TOOLS_ENABLED) && !defined(GDSCRIPT_NO_LSP)
148
#include "modules/gdscript/language_server/gdscript_language_server.h"
149
#endif // TOOLS_ENABLED && !GDSCRIPT_NO_LSP
150
#endif // MODULE_GDSCRIPT_ENABLED
151
152
/* Static members */
153
154
// Singletons
155
156
// Initialized in setup()
157
static Engine *engine = nullptr;
158
static ProjectSettings *globals = nullptr;
159
static Input *input = nullptr;
160
static InputMap *input_map = nullptr;
161
static TranslationServer *translation_server = nullptr;
162
static Performance *performance = nullptr;
163
static PackedData *packed_data = nullptr;
164
#ifdef MINIZIP_ENABLED
165
static ZipArchive *zip_packed_data = nullptr;
166
#endif
167
static MessageQueue *message_queue = nullptr;
168
169
#if defined(STEAMAPI_ENABLED)
170
static SteamTracker *steam_tracker = nullptr;
171
#endif
172
173
// Initialized in setup2()
174
static AudioServer *audio_server = nullptr;
175
static CameraServer *camera_server = nullptr;
176
static DisplayServer *display_server = nullptr;
177
static RenderingServer *rendering_server = nullptr;
178
static TextServerManager *tsman = nullptr;
179
static ThemeDB *theme_db = nullptr;
180
#ifndef PHYSICS_2D_DISABLED
181
static PhysicsServer2DManager *physics_server_2d_manager = nullptr;
182
static PhysicsServer2D *physics_server_2d = nullptr;
183
#endif // PHYSICS_2D_DISABLED
184
#ifndef PHYSICS_3D_DISABLED
185
static PhysicsServer3DManager *physics_server_3d_manager = nullptr;
186
static PhysicsServer3D *physics_server_3d = nullptr;
187
#endif // PHYSICS_3D_DISABLED
188
#ifndef XR_DISABLED
189
static XRServer *xr_server = nullptr;
190
#endif // XR_DISABLED
191
// We error out if setup2() doesn't turn this true
192
static bool _start_success = false;
193
194
// Drivers
195
196
String display_driver = "";
197
String tablet_driver = "";
198
String text_driver = "";
199
static int text_driver_idx = -1;
200
static int audio_driver_idx = -1;
201
202
// Engine config/tools
203
204
static DisplayServer::AccessibilityMode accessibility_mode = DisplayServer::AccessibilityMode::ACCESSIBILITY_AUTO;
205
static bool accessibility_mode_set = false;
206
static bool single_window = false;
207
static bool editor = false;
208
static bool project_manager = false;
209
static bool cmdline_tool = false;
210
static String locale;
211
static String log_file;
212
static bool show_help = false;
213
static uint64_t quit_after = 0;
214
static OS::ProcessID editor_pid = 0;
215
#ifdef TOOLS_ENABLED
216
static bool found_project = false;
217
static bool recovery_mode = false;
218
static bool auto_build_solutions = false;
219
static String debug_server_uri;
220
static bool wait_for_import = false;
221
static bool restore_editor_window_layout = true;
222
#ifndef DISABLE_DEPRECATED
223
static int converter_max_kb_file = 4 * 1024; // 4MB
224
static int converter_max_line_length = 100000;
225
#endif // DISABLE_DEPRECATED
226
227
HashMap<Main::CLIScope, Vector<String>> forwardable_cli_arguments;
228
#endif
229
static bool single_threaded_scene = false;
230
231
// Display
232
233
static DisplayServer::WindowMode window_mode = DisplayServer::WINDOW_MODE_WINDOWED;
234
static DisplayServer::ScreenOrientation window_orientation = DisplayServer::SCREEN_LANDSCAPE;
235
static DisplayServer::VSyncMode window_vsync_mode = DisplayServer::VSYNC_ENABLED;
236
static uint32_t window_flags = 0;
237
static Size2i window_size = Size2i(1152, 648);
238
239
static int init_screen = DisplayServer::SCREEN_PRIMARY;
240
static bool init_fullscreen = false;
241
static bool init_maximized = false;
242
static bool init_windowed = false;
243
static bool init_always_on_top = false;
244
static bool init_use_custom_pos = false;
245
static bool init_use_custom_screen = false;
246
static Vector2 init_custom_pos;
247
static int64_t init_embed_parent_window_id = 0;
248
#ifdef TOOLS_ENABLED
249
static bool init_display_scale_found = false;
250
static int init_display_scale = 0;
251
static bool init_custom_scale_found = false;
252
static float init_custom_scale = 1.0;
253
static bool init_expand_to_title = false;
254
static bool init_expand_to_title_found = false;
255
#endif
256
static bool use_custom_res = true;
257
static bool force_res = false;
258
259
// Debug
260
261
static bool use_debug_profiler = false;
262
#ifdef DEBUG_ENABLED
263
static bool debug_collisions = false;
264
static bool debug_paths = false;
265
static bool debug_navigation = false;
266
static bool debug_avoidance = false;
267
static bool debug_canvas_item_redraw = false;
268
static bool debug_mute_audio = false;
269
#endif
270
static int max_fps = -1;
271
static int frame_delay = 0;
272
static int audio_output_latency = 0;
273
static bool disable_render_loop = false;
274
static int fixed_fps = -1;
275
static MovieWriter *movie_writer = nullptr;
276
static bool disable_vsync = false;
277
static bool print_fps = false;
278
#ifdef TOOLS_ENABLED
279
static bool editor_pseudolocalization = false;
280
static bool dump_gdextension_interface = false;
281
static bool dump_gdextension_interface_header = false;
282
static bool dump_extension_api = false;
283
static bool include_docs_in_extension_api_dump = false;
284
static bool validate_extension_api = false;
285
static String validate_extension_api_file;
286
#endif
287
bool profile_gpu = false;
288
289
// Constants.
290
291
static const String NULL_DISPLAY_DRIVER("headless");
292
static const String EMBEDDED_DISPLAY_DRIVER("embedded");
293
static const String NULL_AUDIO_DRIVER("Dummy");
294
295
// The length of the longest column in the command-line help we should align to
296
// (excluding the 2-space left and right margins).
297
// Currently, this is `--export-release <preset> <path>`.
298
static const int OPTION_COLUMN_LENGTH = 32;
299
300
/* Helper methods */
301
302
bool Main::is_cmdline_tool() {
303
return cmdline_tool;
304
}
305
306
#ifdef TOOLS_ENABLED
307
const Vector<String> &Main::get_forwardable_cli_arguments(Main::CLIScope p_scope) {
308
return forwardable_cli_arguments[p_scope];
309
}
310
#endif
311
312
static String unescape_cmdline(const String &p_str) {
313
return p_str.replace("%20", " ");
314
}
315
316
static String get_full_version_string() {
317
String hash = String(GODOT_VERSION_HASH);
318
if (!hash.is_empty()) {
319
hash = "." + hash.left(9);
320
}
321
return String(GODOT_VERSION_FULL_BUILD) + hash;
322
}
323
324
#if defined(TOOLS_ENABLED) && defined(MODULE_GDSCRIPT_ENABLED)
325
static Vector<String> get_files_with_extension(const String &p_root, const String &p_extension) {
326
Vector<String> paths;
327
328
Ref<DirAccess> dir = DirAccess::open(p_root);
329
if (dir.is_valid()) {
330
dir->list_dir_begin();
331
String fn = dir->get_next();
332
while (!fn.is_empty()) {
333
if (!dir->current_is_hidden() && fn != "." && fn != "..") {
334
if (dir->current_is_dir()) {
335
paths.append_array(get_files_with_extension(p_root.path_join(fn), p_extension));
336
} else if (fn.get_extension() == p_extension) {
337
paths.append(p_root.path_join(fn));
338
}
339
}
340
fn = dir->get_next();
341
}
342
dir->list_dir_end();
343
}
344
345
return paths;
346
}
347
#endif
348
349
// FIXME: Could maybe be moved to have less code in main.cpp.
350
void initialize_physics() {
351
#ifndef PHYSICS_3D_DISABLED
352
/// 3D Physics Server
353
physics_server_3d = PhysicsServer3DManager::get_singleton()->new_server(
354
GLOBAL_GET(PhysicsServer3DManager::setting_property_name));
355
if (!physics_server_3d) {
356
// Physics server not found, Use the default physics
357
physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server();
358
}
359
360
// Fall back to dummy if no default server has been registered.
361
if (!physics_server_3d) {
362
WARN_PRINT(vformat("Falling back to dummy PhysicsServer3D; 3D physics functionality will be disabled. If this is intended, set the %s project setting to Dummy.", PhysicsServer3DManager::setting_property_name));
363
physics_server_3d = memnew(PhysicsServer3DDummy);
364
}
365
366
// Should be impossible, but make sure it's not null.
367
ERR_FAIL_NULL_MSG(physics_server_3d, "Failed to initialize PhysicsServer3D.");
368
physics_server_3d->init();
369
#endif // PHYSICS_3D_DISABLED
370
371
#ifndef PHYSICS_2D_DISABLED
372
// 2D Physics server
373
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_server(
374
GLOBAL_GET(PhysicsServer2DManager::get_singleton()->setting_property_name));
375
if (!physics_server_2d) {
376
// Physics server not found, Use the default physics
377
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
378
}
379
380
// Fall back to dummy if no default server has been registered.
381
if (!physics_server_2d) {
382
WARN_PRINT(vformat("Falling back to dummy PhysicsServer2D; 2D physics functionality will be disabled. If this is intended, set the %s project setting to Dummy.", PhysicsServer2DManager::setting_property_name));
383
physics_server_2d = memnew(PhysicsServer2DDummy);
384
}
385
386
// Should be impossible, but make sure it's not null.
387
ERR_FAIL_NULL_MSG(physics_server_2d, "Failed to initialize PhysicsServer2D.");
388
physics_server_2d->init();
389
#endif // PHYSICS_2D_DISABLED
390
}
391
392
void finalize_physics() {
393
#ifndef PHYSICS_3D_DISABLED
394
physics_server_3d->finish();
395
memdelete(physics_server_3d);
396
#endif // PHYSICS_3D_DISABLED
397
398
#ifndef PHYSICS_2D_DISABLED
399
physics_server_2d->finish();
400
memdelete(physics_server_2d);
401
#endif // PHYSICS_2D_DISABLED
402
}
403
404
void finalize_display() {
405
rendering_server->finish();
406
memdelete(rendering_server);
407
408
memdelete(display_server);
409
}
410
411
void initialize_theme_db() {
412
theme_db = memnew(ThemeDB);
413
}
414
415
void finalize_theme_db() {
416
memdelete(theme_db);
417
theme_db = nullptr;
418
}
419
420
//#define DEBUG_INIT
421
#ifdef DEBUG_INIT
422
#define MAIN_PRINT(m_txt) print_line(m_txt)
423
#else
424
#define MAIN_PRINT(m_txt)
425
#endif
426
427
void Main::print_header(bool p_rich) {
428
if (GODOT_VERSION_TIMESTAMP > 0) {
429
// Version timestamp available.
430
if (p_rich) {
431
Engine::get_singleton()->print_header_rich("\u001b[38;5;39m" + String(GODOT_VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " (" + Time::get_singleton()->get_datetime_string_from_unix_time(GODOT_VERSION_TIMESTAMP, true) + " UTC) - \u001b[4m" + String(GODOT_VERSION_WEBSITE));
432
} else {
433
Engine::get_singleton()->print_header(String(GODOT_VERSION_NAME) + " v" + get_full_version_string() + " (" + Time::get_singleton()->get_datetime_string_from_unix_time(GODOT_VERSION_TIMESTAMP, true) + " UTC) - " + String(GODOT_VERSION_WEBSITE));
434
}
435
} else {
436
if (p_rich) {
437
Engine::get_singleton()->print_header_rich("\u001b[38;5;39m" + String(GODOT_VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " - \u001b[4m" + String(GODOT_VERSION_WEBSITE));
438
} else {
439
Engine::get_singleton()->print_header(String(GODOT_VERSION_NAME) + " v" + get_full_version_string() + " - " + String(GODOT_VERSION_WEBSITE));
440
}
441
}
442
}
443
444
/**
445
* Prints a copyright notice in the command-line help with colored text. A newline is
446
* automatically added at the end.
447
*/
448
void Main::print_help_copyright(const char *p_notice) {
449
OS::get_singleton()->print("\u001b[90m%s\u001b[0m\n", p_notice);
450
}
451
452
/**
453
* Prints a title in the command-line help with colored text. A newline is
454
* automatically added at beginning and at the end.
455
*/
456
void Main::print_help_title(const char *p_title) {
457
OS::get_singleton()->print("\n\u001b[1;93m%s:\u001b[0m\n", p_title);
458
}
459
460
/**
461
* Returns the option string with required and optional arguments colored separately from the rest of the option.
462
* This color replacement must be done *after* calling `rpad()` for the length padding to be done correctly.
463
*/
464
String Main::format_help_option(const char *p_option) {
465
return (String(p_option)
466
.rpad(OPTION_COLUMN_LENGTH)
467
.replace("[", "\u001b[96m[")
468
.replace("]", "]\u001b[0m")
469
.replace("<", "\u001b[95m<")
470
.replace(">", ">\u001b[0m"));
471
}
472
473
/**
474
* Prints an option in the command-line help with colored text. No newline is
475
* added at the end. `p_availability` denotes which build types the argument is
476
* available in. Support in release export templates implies support in debug
477
* export templates and editor. Support in debug export templates implies
478
* support in editor.
479
*/
480
void Main::print_help_option(const char *p_option, const char *p_description, CLIOptionAvailability p_availability) {
481
const bool option_empty = (p_option && !p_option[0]);
482
if (!option_empty) {
483
const char *availability_badge = "";
484
switch (p_availability) {
485
case CLI_OPTION_AVAILABILITY_EDITOR:
486
availability_badge = "\u001b[1;91mE";
487
break;
488
case CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG:
489
availability_badge = "\u001b[1;94mD";
490
break;
491
case CLI_OPTION_AVAILABILITY_TEMPLATE_UNSAFE:
492
availability_badge = "\u001b[1;93mX";
493
break;
494
case CLI_OPTION_AVAILABILITY_TEMPLATE_RELEASE:
495
availability_badge = "\u001b[1;92mR";
496
break;
497
case CLI_OPTION_AVAILABILITY_HIDDEN:
498
// Use for multiline option names (but not when the option name is empty).
499
availability_badge = " ";
500
break;
501
}
502
OS::get_singleton()->print(
503
" \u001b[92m%s %s\u001b[0m %s",
504
format_help_option(p_option).utf8().ptr(),
505
availability_badge,
506
p_description);
507
} else {
508
// Make continuation lines for descriptions faint if the option name is empty.
509
OS::get_singleton()->print(
510
" \u001b[92m%s \u001b[0m \u001b[90m%s",
511
format_help_option(p_option).utf8().ptr(),
512
p_description);
513
}
514
}
515
516
void Main::print_help(const char *p_binary) {
517
print_header(true);
518
print_help_copyright("Free and open source software under the terms of the MIT license.");
519
print_help_copyright("(c) 2014-present Godot Engine contributors. (c) 2007-present Juan Linietsky, Ariel Manzur.");
520
521
print_help_title("Usage");
522
OS::get_singleton()->print(" %s \u001b[96m[options] [path to \"project.godot\" file]\u001b[0m\n", p_binary);
523
524
#if defined(TOOLS_ENABLED)
525
print_help_title("Option legend (this build = editor)");
526
#elif defined(DEBUG_ENABLED)
527
print_help_title("Option legend (this build = debug export template)");
528
#else
529
print_help_title("Option legend (this build = release export template)");
530
#endif
531
532
OS::get_singleton()->print(" \u001b[1;92mR\u001b[0m Available in editor builds, debug export templates and release export templates.\n");
533
#ifdef DEBUG_ENABLED
534
OS::get_singleton()->print(" \u001b[1;94mD\u001b[0m Available in editor builds and debug export templates only.\n");
535
#endif
536
#if defined(OVERRIDE_PATH_ENABLED)
537
OS::get_singleton()->print(" \u001b[1;93mX\u001b[0m Only available in editor builds, and export templates compiled with `disable_path_overrides=false`.\n");
538
#endif
539
#ifdef TOOLS_ENABLED
540
OS::get_singleton()->print(" \u001b[1;91mE\u001b[0m Only available in editor builds.\n");
541
#endif
542
543
print_help_title("General options");
544
print_help_option("-h, --help", "Display this help message.\n");
545
print_help_option("--version", "Display the version string.\n");
546
print_help_option("-v, --verbose", "Use verbose stdout mode.\n");
547
print_help_option("--quiet", "Quiet mode, silences stdout messages. Errors are still displayed.\n");
548
print_help_option("--no-header", "Do not print engine version and rendering driver/method header on startup.\n");
549
550
print_help_title("Run options");
551
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");
552
#ifdef TOOLS_ENABLED
553
print_help_option("-e, --editor", "Start the editor instead of running the scene.\n", CLI_OPTION_AVAILABILITY_EDITOR);
554
print_help_option("-p, --project-manager", "Start the project manager, even if a project is auto-detected.\n", CLI_OPTION_AVAILABILITY_EDITOR);
555
print_help_option("--recovery-mode", "Start the editor in recovery mode, which disables features that can typically cause startup crashes, such as tool scripts, editor plugins, GDExtension addons, and others.\n", CLI_OPTION_AVAILABILITY_EDITOR);
556
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);
557
print_help_option("--dap-port <port>", "Use the specified port for the GDScript Debug Adapter Protocol. Recommended port range [1024, 49151].\n", CLI_OPTION_AVAILABILITY_EDITOR);
558
#if defined(MODULE_GDSCRIPT_ENABLED) && !defined(GDSCRIPT_NO_LSP)
559
print_help_option("--lsp-port <port>", "Use the specified port for the GDScript Language Server Protocol. Recommended port range [1024, 49151].\n", CLI_OPTION_AVAILABILITY_EDITOR);
560
#endif // MODULE_GDSCRIPT_ENABLED && !GDSCRIPT_NO_LSP
561
#endif
562
print_help_option("--quit", "Quit after the first iteration.\n");
563
print_help_option("--quit-after <int>", "Quit after the given number of iterations. Set to 0 to disable.\n");
564
print_help_option("-l, --language <locale>", "Use a specific locale (<locale> being a two-letter code).\n");
565
#if defined(OVERRIDE_PATH_ENABLED)
566
print_help_option("--path <directory>", "Path to a project (<directory> must contain a \"project.godot\" file).\n", CLI_OPTION_AVAILABILITY_TEMPLATE_UNSAFE);
567
print_help_option("--scene <path>", "Path or UID of a scene in the project that should be started.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_UNSAFE);
568
print_help_option("--main-pack <file>", "Path to a pack (.pck) file to load.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_UNSAFE);
569
#endif // defined(OVERRIDE_PATH_ENABLED)
570
#ifdef DISABLE_DEPRECATED
571
print_help_option("--render-thread <mode>", "Render thread mode (\"safe\", \"separate\").\n");
572
#else
573
print_help_option("--render-thread <mode>", "Render thread mode (\"unsafe\" [deprecated], \"safe\", \"separate\").\n");
574
#endif // DISABLE_DEPRECATED
575
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
576
print_help_option("--remote-fs <address>", "Remote filesystem (<host/IP>[:<port>] address).\n", CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG);
577
print_help_option("--remote-fs-password <password>", "Password for remote filesystem.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG);
578
#endif // defined(DEBUG_ENABLED) || defined (TOOLS_ENABLED)
579
580
print_help_option("--audio-driver <driver>", "Audio driver [");
581
for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
582
if (i > 0) {
583
OS::get_singleton()->print(", ");
584
}
585
OS::get_singleton()->print("\"%s\"", AudioDriverManager::get_driver(i)->get_name());
586
}
587
OS::get_singleton()->print("].\n");
588
589
print_help_option("--display-driver <driver>", "Display driver (and rendering driver) [");
590
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
591
if (i > 0) {
592
OS::get_singleton()->print(", ");
593
}
594
OS::get_singleton()->print("\"%s\" (", DisplayServer::get_create_function_name(i));
595
Vector<String> rd = DisplayServer::get_create_function_rendering_drivers(i);
596
for (int j = 0; j < rd.size(); j++) {
597
if (j > 0) {
598
OS::get_singleton()->print(", ");
599
}
600
OS::get_singleton()->print("\"%s\"", rd[j].utf8().get_data());
601
}
602
OS::get_singleton()->print(")");
603
}
604
OS::get_singleton()->print("].\n");
605
print_help_option("--audio-output-latency <ms>", "Override audio output latency in milliseconds (default is 15 ms).\n");
606
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");
607
608
print_help_option("--rendering-method <renderer>", "Renderer name. Requires driver support.\n");
609
print_help_option("--rendering-driver <driver>", "Rendering driver (depends on display driver).\n");
610
print_help_option("--gpu-index <device_index>", "Use a specific GPU (run with --verbose to get a list of available devices).\n");
611
print_help_option("--text-driver <driver>", "Text driver (used for font rendering, bidirectional support and shaping).\n");
612
print_help_option("--tablet-driver <driver>", "Pen tablet input driver.\n");
613
print_help_option("--headless", "Enable headless mode (--display-driver headless --audio-driver Dummy). Useful for servers and with --script.\n");
614
print_help_option("--log-file <file>", "Write output/error log to the specified path instead of the default location defined by the project.\n");
615
print_help_option("", "<file> path should be absolute or relative to the project directory.\n");
616
print_help_option("--write-movie <file>", "Write a video to the specified path (usually with .avi or .png extension).\n");
617
print_help_option("", "--fixed-fps is forced when enabled, but it can be used to change movie FPS.\n");
618
print_help_option("", "--disable-vsync can speed up movie writing but makes interaction more difficult.\n");
619
print_help_option("", "--quit-after can be used to specify the number of frames to write.\n");
620
621
print_help_title("Display options");
622
print_help_option("-f, --fullscreen", "Request fullscreen mode.\n");
623
print_help_option("-m, --maximized", "Request a maximized window.\n");
624
print_help_option("-w, --windowed", "Request windowed mode.\n");
625
print_help_option("-t, --always-on-top", "Request an always-on-top window.\n");
626
print_help_option("--resolution <W>x<H>", "Request window resolution.\n");
627
print_help_option("--position <X>,<Y>", "Request window position.\n");
628
print_help_option("--screen <N>", "Request window screen.\n");
629
print_help_option("--single-window", "Use a single window (no separate subwindows).\n");
630
#ifndef _3D_DISABLED
631
print_help_option("--xr-mode <mode>", "Select XR (Extended Reality) mode [\"default\", \"off\", \"on\"].\n");
632
#endif
633
print_help_option("--wid <window_id>", "Request parented to window.\n");
634
print_help_option("--accessibility <mode>", "Select accessibility mode ['auto' (when screen reader is running, default), 'always', 'disabled'].\n");
635
636
print_help_title("Debug options");
637
print_help_option("-d, --debug", "Debug (local stdout debugger).\n");
638
print_help_option("-b, --breakpoints", "Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n");
639
print_help_option("--ignore-error-breaks", "If debugger is connected, prevents sending error breakpoints.\n");
640
print_help_option("--profiling", "Enable profiling in the script debugger.\n");
641
print_help_option("--gpu-profile", "Show a GPU profile of the tasks that took the most time during frame rendering.\n");
642
print_help_option("--gpu-validation", "Enable graphics API validation layers for debugging.\n");
643
#ifdef DEBUG_ENABLED
644
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);
645
#endif
646
print_help_option("--generate-spirv-debug-info", "Generate SPIR-V debug information (Vulkan only). This allows source-level shader debugging with RenderDoc.\n");
647
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
648
print_help_option("--extra-gpu-memory-tracking", "Enables additional memory tracking (see class reference for `RenderingDevice.get_driver_and_device_memory_report()` and linked methods). Currently only implemented for Vulkan. Enabling this feature may cause crashes on some systems due to buggy drivers or bugs in the Vulkan Loader. See https://github.com/godotengine/godot/issues/95967\n");
649
print_help_option("--accurate-breadcrumbs", "Force barriers between breadcrumbs. Useful for narrowing down a command causing GPU resets. Currently only implemented for Vulkan.\n");
650
#endif
651
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
652
print_help_option("--remote-debug <uri>", "Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");
653
#endif
654
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");
655
#ifdef DEBUG_ENABLED
656
print_help_option("--debug-collisions", "Show collision shapes when running the scene.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG);
657
print_help_option("--debug-paths", "Show path lines when running the scene.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG);
658
print_help_option("--debug-navigation", "Show navigation polygons when running the scene.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG);
659
print_help_option("--debug-avoidance", "Show navigation avoidance debug visuals when running the scene.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG);
660
print_help_option("--debug-stringnames", "Print all StringName allocations to stdout when the engine quits.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_DEBUG);
661
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);
662
663
#endif
664
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");
665
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");
666
print_help_option("--time-scale <scale>", "Force time scale (higher values are faster, 1.0 is normal speed).\n");
667
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");
668
print_help_option("--disable-render-loop", "Disable render loop so rendering only occurs when called explicitly from script.\n");
669
print_help_option("--disable-crash-handler", "Disable crash handler when supported by the platform code.\n");
670
print_help_option("--fixed-fps <fps>", "Force a fixed number of frames per second. This setting disables real-time synchronization.\n");
671
print_help_option("--delta-smoothing <enable>", "Enable or disable frame delta smoothing [\"enable\", \"disable\"].\n");
672
print_help_option("--print-fps", "Print the frames per second to the stdout.\n");
673
#ifdef TOOLS_ENABLED
674
print_help_option("--editor-pseudolocalization", "Enable pseudolocalization for the editor and the project manager.\n", CLI_OPTION_AVAILABILITY_EDITOR);
675
#endif
676
677
#if defined(OVERRIDE_PATH_ENABLED) || defined(TESTS_ENABLED)
678
print_help_title("Standalone tools");
679
#endif // defined(OVERRIDE_PATH_ENABLED) || defined(TESTS_ENABLED)
680
#if defined(OVERRIDE_PATH_ENABLED)
681
print_help_option("-s, --script <script>", "Run a script.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_UNSAFE);
682
print_help_option("--main-loop <main_loop_name>", "Run a MainLoop specified by its global class name.\n", CLI_OPTION_AVAILABILITY_TEMPLATE_UNSAFE);
683
print_help_option("--check-only", "Only parse for errors and quit (use with --script).\n", CLI_OPTION_AVAILABILITY_TEMPLATE_UNSAFE);
684
#endif // defined(OVERRIDE_PATH_ENABLED)
685
#ifdef TOOLS_ENABLED
686
print_help_option("--import", "Starts the editor, waits for any resources to be imported, and then quits.\n", CLI_OPTION_AVAILABILITY_EDITOR);
687
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);
688
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");
689
print_help_option("", "The target directory must exist.\n");
690
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);
691
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);
692
print_help_option("--export-patch <preset> <path>", "Export pack with changed files only. See --export-pack description for other considerations.\n", CLI_OPTION_AVAILABILITY_EDITOR);
693
print_help_option("--patches <paths>", "List of patches to use with --export-patch. The list is comma-separated.\n", CLI_OPTION_AVAILABILITY_EDITOR);
694
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);
695
#ifndef DISABLE_DEPRECATED
696
// Commands are long; split the description to a second line.
697
print_help_option("--convert-3to4 ", "\n", CLI_OPTION_AVAILABILITY_HIDDEN);
698
print_help_option(" [max_file_kb] [max_line_size]", "Converts project from Godot 3.x to Godot 4.x.\n", CLI_OPTION_AVAILABILITY_EDITOR);
699
print_help_option("--validate-conversion-3to4 ", "\n", CLI_OPTION_AVAILABILITY_HIDDEN);
700
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);
701
#endif // DISABLE_DEPRECATED
702
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);
703
print_help_option("--no-docbase", "Disallow dumping the base types (used with --doctool).\n", CLI_OPTION_AVAILABILITY_EDITOR);
704
print_help_option("--gdextension-docs", "Rather than dumping the engine API, generate API reference from all the GDExtensions loaded in the current project (used with --doctool).\n", CLI_OPTION_AVAILABILITY_EDITOR);
705
#ifdef MODULE_GDSCRIPT_ENABLED
706
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);
707
#endif
708
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);
709
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);
710
print_help_option("--dump-gdextension-interface-json", "Generate a JSON dump of the GDExtension interface named \"gdextension_interface.json\" in the current folder.\n", CLI_OPTION_AVAILABILITY_EDITOR);
711
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);
712
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);
713
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);
714
print_help_option("", "If incompatibilities or errors are detected, the exit code will be non-zero.\n");
715
print_help_option("--benchmark", "Benchmark the run time and print it to console.\n", CLI_OPTION_AVAILABILITY_EDITOR);
716
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);
717
#endif // TOOLS_ENABLED
718
#ifdef TESTS_ENABLED
719
print_help_option("--test [--help]", "Run unit tests. Use --test --help for more information.\n");
720
#endif // TESTS_ENABLED
721
OS::get_singleton()->print("\n");
722
}
723
724
#ifdef TESTS_ENABLED
725
// The order is the same as in `Main::setup()`, only core and some editor types
726
// are initialized here. This also combines `Main::setup2()` initialization.
727
Error Main::test_setup() {
728
Thread::make_main_thread();
729
set_current_thread_safe_for_nodes(true);
730
731
OS::get_singleton()->initialize();
732
733
engine = memnew(Engine);
734
735
register_core_types();
736
register_core_driver_types();
737
738
packed_data = memnew(PackedData);
739
740
globals = memnew(ProjectSettings);
741
742
register_core_settings(); // Here globals are present.
743
744
translation_server = memnew(TranslationServer);
745
tsman = memnew(TextServerManager);
746
747
if (tsman) {
748
Ref<TextServerDummy> ts;
749
ts.instantiate();
750
tsman->add_interface(ts);
751
}
752
753
#ifndef PHYSICS_3D_DISABLED
754
physics_server_3d_manager = memnew(PhysicsServer3DManager);
755
#endif // PHYSICS_3D_DISABLED
756
#ifndef PHYSICS_2D_DISABLED
757
physics_server_2d_manager = memnew(PhysicsServer2DManager);
758
#endif // PHYSICS_2D_DISABLED
759
760
#ifndef NAVIGATION_2D_DISABLED
761
NavigationServer2DManager::initialize_server_manager();
762
#endif // NAVIGATION_2D_DISABLED
763
#ifndef NAVIGATION_3D_DISABLED
764
NavigationServer3DManager::initialize_server_manager();
765
#endif // NAVIGATION_3D_DISABLED
766
767
// From `Main::setup2()`.
768
register_early_core_singletons();
769
initialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
770
register_core_extensions();
771
772
register_core_singletons();
773
774
/** INITIALIZE SERVERS **/
775
register_server_types();
776
#ifndef XR_DISABLED
777
XRServer::set_xr_mode(XRServer::XRMODE_OFF); // Skip in tests.
778
#endif // XR_DISABLED
779
initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
780
GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
781
782
translation_server->setup(); //register translations, load them, etc.
783
if (!locale.is_empty()) {
784
translation_server->set_locale(locale);
785
}
786
translation_server->load_project_translations(translation_server->get_main_domain());
787
ResourceLoader::load_translation_remaps(); //load remaps for resources
788
789
// Initialize ThemeDB early so that scene types can register their theme items.
790
// Default theme will be initialized later, after modules and ScriptServer are ready.
791
initialize_theme_db();
792
793
#ifndef NAVIGATION_3D_DISABLED
794
NavigationServer3DManager::initialize_server();
795
#endif // NAVIGATION_3D_DISABLED
796
#ifndef NAVIGATION_2D_DISABLED
797
NavigationServer2DManager::initialize_server();
798
#endif // NAVIGATION_2D_DISABLED
799
800
register_scene_types();
801
register_driver_types();
802
803
register_scene_singletons();
804
805
initialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE);
806
GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SCENE);
807
808
#ifdef TOOLS_ENABLED
809
ClassDB::set_current_api(ClassDB::API_EDITOR);
810
register_editor_types();
811
812
initialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR);
813
GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR);
814
815
ClassDB::set_current_api(ClassDB::API_CORE);
816
#endif
817
register_platform_apis();
818
819
// Theme needs modules to be initialized so that sub-resources can be loaded.
820
theme_db->initialize_theme_noproject();
821
822
ERR_FAIL_COND_V(TextServerManager::get_singleton()->get_interface_count() == 0, ERR_CANT_CREATE);
823
824
/* Use one with the most features available. */
825
int max_features = 0;
826
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
827
uint32_t features = TextServerManager::get_singleton()->get_interface(i)->get_features();
828
int feature_number = 0;
829
while (features) {
830
feature_number += features & 1;
831
features >>= 1;
832
}
833
if (feature_number >= max_features) {
834
max_features = feature_number;
835
text_driver_idx = i;
836
}
837
}
838
if (text_driver_idx >= 0) {
839
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(text_driver_idx);
840
TextServerManager::get_singleton()->set_primary_interface(ts);
841
if (ts->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
842
ts->load_support_data("res://" + ts->get_support_data_filename());
843
}
844
} else {
845
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "TextServer: Unable to create TextServer interface.");
846
}
847
848
ClassDB::set_current_api(ClassDB::API_NONE);
849
850
_start_success = true;
851
852
return OK;
853
}
854
855
// The order is the same as in `Main::cleanup()`.
856
void Main::test_cleanup() {
857
ERR_FAIL_COND(!_start_success);
858
859
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
860
TextServerManager::get_singleton()->get_interface(i)->cleanup();
861
}
862
863
ResourceLoader::remove_custom_loaders();
864
ResourceSaver::remove_custom_savers();
865
PropertyListHelper::clear_base_helpers();
866
867
#ifdef TOOLS_ENABLED
868
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR);
869
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR);
870
unregister_editor_types();
871
#endif
872
873
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SCENE);
874
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE);
875
876
unregister_platform_apis();
877
unregister_driver_types();
878
unregister_scene_types();
879
880
finalize_theme_db();
881
882
#ifndef NAVIGATION_2D_DISABLED
883
NavigationServer2DManager::finalize_server();
884
NavigationServer2DManager::finalize_server_manager();
885
#endif // NAVIGATION_2D_DISABLED
886
#ifndef NAVIGATION_3D_DISABLED
887
NavigationServer3DManager::finalize_server();
888
NavigationServer3DManager::finalize_server_manager();
889
#endif // NAVIGATION_3D_DISABLED
890
891
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
892
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
893
unregister_server_types();
894
895
EngineDebugger::deinitialize();
896
OS::get_singleton()->finalize();
897
898
if (packed_data) {
899
memdelete(packed_data);
900
}
901
if (translation_server) {
902
memdelete(translation_server);
903
}
904
if (tsman) {
905
memdelete(tsman);
906
}
907
#ifndef PHYSICS_3D_DISABLED
908
if (physics_server_3d_manager) {
909
memdelete(physics_server_3d_manager);
910
}
911
#endif // PHYSICS_3D_DISABLED
912
#ifndef PHYSICS_2D_DISABLED
913
if (physics_server_2d_manager) {
914
memdelete(physics_server_2d_manager);
915
}
916
#endif // PHYSICS_2D_DISABLED
917
if (globals) {
918
memdelete(globals);
919
}
920
921
unregister_core_driver_types();
922
unregister_core_extensions();
923
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
924
925
if (engine) {
926
memdelete(engine);
927
}
928
929
unregister_core_types();
930
931
OS::get_singleton()->finalize_core();
932
}
933
#endif
934
935
int Main::test_entrypoint(int argc, char *argv[], bool &tests_need_run) {
936
for (int x = 0; x < argc; x++) {
937
// Early return to ignore a possible user-provided "--test" argument.
938
if ((strlen(argv[x]) == 2) && ((strncmp(argv[x], "--", 2) == 0) || (strncmp(argv[x], "++", 2) == 0))) {
939
tests_need_run = false;
940
return EXIT_SUCCESS;
941
}
942
if ((strncmp(argv[x], "--test", 6) == 0) && (strlen(argv[x]) == 6)) {
943
tests_need_run = true;
944
#ifdef TESTS_ENABLED
945
// TODO: need to come up with different test contexts.
946
// Not every test requires high-level functionality like `ClassDB`.
947
test_setup();
948
int status = test_main(argc, argv);
949
test_cleanup();
950
return status;
951
#else
952
ERR_PRINT(
953
"`--test` was specified on the command line, but this Godot binary was compiled without support for unit tests. Aborting.\n"
954
"To be able to run unit tests, use the `tests=yes` SCons option when compiling Godot.\n");
955
return EXIT_FAILURE;
956
#endif
957
}
958
}
959
tests_need_run = false;
960
return EXIT_SUCCESS;
961
}
962
963
/* Engine initialization
964
*
965
* Consists of several methods that are called by each platform's specific main(argc, argv).
966
* To fully understand engine init, one should therefore start from the platform's main and
967
* see how it calls into the Main class' methods.
968
*
969
* The initialization is typically done in 3 steps (with the setup2 step triggered either
970
* automatically by setup, or manually in the platform's main).
971
*
972
* - setup(execpath, argc, argv, p_second_phase) is the main entry point for all platforms,
973
* responsible for the initialization of all low level singletons and core types, and parsing
974
* command line arguments to configure things accordingly.
975
* If p_second_phase is true, it will chain into setup2() (default behavior). This is
976
* disabled on some platforms (Android, iOS) which trigger the second step in their own time.
977
*
978
* - setup2(p_main_tid_override) registers high level servers and singletons, displays the
979
* boot splash, then registers higher level types (scene, editor, etc.).
980
*
981
* - start() is the last step and that's where command line tools can run, or the main loop
982
* can be created eventually and the project settings put into action. That's also where
983
* the editor node is created, if relevant.
984
* start() does it own argument parsing for a subset of the command line arguments described
985
* in help, it's a bit messy and should be globalized with the setup() parsing somehow.
986
*/
987
988
Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_phase) {
989
GodotProfileZone("setup");
990
Thread::make_main_thread();
991
set_current_thread_safe_for_nodes(true);
992
993
OS::get_singleton()->initialize();
994
995
#if !defined(OVERRIDE_PATH_ENABLED) && !defined(TOOLS_ENABLED)
996
String old_cwd = OS::get_singleton()->get_cwd();
997
#if defined(MACOS_ENABLED) || defined(APPLE_EMBEDDED_ENABLED)
998
String new_cwd = OS::get_singleton()->get_bundle_resource_dir();
999
if (new_cwd.is_empty() || !new_cwd.is_absolute_path()) {
1000
new_cwd = OS::get_singleton()->get_executable_path().get_base_dir();
1001
}
1002
#else
1003
String new_cwd = OS::get_singleton()->get_executable_path().get_base_dir();
1004
#endif
1005
if (!new_cwd.is_empty()) {
1006
OS::get_singleton()->set_cwd(new_cwd);
1007
}
1008
#endif
1009
1010
// Benchmark tracking must be done after `OS::get_singleton()->initialize()` as on some
1011
// platforms, it's used to set up the time utilities.
1012
OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Setup");
1013
1014
engine = memnew(Engine);
1015
1016
MAIN_PRINT("Main: Initialize CORE");
1017
1018
register_core_types();
1019
register_core_driver_types();
1020
1021
MAIN_PRINT("Main: Initialize Globals");
1022
1023
input_map = memnew(InputMap);
1024
globals = memnew(ProjectSettings);
1025
1026
register_core_settings(); //here globals are present
1027
1028
translation_server = memnew(TranslationServer);
1029
performance = memnew(Performance);
1030
GDREGISTER_CLASS(Performance);
1031
engine->add_singleton(Engine::Singleton("Performance", performance));
1032
1033
// Only flush stdout in debug builds by default, as spamming `print()` will
1034
// decrease performance if this is enabled.
1035
GLOBAL_DEF_RST("application/run/flush_stdout_on_print", false);
1036
GLOBAL_DEF_RST("application/run/flush_stdout_on_print.debug", true);
1037
1038
MAIN_PRINT("Main: Parse CMDLine");
1039
1040
/* argument parsing and main creation */
1041
List<String> args;
1042
List<String> main_args;
1043
List<String> user_args;
1044
bool adding_user_args = false;
1045
List<String> platform_args = OS::get_singleton()->get_cmdline_platform_args();
1046
1047
// Add command line arguments.
1048
for (int i = 0; i < argc; i++) {
1049
args.push_back(String::utf8(argv[i]));
1050
}
1051
1052
// Add arguments received from macOS LaunchService (URL schemas, file associations).
1053
for (const String &arg : platform_args) {
1054
args.push_back(arg);
1055
}
1056
1057
List<String>::Element *I = args.front();
1058
1059
while (I) {
1060
I->get() = unescape_cmdline(I->get().strip_edges());
1061
I = I->next();
1062
}
1063
1064
String audio_driver = "";
1065
String project_path = ".";
1066
String debug_uri = "";
1067
#if defined(TOOLS_ENABLED) && (defined(WINDOWS_ENABLED) || defined(LINUXBSD_ENABLED))
1068
bool test_rd_creation = false;
1069
bool test_rd_support = false;
1070
#endif
1071
bool skip_breakpoints = false;
1072
bool ignore_error_breaks = false;
1073
String main_pack;
1074
bool quiet_stdout = false;
1075
int separate_thread_render = -1; // Tri-state: -1 = not set, 0 = false, 1 = true.
1076
1077
String remotefs;
1078
String remotefs_pass;
1079
1080
Vector<String> breakpoints;
1081
bool delta_smoothing_override = false;
1082
bool load_shell_env = false;
1083
1084
String rendering_driver = "";
1085
String rendering_method = "";
1086
OS::RenderingSource rendering_driver_source = OS::RenderingSource::RENDERING_SOURCE_DEFAULT;
1087
OS::RenderingSource rendering_method_source = OS::RenderingSource::RENDERING_SOURCE_DEFAULT;
1088
String default_renderer = "";
1089
String default_renderer_mobile = "";
1090
String renderer_hints = "";
1091
1092
packed_data = PackedData::get_singleton();
1093
if (!packed_data) {
1094
packed_data = memnew(PackedData);
1095
}
1096
1097
#ifdef MINIZIP_ENABLED
1098
1099
//XXX: always get_singleton() == 0x0
1100
zip_packed_data = ZipArchive::get_singleton();
1101
//TODO: remove this temporary fix
1102
if (!zip_packed_data) {
1103
zip_packed_data = memnew(ZipArchive);
1104
}
1105
1106
packed_data->add_pack_source(zip_packed_data);
1107
#endif
1108
1109
// Exit error code used in the `goto error` conditions.
1110
// It's returned as the program exit code. ERR_HELP is special cased and handled as success (0).
1111
Error exit_err = ERR_INVALID_PARAMETER;
1112
1113
I = args.front();
1114
while (I) {
1115
List<String>::Element *N = I->next();
1116
1117
const String &arg = I->get();
1118
1119
#ifdef MACOS_ENABLED
1120
// Ignore the process serial number argument passed by macOS Gatekeeper.
1121
// Otherwise, Godot would try to open a non-existent project on the first start and abort.
1122
if (arg.begins_with("-psn_")) {
1123
I = N;
1124
continue;
1125
}
1126
#endif
1127
1128
#ifdef TOOLS_ENABLED
1129
if (arg == "--debug" ||
1130
arg == "--verbose" ||
1131
arg == "--disable-crash-handler") {
1132
forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(arg);
1133
forwardable_cli_arguments[CLI_SCOPE_PROJECT].push_back(arg);
1134
}
1135
if (arg == "--single-window" || arg == "--editor-pseudolocalization") {
1136
forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(arg);
1137
}
1138
if (arg == "--audio-driver" ||
1139
arg == "--display-driver" ||
1140
arg == "--rendering-method" ||
1141
arg == "--rendering-driver" ||
1142
arg == "--xr-mode" ||
1143
arg == "-l" ||
1144
arg == "--language") {
1145
if (N) {
1146
forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(arg);
1147
forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(N->get());
1148
}
1149
}
1150
// If gpu is specified, both editor and debug instances started from editor will inherit.
1151
if (arg == "--gpu-index") {
1152
if (N) {
1153
const String &next_arg = N->get();
1154
forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(arg);
1155
forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(next_arg);
1156
forwardable_cli_arguments[CLI_SCOPE_PROJECT].push_back(arg);
1157
forwardable_cli_arguments[CLI_SCOPE_PROJECT].push_back(next_arg);
1158
}
1159
}
1160
#endif
1161
1162
if (adding_user_args) {
1163
user_args.push_back(arg);
1164
} else if (arg == "-h" || arg == "--help" || arg == "/?") { // display help
1165
1166
show_help = true;
1167
exit_err = ERR_HELP; // Hack to force an early exit in `main()` with a success code.
1168
goto error;
1169
1170
} else if (arg == "--version") {
1171
print_line(get_full_version_string());
1172
exit_err = ERR_HELP; // Hack to force an early exit in `main()` with a success code.
1173
goto error;
1174
1175
} else if (arg == "-v" || arg == "--verbose") { // verbose output
1176
1177
OS::get_singleton()->_verbose_stdout = true;
1178
} else if (arg == "-q" || arg == "--quiet") { // quieter output
1179
1180
quiet_stdout = true;
1181
1182
} else if (arg == "--no-header") {
1183
Engine::get_singleton()->_print_header = false;
1184
1185
} else if (arg == "--audio-driver") { // audio driver
1186
1187
if (N) {
1188
audio_driver = N->get();
1189
1190
bool found = false;
1191
for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
1192
if (audio_driver == AudioDriverManager::get_driver(i)->get_name()) {
1193
found = true;
1194
}
1195
}
1196
1197
if (!found) {
1198
OS::get_singleton()->print("Unknown audio driver '%s', aborting.\nValid options are ",
1199
audio_driver.utf8().get_data());
1200
1201
for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
1202
if (i == AudioDriverManager::get_driver_count() - 1) {
1203
OS::get_singleton()->print(" and ");
1204
} else if (i != 0) {
1205
OS::get_singleton()->print(", ");
1206
}
1207
1208
OS::get_singleton()->print("'%s'", AudioDriverManager::get_driver(i)->get_name());
1209
}
1210
1211
OS::get_singleton()->print(".\n");
1212
1213
goto error;
1214
}
1215
1216
N = N->next();
1217
} else {
1218
OS::get_singleton()->print("Missing audio driver argument, aborting.\n");
1219
goto error;
1220
}
1221
} else if (arg == "--audio-output-latency") {
1222
if (N) {
1223
audio_output_latency = N->get().to_int();
1224
N = N->next();
1225
} else {
1226
OS::get_singleton()->print("Missing audio output latency argument, aborting.\n");
1227
goto error;
1228
}
1229
} else if (arg == "--text-driver") {
1230
if (N) {
1231
text_driver = N->get();
1232
N = N->next();
1233
} else {
1234
OS::get_singleton()->print("Missing text driver argument, aborting.\n");
1235
goto error;
1236
}
1237
1238
} else if (arg == "--display-driver") { // force video driver
1239
1240
if (N) {
1241
display_driver = N->get();
1242
1243
bool found = false;
1244
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
1245
if (display_driver == DisplayServer::get_create_function_name(i)) {
1246
found = true;
1247
}
1248
}
1249
1250
if (!found) {
1251
OS::get_singleton()->print("Unknown display driver '%s', aborting.\nValid options are ",
1252
display_driver.utf8().get_data());
1253
1254
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
1255
if (i == DisplayServer::get_create_function_count() - 1) {
1256
OS::get_singleton()->print(" and ");
1257
} else if (i != 0) {
1258
OS::get_singleton()->print(", ");
1259
}
1260
1261
OS::get_singleton()->print("'%s'", DisplayServer::get_create_function_name(i));
1262
}
1263
1264
OS::get_singleton()->print(".\n");
1265
1266
goto error;
1267
}
1268
1269
N = N->next();
1270
} else {
1271
OS::get_singleton()->print("Missing display driver argument, aborting.\n");
1272
goto error;
1273
}
1274
} else if (arg == "--rendering-method") {
1275
if (N) {
1276
rendering_method = N->get();
1277
N = N->next();
1278
} else {
1279
OS::get_singleton()->print("Missing renderer name argument, aborting.\n");
1280
goto error;
1281
}
1282
} else if (arg == "--rendering-driver") {
1283
if (N) {
1284
rendering_driver = N->get();
1285
rendering_driver_source = OS::RenderingSource::RENDERING_SOURCE_COMMANDLINE;
1286
N = N->next();
1287
} else {
1288
OS::get_singleton()->print("Missing rendering driver argument, aborting.\n");
1289
goto error;
1290
}
1291
} else if (arg == "-f" || arg == "--fullscreen") { // force fullscreen
1292
init_fullscreen = true;
1293
window_mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
1294
} else if (arg == "-m" || arg == "--maximized") { // force maximized window
1295
init_maximized = true;
1296
window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
1297
} else if (arg == "-w" || arg == "--windowed") { // force windowed window
1298
1299
init_windowed = true;
1300
} else if (arg == "--gpu-index") {
1301
if (N) {
1302
Engine::singleton->gpu_idx = N->get().to_int();
1303
N = N->next();
1304
} else {
1305
OS::get_singleton()->print("Missing GPU index argument, aborting.\n");
1306
goto error;
1307
}
1308
} else if (arg == "--gpu-validation") {
1309
Engine::singleton->use_validation_layers = true;
1310
#ifdef DEBUG_ENABLED
1311
} else if (arg == "--gpu-abort") {
1312
Engine::singleton->abort_on_gpu_errors = true;
1313
#endif
1314
} else if (arg == "--generate-spirv-debug-info") {
1315
Engine::singleton->generate_spirv_debug_info = true;
1316
#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
1317
} else if (arg == "--extra-gpu-memory-tracking") {
1318
Engine::singleton->extra_gpu_memory_tracking = true;
1319
} else if (arg == "--accurate-breadcrumbs") {
1320
Engine::singleton->accurate_breadcrumbs = true;
1321
#endif
1322
} else if (arg == "--tablet-driver") {
1323
if (N) {
1324
tablet_driver = N->get();
1325
N = N->next();
1326
} else {
1327
OS::get_singleton()->print("Missing tablet driver argument, aborting.\n");
1328
goto error;
1329
}
1330
} else if (arg == "--delta-smoothing") {
1331
if (N) {
1332
String string = N->get();
1333
bool recognized = false;
1334
if (string == "enable") {
1335
OS::get_singleton()->set_delta_smoothing(true);
1336
delta_smoothing_override = true;
1337
recognized = true;
1338
}
1339
if (string == "disable") {
1340
OS::get_singleton()->set_delta_smoothing(false);
1341
delta_smoothing_override = false;
1342
recognized = true;
1343
}
1344
if (!recognized) {
1345
OS::get_singleton()->print("Delta-smoothing argument not recognized, aborting.\n");
1346
goto error;
1347
}
1348
N = N->next();
1349
} else {
1350
OS::get_singleton()->print("Missing delta-smoothing argument, aborting.\n");
1351
goto error;
1352
}
1353
} else if (arg == "--single-window") { // force single window
1354
1355
single_window = true;
1356
} else if (arg == "--accessibility") {
1357
if (N) {
1358
String string = N->get();
1359
if (string == "auto") {
1360
accessibility_mode = DisplayServer::AccessibilityMode::ACCESSIBILITY_AUTO;
1361
accessibility_mode_set = true;
1362
} else if (string == "always") {
1363
accessibility_mode = DisplayServer::AccessibilityMode::ACCESSIBILITY_ALWAYS;
1364
accessibility_mode_set = true;
1365
} else if (string == "disabled") {
1366
accessibility_mode = DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED;
1367
accessibility_mode_set = true;
1368
} else {
1369
OS::get_singleton()->print("Accessibility mode argument not recognized, aborting.\n");
1370
goto error;
1371
}
1372
N = N->next();
1373
} else {
1374
OS::get_singleton()->print("Missing accessibility mode argument, aborting.\n");
1375
goto error;
1376
}
1377
} else if (arg == "-t" || arg == "--always-on-top") { // force always-on-top window
1378
1379
init_always_on_top = true;
1380
} else if (arg == "--resolution") { // force resolution
1381
1382
if (N) {
1383
String vm = N->get();
1384
1385
if (!vm.contains_char('x')) { // invalid parameter format
1386
1387
OS::get_singleton()->print("Invalid resolution '%s', it should be e.g. '1280x720'.\n",
1388
vm.utf8().get_data());
1389
goto error;
1390
}
1391
1392
int w = vm.get_slicec('x', 0).to_int();
1393
int h = vm.get_slicec('x', 1).to_int();
1394
1395
if (w <= 0 || h <= 0) {
1396
OS::get_singleton()->print("Invalid resolution '%s', width and height must be above 0.\n",
1397
vm.utf8().get_data());
1398
goto error;
1399
}
1400
1401
window_size.width = w;
1402
window_size.height = h;
1403
force_res = true;
1404
1405
N = N->next();
1406
} else {
1407
OS::get_singleton()->print("Missing resolution argument, aborting.\n");
1408
goto error;
1409
}
1410
1411
} else if (arg == "--screen") { // set window screen
1412
1413
if (N) {
1414
init_screen = N->get().to_int();
1415
init_use_custom_screen = true;
1416
1417
N = N->next();
1418
} else {
1419
OS::get_singleton()->print("Missing screen argument, aborting.\n");
1420
goto error;
1421
}
1422
1423
} else if (arg == "--position") { // set window position
1424
1425
if (N) {
1426
String vm = N->get();
1427
1428
if (!vm.contains_char(',')) { // invalid parameter format
1429
1430
OS::get_singleton()->print("Invalid position '%s', it should be e.g. '80,128'.\n",
1431
vm.utf8().get_data());
1432
goto error;
1433
}
1434
1435
int x = vm.get_slicec(',', 0).to_int();
1436
int y = vm.get_slicec(',', 1).to_int();
1437
1438
init_custom_pos = Point2(x, y);
1439
init_use_custom_pos = true;
1440
1441
N = N->next();
1442
} else {
1443
OS::get_singleton()->print("Missing position argument, aborting.\n");
1444
goto error;
1445
}
1446
1447
} else if (arg == "--headless") { // enable headless mode (no audio, no rendering).
1448
1449
audio_driver = NULL_AUDIO_DRIVER;
1450
display_driver = NULL_DISPLAY_DRIVER;
1451
1452
} else if (arg == "--embedded") { // Enable embedded mode.
1453
#ifdef MACOS_ENABLED
1454
display_driver = EMBEDDED_DISPLAY_DRIVER;
1455
#else
1456
OS::get_singleton()->print("--embedded is only supported on macOS, aborting.\n");
1457
goto error;
1458
#endif
1459
} else if (arg == "--log-file") { // write to log file
1460
1461
if (N) {
1462
log_file = N->get();
1463
N = N->next();
1464
} else {
1465
OS::get_singleton()->print("Missing log file path argument, aborting.\n");
1466
goto error;
1467
}
1468
} else if (arg == "--profiling") { // enable profiling
1469
1470
use_debug_profiler = true;
1471
1472
} else if (arg == "-l" || arg == "--language") { // language
1473
1474
if (N) {
1475
locale = N->get();
1476
N = N->next();
1477
} else {
1478
OS::get_singleton()->print("Missing language argument, aborting.\n");
1479
goto error;
1480
}
1481
} else if (arg == "--remote-fs") { // remote filesystem
1482
1483
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
1484
if (N) {
1485
remotefs = N->get();
1486
N = N->next();
1487
} else {
1488
OS::get_singleton()->print("Missing remote filesystem address, aborting.\n");
1489
goto error;
1490
}
1491
#else
1492
ERR_PRINT(
1493
"`--remote-fs` was specified on the command line, but this Godot binary was compiled without debug. Aborting.\n"
1494
"To be able to use it, use the `target=template_debug` SCons option when compiling Godot.\n");
1495
#endif // defined(DEBUG_ENABLED) || defined (TOOLS_ENABLED)
1496
} else if (arg == "--remote-fs-password") { // remote filesystem password
1497
1498
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
1499
if (N) {
1500
remotefs_pass = N->get();
1501
N = N->next();
1502
} else {
1503
OS::get_singleton()->print("Missing remote filesystem password, aborting.\n");
1504
goto error;
1505
}
1506
#else
1507
ERR_PRINT(
1508
"`--remote-fs-password` was specified on the command line, but this Godot binary was compiled without debug. Aborting.\n"
1509
"To be able to use it, use the `target=template_debug` SCons option when compiling Godot.\n");
1510
goto error;
1511
#endif // defined(DEBUG_ENABLED) || defined (TOOLS_ENABLED)
1512
} else if (arg == "--render-thread") { // render thread mode
1513
1514
if (N) {
1515
if (N->get() == "safe") {
1516
separate_thread_render = 0;
1517
#ifndef DISABLE_DEPRECATED
1518
} else if (N->get() == "unsafe") {
1519
OS::get_singleton()->print("The --render-thread unsafe option is unsupported in Godot 4 and will be removed.\n");
1520
separate_thread_render = 0;
1521
#endif
1522
} else if (N->get() == "separate") {
1523
separate_thread_render = 1;
1524
} else {
1525
OS::get_singleton()->print("Unknown render thread mode, aborting.\n");
1526
#ifdef DISABLE_DEPRECATED
1527
OS::get_singleton()->print("Valid options are 'safe' and 'separate'.\n");
1528
#else
1529
OS::get_singleton()->print("Valid options are 'unsafe', 'safe' and 'separate'.\n");
1530
#endif
1531
goto error;
1532
}
1533
1534
N = N->next();
1535
} else {
1536
OS::get_singleton()->print("Missing render thread mode argument, aborting.\n");
1537
goto error;
1538
}
1539
#ifdef TOOLS_ENABLED
1540
} else if (arg == "-e" || arg == "--editor") { // starts editor
1541
1542
editor = true;
1543
} else if (arg == "-p" || arg == "--project-manager") { // starts project manager
1544
project_manager = true;
1545
} else if (arg == "--recovery-mode") { // Enables recovery mode.
1546
recovery_mode = true;
1547
} else if (arg == "--debug-server") {
1548
if (N) {
1549
debug_server_uri = N->get();
1550
if (!debug_server_uri.contains("://")) { // wrong address
1551
OS::get_singleton()->print("Invalid debug server uri. It should be of the form <protocol>://<bind_address>:<port>.\n");
1552
goto error;
1553
}
1554
N = N->next();
1555
} else {
1556
OS::get_singleton()->print("Missing remote debug server uri, aborting.\n");
1557
goto error;
1558
}
1559
} else if (arg == "--single-threaded-scene") {
1560
single_threaded_scene = true;
1561
} else if (arg == "--build-solutions") { // Build the scripting solution such C#
1562
1563
auto_build_solutions = true;
1564
editor = true;
1565
cmdline_tool = true;
1566
} else if (arg == "--dump-gdextension-interface") {
1567
// Register as an editor instance to use low-end fallback if relevant.
1568
editor = true;
1569
cmdline_tool = true;
1570
dump_gdextension_interface_header = true;
1571
print_line("Dumping GDExtension interface header file");
1572
// Hack. Not needed but otherwise we end up detecting that this should
1573
// run the project instead of a cmdline tool.
1574
// Needs full refactoring to fix properly.
1575
main_args.push_back(arg);
1576
} else if (arg == "--dump-gdextension-interface-json") {
1577
// Register as an editor instance to use low-end fallback if relevant.
1578
editor = true;
1579
cmdline_tool = true;
1580
dump_gdextension_interface = true;
1581
print_line("Dumping GDExtension interface json file");
1582
// Hack. Not needed but otherwise we end up detecting that this should
1583
// run the project instead of a cmdline tool.
1584
// Needs full refactoring to fix properly.
1585
main_args.push_back(arg);
1586
} else if (arg == "--dump-extension-api") {
1587
// Register as an editor instance to use low-end fallback if relevant.
1588
editor = true;
1589
cmdline_tool = true;
1590
dump_extension_api = true;
1591
print_line("Dumping Extension API");
1592
// Hack. Not needed but otherwise we end up detecting that this should
1593
// run the project instead of a cmdline tool.
1594
// Needs full refactoring to fix properly.
1595
main_args.push_back(arg);
1596
} else if (arg == "--dump-extension-api-with-docs") {
1597
// Register as an editor instance to use low-end fallback if relevant.
1598
editor = true;
1599
cmdline_tool = true;
1600
dump_extension_api = true;
1601
include_docs_in_extension_api_dump = true;
1602
print_line("Dumping Extension API including documentation");
1603
// Hack. Not needed but otherwise we end up detecting that this should
1604
// run the project instead of a cmdline tool.
1605
// Needs full refactoring to fix properly.
1606
main_args.push_back(arg);
1607
} else if (arg == "--validate-extension-api") {
1608
// Register as an editor instance to use low-end fallback if relevant.
1609
editor = true;
1610
cmdline_tool = true;
1611
validate_extension_api = true;
1612
// Hack. Not needed but otherwise we end up detecting that this should
1613
// run the project instead of a cmdline tool.
1614
// Needs full refactoring to fix properly.
1615
main_args.push_back(arg);
1616
1617
if (N) {
1618
validate_extension_api_file = N->get();
1619
1620
N = N->next();
1621
} else {
1622
OS::get_singleton()->print("Missing file to load argument after --validate-extension-api, aborting.");
1623
goto error;
1624
}
1625
} else if (arg == "--import") {
1626
editor = true;
1627
cmdline_tool = true;
1628
wait_for_import = true;
1629
quit_after = 1;
1630
} else if (arg == "--export-release" || arg == "--export-debug" ||
1631
arg == "--export-pack" || arg == "--export-patch") { // Export project
1632
// Actually handling is done in start().
1633
editor = true;
1634
cmdline_tool = true;
1635
wait_for_import = true;
1636
main_args.push_back(arg);
1637
} else if (arg == "--patches") {
1638
if (N) {
1639
// Actually handling is done in start().
1640
main_args.push_back(arg);
1641
main_args.push_back(N->get());
1642
1643
N = N->next();
1644
} else {
1645
OS::get_singleton()->print("Missing comma-separated list of patches after --patches, aborting.\n");
1646
goto error;
1647
}
1648
#ifndef DISABLE_DEPRECATED
1649
} else if (arg == "--export") { // For users used to 3.x syntax.
1650
OS::get_singleton()->print("The Godot 3 --export option was changed to more explicit --export-release / --export-debug / --export-pack options.\nSee the --help output for details.\n");
1651
goto error;
1652
} else if (arg == "--convert-3to4") {
1653
// Actually handling is done in start().
1654
cmdline_tool = true;
1655
main_args.push_back(arg);
1656
1657
if (N && !N->get().begins_with("-")) {
1658
if (itos(N->get().to_int()) == N->get()) {
1659
converter_max_kb_file = N->get().to_int();
1660
}
1661
if (N->next() && !N->next()->get().begins_with("-")) {
1662
if (itos(N->next()->get().to_int()) == N->next()->get()) {
1663
converter_max_line_length = N->next()->get().to_int();
1664
}
1665
}
1666
}
1667
} else if (arg == "--validate-conversion-3to4") {
1668
// Actually handling is done in start().
1669
cmdline_tool = true;
1670
main_args.push_back(arg);
1671
1672
if (N && !N->get().begins_with("-")) {
1673
if (itos(N->get().to_int()) == N->get()) {
1674
converter_max_kb_file = N->get().to_int();
1675
}
1676
if (N->next() && !N->next()->get().begins_with("-")) {
1677
if (itos(N->next()->get().to_int()) == N->next()->get()) {
1678
converter_max_line_length = N->next()->get().to_int();
1679
}
1680
}
1681
}
1682
#endif // DISABLE_DEPRECATED
1683
} else if (arg == "--doctool") {
1684
// Actually handling is done in start().
1685
cmdline_tool = true;
1686
1687
// `--doctool` implies `--headless` to avoid spawning an unnecessary window
1688
// and speed up class reference generation.
1689
audio_driver = NULL_AUDIO_DRIVER;
1690
display_driver = NULL_DISPLAY_DRIVER;
1691
main_args.push_back(arg);
1692
#ifdef MODULE_GDSCRIPT_ENABLED
1693
} else if (arg == "--gdscript-docs") {
1694
if (N) {
1695
project_path = N->get();
1696
// Will be handled in start()
1697
main_args.push_back(arg);
1698
main_args.push_back(N->get());
1699
N = N->next();
1700
// GDScript docgen requires Autoloads, but loading those also creates a main loop.
1701
// This forces main loop to quit without adding more GDScript-specific exceptions to setup.
1702
quit_after = 1;
1703
} else {
1704
OS::get_singleton()->print("Missing relative or absolute path to project for --gdscript-docs, aborting.\n");
1705
goto error;
1706
}
1707
#endif // MODULE_GDSCRIPT_ENABLED
1708
#endif // TOOLS_ENABLED
1709
1710
} else if (arg == "--path") { // set path of project to start or edit
1711
#if defined(OVERRIDE_PATH_ENABLED)
1712
if (N) {
1713
String p = N->get();
1714
if (OS::get_singleton()->set_cwd(p) != OK) {
1715
OS::get_singleton()->print("Invalid project path specified: \"%s\", aborting.\n", p.utf8().get_data());
1716
goto error;
1717
}
1718
N = N->next();
1719
} else {
1720
OS::get_singleton()->print("Missing relative or absolute path, aborting.\n");
1721
goto error;
1722
}
1723
#else
1724
ERR_PRINT(
1725
"`--path` was specified on the command line, but this Godot binary was compiled without support for path overrides. Aborting.\n"
1726
"To be able to use it, use the `disable_path_overrides=no` SCons option when compiling Godot.\n");
1727
goto error;
1728
#endif // defined(OVERRIDE_PATH_ENABLED)
1729
} else if (arg == "--quit") { // Auto quit at the end of the first main loop iteration
1730
quit_after = 1;
1731
#ifdef TOOLS_ENABLED
1732
wait_for_import = true;
1733
#endif
1734
} else if (arg == "--quit-after") { // Quit after the given number of iterations
1735
if (N) {
1736
quit_after = N->get().to_int();
1737
N = N->next();
1738
} else {
1739
OS::get_singleton()->print("Missing number of iterations, aborting.\n");
1740
goto error;
1741
}
1742
} else if (arg.ends_with("project.godot")) {
1743
#if defined(OVERRIDE_PATH_ENABLED)
1744
String path;
1745
String file = arg;
1746
int sep = MAX(file.rfind_char('/'), file.rfind_char('\\'));
1747
if (sep == -1) {
1748
path = ".";
1749
} else {
1750
path = file.substr(0, sep);
1751
}
1752
if (OS::get_singleton()->set_cwd(path) == OK) {
1753
// path already specified, don't override
1754
} else {
1755
project_path = path;
1756
}
1757
#ifdef TOOLS_ENABLED
1758
editor = true;
1759
#endif
1760
#else
1761
ERR_PRINT(
1762
"`project.godot` path was specified on the command line, but this Godot binary was compiled without support for path overrides. Aborting.\n"
1763
"To be able to use it, use the `disable_path_overrides=no` SCons option when compiling Godot.\n");
1764
goto error;
1765
#endif // defined(OVERRIDE_PATH_ENABLED)
1766
} else if (arg == "-b" || arg == "--breakpoints") { // add breakpoints
1767
1768
if (N) {
1769
String bplist = N->get();
1770
breakpoints = bplist.split(",");
1771
N = N->next();
1772
} else {
1773
OS::get_singleton()->print("Missing list of breakpoints, aborting.\n");
1774
goto error;
1775
}
1776
1777
} else if (arg == "--max-fps") { // set maximum rendered FPS
1778
1779
if (N) {
1780
max_fps = N->get().to_int();
1781
N = N->next();
1782
} else {
1783
OS::get_singleton()->print("Missing maximum FPS argument, aborting.\n");
1784
goto error;
1785
}
1786
1787
} else if (arg == "--frame-delay") { // force frame delay
1788
1789
if (N) {
1790
frame_delay = N->get().to_int();
1791
N = N->next();
1792
} else {
1793
OS::get_singleton()->print("Missing frame delay argument, aborting.\n");
1794
goto error;
1795
}
1796
1797
} else if (arg == "--time-scale") { // force time scale
1798
1799
if (N) {
1800
Engine::get_singleton()->set_time_scale(N->get().to_float());
1801
N = N->next();
1802
} else {
1803
OS::get_singleton()->print("Missing time scale argument, aborting.\n");
1804
goto error;
1805
}
1806
} else if (arg == "--main-pack") {
1807
#if defined(OVERRIDE_PATH_ENABLED) || defined(WEB_ENABLED) // Note: main-pack is always used on web and can't be disabled.
1808
if (N) {
1809
main_pack = N->get();
1810
N = N->next();
1811
} else {
1812
OS::get_singleton()->print("Missing path to main pack file, aborting.\n");
1813
goto error;
1814
}
1815
#else
1816
ERR_PRINT(
1817
"`--main-pack` was specified on the command line, but this Godot binary was compiled without support for path overrides. Aborting.\n"
1818
"To be able to use it, use the `disable_path_overrides=no` SCons option when compiling Godot.\n");
1819
goto error;
1820
#endif // defined(OVERRIDE_PATH_ENABLED) || defined(WEB_ENABLED)
1821
1822
} else if (arg == "-d" || arg == "--debug") {
1823
debug_uri = "local://";
1824
OS::get_singleton()->_debug_stdout = true;
1825
#if defined(DEBUG_ENABLED)
1826
} else if (arg == "--debug-collisions") {
1827
debug_collisions = true;
1828
} else if (arg == "--debug-paths") {
1829
debug_paths = true;
1830
} else if (arg == "--debug-navigation") {
1831
debug_navigation = true;
1832
} else if (arg == "--debug-avoidance") {
1833
debug_avoidance = true;
1834
} else if (arg == "--debug-canvas-item-redraw") {
1835
debug_canvas_item_redraw = true;
1836
} else if (arg == "--debug-stringnames") {
1837
StringName::set_debug_stringnames(true);
1838
} else if (arg == "--debug-mute-audio") {
1839
debug_mute_audio = true;
1840
#endif // defined(DEBUG_ENABLED)
1841
#if defined(TOOLS_ENABLED) && (defined(WINDOWS_ENABLED) || defined(LINUXBSD_ENABLED))
1842
} else if (arg == "--test-rd-support") {
1843
test_rd_support = true;
1844
} else if (arg == "--test-rd-creation") {
1845
test_rd_creation = true;
1846
#endif // defined(TOOLS_ENABLED) && (defined(WINDOWS_ENABLED) || defined(LINUXBSD_ENABLED))
1847
} else if (arg == "--remote-debug") {
1848
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
1849
if (N) {
1850
debug_uri = N->get();
1851
if (!debug_uri.contains("://")) { // wrong address
1852
OS::get_singleton()->print(
1853
"Invalid debug host address, it should be of the form <protocol>://<host/IP>:<port>.\n");
1854
goto error;
1855
}
1856
N = N->next();
1857
} else {
1858
OS::get_singleton()->print("Missing remote debug host address, aborting.\n");
1859
goto error;
1860
}
1861
#else
1862
ERR_PRINT(
1863
"`--remote-debug` was specified on the command line, but this Godot binary was compiled without debug. Aborting.\n"
1864
"To be able to use it, use the `target=template_debug` SCons option when compiling Godot.\n");
1865
goto error;
1866
#endif // defined(DEBUG_ENABLED) || defined (TOOLS_ENABLED)
1867
} else if (arg == "--editor-pid") { // not exposed to user
1868
if (N) {
1869
editor_pid = N->get().to_int();
1870
N = N->next();
1871
} else {
1872
OS::get_singleton()->print("Missing editor PID argument, aborting.\n");
1873
goto error;
1874
}
1875
} else if (arg == "--disable-render-loop") {
1876
disable_render_loop = true;
1877
} else if (arg == "--fixed-fps") {
1878
if (N) {
1879
fixed_fps = N->get().to_int();
1880
N = N->next();
1881
} else {
1882
OS::get_singleton()->print("Missing fixed-fps argument, aborting.\n");
1883
goto error;
1884
}
1885
} else if (arg == "--write-movie") {
1886
if (N) {
1887
Engine::get_singleton()->set_write_movie_path(N->get());
1888
N = N->next();
1889
if (fixed_fps == -1) {
1890
fixed_fps = 60;
1891
}
1892
OS::get_singleton()->_writing_movie = true;
1893
} else {
1894
OS::get_singleton()->print("Missing write-movie argument, aborting.\n");
1895
goto error;
1896
}
1897
} else if (arg == "--disable-vsync") {
1898
disable_vsync = true;
1899
} else if (arg == "--print-fps") {
1900
print_fps = true;
1901
#ifdef TOOLS_ENABLED
1902
} else if (arg == "--editor-pseudolocalization") {
1903
editor_pseudolocalization = true;
1904
main_args.push_back(arg);
1905
#endif // TOOLS_ENABLED
1906
} else if (arg == "--gpu-profile") {
1907
profile_gpu = true;
1908
} else if (arg == "--disable-crash-handler") {
1909
OS::get_singleton()->disable_crash_handler();
1910
} else if (arg == "--skip-breakpoints") {
1911
skip_breakpoints = true;
1912
} else if (I->get() == "--ignore-error-breaks") {
1913
ignore_error_breaks = true;
1914
#ifndef XR_DISABLED
1915
} else if (arg == "--xr-mode") {
1916
if (N) {
1917
String xr_mode = N->get().to_lower();
1918
N = N->next();
1919
if (xr_mode == "default") {
1920
XRServer::set_xr_mode(XRServer::XRMODE_DEFAULT);
1921
} else if (xr_mode == "off") {
1922
XRServer::set_xr_mode(XRServer::XRMODE_OFF);
1923
} else if (xr_mode == "on") {
1924
XRServer::set_xr_mode(XRServer::XRMODE_ON);
1925
} else {
1926
OS::get_singleton()->print("Unknown --xr-mode argument \"%s\", aborting.\n", xr_mode.ascii().get_data());
1927
goto error;
1928
}
1929
} else {
1930
OS::get_singleton()->print("Missing --xr-mode argument, aborting.\n");
1931
goto error;
1932
}
1933
#endif // XR_DISABLED
1934
} else if (arg == "--benchmark") {
1935
OS::get_singleton()->set_use_benchmark(true);
1936
} else if (arg == "--benchmark-file") {
1937
if (N) {
1938
OS::get_singleton()->set_use_benchmark(true);
1939
String benchmark_file = N->get();
1940
OS::get_singleton()->set_benchmark_file(benchmark_file);
1941
N = N->next();
1942
} else {
1943
OS::get_singleton()->print("Missing <path> argument for --benchmark-file <path>.\n");
1944
goto error;
1945
}
1946
#if defined(TOOLS_ENABLED) && defined(MODULE_GDSCRIPT_ENABLED) && !defined(GDSCRIPT_NO_LSP)
1947
} else if (arg == "--lsp-port") {
1948
if (N) {
1949
int port_override = N->get().to_int();
1950
if (port_override < 0 || port_override > 65535) {
1951
OS::get_singleton()->print("<port> argument for --lsp-port <port> must be between 0 and 65535.\n");
1952
goto error;
1953
}
1954
GDScriptLanguageServer::port_override = port_override;
1955
N = N->next();
1956
} else {
1957
OS::get_singleton()->print("Missing <port> argument for --lsp-port <port>.\n");
1958
goto error;
1959
}
1960
#endif // TOOLS_ENABLED && MODULE_GDSCRIPT_ENABLED && !GDSCRIPT_NO_LSP
1961
#if defined(TOOLS_ENABLED)
1962
} else if (arg == "--dap-port") {
1963
if (N) {
1964
int port_override = N->get().to_int();
1965
if (port_override < 0 || port_override > 65535) {
1966
OS::get_singleton()->print("<port> argument for --dap-port <port> must be between 0 and 65535.\n");
1967
goto error;
1968
}
1969
DebugAdapterServer::port_override = port_override;
1970
N = N->next();
1971
} else {
1972
OS::get_singleton()->print("Missing <port> argument for --dap-port <port>.\n");
1973
goto error;
1974
}
1975
#endif // TOOLS_ENABLED
1976
} else if (arg == "--wid") {
1977
if (N) {
1978
init_embed_parent_window_id = N->get().to_int();
1979
if (init_embed_parent_window_id == 0) {
1980
OS::get_singleton()->print("<window_id> argument for --wid <window_id> must be different then 0.\n");
1981
goto error;
1982
}
1983
1984
OS::get_singleton()->_embedded_in_editor = true;
1985
Engine::get_singleton()->set_embedded_in_editor(true);
1986
1987
N = N->next();
1988
} else {
1989
OS::get_singleton()->print("Missing <window_id> argument for --wid <window_id>.\n");
1990
goto error;
1991
}
1992
1993
} else if (arg == "--" || arg == "++") {
1994
adding_user_args = true;
1995
} else {
1996
main_args.push_back(arg);
1997
}
1998
1999
I = N;
2000
}
2001
2002
#ifdef TOOLS_ENABLED
2003
if (editor && project_manager) {
2004
OS::get_singleton()->print(
2005
"Error: Command line arguments implied opening both editor and project manager, which is not possible. Aborting.\n");
2006
goto error;
2007
}
2008
#endif
2009
2010
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
2011
// Network file system needs to be configured before globals, since globals are based on the
2012
// 'project.godot' file which will only be available through the network if this is enabled
2013
if (!remotefs.is_empty()) {
2014
int port;
2015
if (remotefs.contains_char(':')) {
2016
port = remotefs.get_slicec(':', 1).to_int();
2017
remotefs = remotefs.get_slicec(':', 0);
2018
} else {
2019
port = 6010;
2020
}
2021
Error err = OS::get_singleton()->setup_remote_filesystem(remotefs, port, remotefs_pass, project_path);
2022
2023
if (err) {
2024
OS::get_singleton()->printerr("Could not connect to remotefs: %s:%i.\n", remotefs.utf8().get_data(), port);
2025
goto error;
2026
}
2027
}
2028
#endif // defined(DEBUG_ENABLED) || defined (TOOLS_ENABLED)
2029
2030
OS::get_singleton()->_in_editor = editor;
2031
if (globals->setup(project_path, main_pack, false, editor) == OK) {
2032
#ifdef TOOLS_ENABLED
2033
found_project = true;
2034
#endif
2035
} else {
2036
#ifdef TOOLS_ENABLED
2037
editor = false;
2038
#else
2039
String error_msg = "Error: Couldn't load project data at path \"" + (project_path == "." ? OS::get_singleton()->get_cwd() : project_path) + "\". Is the .pck file missing?\n\n";
2040
#if !defined(OVERRIDE_PATH_ENABLED) && !defined(TOOLS_ENABLED)
2041
String exec_path = OS::get_singleton()->get_executable_path();
2042
String exec_basename = exec_path.get_file().get_basename();
2043
2044
if (FileAccess::exists(old_cwd.path_join(exec_basename + ".pck"))) {
2045
error_msg += "\"" + exec_basename + ".pck\" was found in the current working directory. To be able to load a project from the CWD, use the `disable_path_overrides=no` SCons option when compiling Godot.\n";
2046
} else if (FileAccess::exists(old_cwd.path_join("project.godot"))) {
2047
error_msg += "\"project.godot\" was found in the current working directory. To be able to load a project from the CWD, use the `disable_path_overrides=no` SCons option when compiling Godot.\n";
2048
} else {
2049
error_msg += "If you've renamed the executable, the associated .pck file should also be renamed to match the executable's name (without the extension).\n";
2050
}
2051
#else
2052
error_msg += "If you've renamed the executable, the associated .pck file should also be renamed to match the executable's name (without the extension).\n";
2053
#endif
2054
ERR_PRINT(error_msg);
2055
2056
OS::get_singleton()->alert(error_msg);
2057
2058
goto error;
2059
#endif
2060
}
2061
2062
// Initialize WorkerThreadPool.
2063
{
2064
#ifdef THREADS_ENABLED
2065
if (editor || project_manager) {
2066
WorkerThreadPool::get_singleton()->init(-1, 0.75);
2067
} else {
2068
int worker_threads = GLOBAL_GET("threading/worker_pool/max_threads");
2069
float low_priority_ratio = GLOBAL_GET("threading/worker_pool/low_priority_thread_ratio");
2070
WorkerThreadPool::get_singleton()->init(worker_threads, low_priority_ratio);
2071
}
2072
#else
2073
WorkerThreadPool::get_singleton()->init(0, 0);
2074
#endif
2075
}
2076
2077
#ifdef TOOLS_ENABLED
2078
if (!project_manager && !editor) {
2079
// If we didn't find a project, we fall back to the project manager.
2080
project_manager = !found_project && !cmdline_tool;
2081
}
2082
2083
{
2084
// Synced with https://github.com/baldurk/renderdoc/blob/2b01465c7/renderdoc/driver/vulkan/vk_layer.cpp#L118-L165
2085
LocalVector<String> layers_to_disable = {
2086
"DISABLE_RTSS_LAYER", // GH-57937.
2087
"DISABLE_VULKAN_OBS_CAPTURE", // GH-103800.
2088
"DISABLE_VULKAN_OW_OBS_CAPTURE", // GH-104154.
2089
"DISABLE_SAMPLE_LAYER", // GH-104154.
2090
"DISABLE_GAMEPP_LAYER", // GH-104154.
2091
"DISABLE_VK_LAYER_TENCENT_wegame_cross_overlay_1", // GH-104154.
2092
// "NODEVICE_SELECT", // Kept as it's useful - GH-104592.
2093
"VK_LAYER_bandicam_helper_DEBUG_1", // GH-101480.
2094
"DISABLE_VK_LAYER_bandicam_helper_1", // GH-101480.
2095
"DISABLE_VK_LAYER_reshade_1", // GH-70849.
2096
"DISABLE_VK_LAYER_GPUOpen_GRS", // GH-104154.
2097
"DISABLE_LAYER", // GH-104154 (fpsmon).
2098
"DISABLE_MANGOHUD", // GH-57403.
2099
"DISABLE_VKBASALT",
2100
"DISABLE_FOSSILIZE", // GH-115139.
2101
};
2102
2103
#if defined(WINDOWS_ENABLED) || defined(LINUXBSD_ENABLED)
2104
if (editor || project_manager || test_rd_support || test_rd_creation) {
2105
#else
2106
if (editor || project_manager) {
2107
#endif
2108
// Disable Vulkan overlays in editor, they cause various issues.
2109
for (const String &layer_disable : layers_to_disable) {
2110
OS::get_singleton()->set_environment(layer_disable, "1");
2111
}
2112
} else {
2113
// Re-allow using Vulkan overlays, disabled while using the editor.
2114
for (const String &layer_disable : layers_to_disable) {
2115
OS::get_singleton()->unset_environment(layer_disable);
2116
}
2117
}
2118
}
2119
#endif
2120
2121
#if defined(TOOLS_ENABLED) && (defined(WINDOWS_ENABLED) || defined(LINUXBSD_ENABLED))
2122
if (test_rd_support) {
2123
// Test Rendering Device creation and exit.
2124
2125
OS::get_singleton()->set_crash_handler_silent();
2126
if (OS::get_singleton()->_test_create_rendering_device(display_driver)) {
2127
exit_err = ERR_HELP;
2128
} else {
2129
exit_err = ERR_UNAVAILABLE;
2130
}
2131
goto error;
2132
} else if (test_rd_creation) {
2133
// Test OpenGL context and Rendering Device simultaneous creation and exit.
2134
2135
OS::get_singleton()->set_crash_handler_silent();
2136
if (OS::get_singleton()->_test_create_rendering_device_and_gl(display_driver)) {
2137
exit_err = ERR_HELP;
2138
} else {
2139
exit_err = ERR_UNAVAILABLE;
2140
}
2141
goto error;
2142
}
2143
#endif
2144
2145
#ifdef TOOLS_ENABLED
2146
if (editor) {
2147
Engine::get_singleton()->set_editor_hint(true);
2148
Engine::get_singleton()->set_extension_reloading_enabled(true);
2149
2150
// Create initialization lock file to detect crashes during startup.
2151
OS::get_singleton()->create_lock_file();
2152
2153
main_args.push_back("--editor");
2154
if (!init_windowed && !init_fullscreen) {
2155
init_maximized = true;
2156
window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
2157
}
2158
}
2159
2160
if (project_manager) {
2161
Engine::get_singleton()->set_project_manager_hint(true);
2162
}
2163
2164
if (recovery_mode) {
2165
if (project_manager || !editor) {
2166
OS::get_singleton()->print("Error: Recovery mode can only be used in the editor. Aborting.\n");
2167
goto error;
2168
}
2169
2170
Engine::get_singleton()->set_recovery_mode_hint(true);
2171
}
2172
#endif
2173
2174
OS::get_singleton()->set_cmdline(execpath, main_args, user_args);
2175
2176
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));
2177
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));
2178
Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/common/physics_jitter_fix", PROPERTY_HINT_RANGE, "0,2,0.001,or_greater"), 0.5));
2179
Engine::get_singleton()->set_max_fps(GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/max_fps", PROPERTY_HINT_RANGE, "0,1000,1"), 0));
2180
if (max_fps >= 0) {
2181
Engine::get_singleton()->set_max_fps(max_fps);
2182
}
2183
2184
// Initialize user data dir.
2185
OS::get_singleton()->ensure_user_data_dir();
2186
2187
OS::get_singleton()->set_low_processor_usage_mode(GLOBAL_DEF("application/run/low_processor_mode", false));
2188
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(
2189
GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "0,33200,1,or_greater"), 6900)); // Roughly 144 FPS
2190
2191
GLOBAL_DEF("application/run/delta_smoothing", true);
2192
if (!delta_smoothing_override) {
2193
OS::get_singleton()->set_delta_smoothing(GLOBAL_GET("application/run/delta_smoothing"));
2194
}
2195
2196
GLOBAL_DEF("debug/settings/stdout/print_fps", false);
2197
GLOBAL_DEF("debug/settings/stdout/print_gpu_profile", false);
2198
GLOBAL_DEF("debug/settings/stdout/verbose_stdout", false);
2199
GLOBAL_DEF("debug/settings/physics_interpolation/enable_warnings", true);
2200
if (!OS::get_singleton()->_verbose_stdout) { // Not manually overridden.
2201
OS::get_singleton()->_verbose_stdout = GLOBAL_GET("debug/settings/stdout/verbose_stdout");
2202
}
2203
2204
register_early_core_singletons();
2205
initialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
2206
register_core_extensions(); // core extensions must be registered after globals setup and before display
2207
2208
if (!editor) {
2209
ResourceUID::get_singleton()->enable_reverse_cache();
2210
}
2211
ResourceUID::get_singleton()->load_from_cache(true); // Load UUIDs from cache.
2212
ProjectSettings::get_singleton()->fix_autoload_paths(); // Handles autoloads saved as UID.
2213
2214
if (ProjectSettings::get_singleton()->has_custom_feature("dedicated_server")) {
2215
audio_driver = NULL_AUDIO_DRIVER;
2216
display_driver = NULL_DISPLAY_DRIVER;
2217
}
2218
2219
GLOBAL_DEF(PropertyInfo(Variant::INT, "network/limits/debugger/max_chars_per_second", PROPERTY_HINT_RANGE, "256,4096,1,or_greater"), 32768);
2220
GLOBAL_DEF(PropertyInfo(Variant::INT, "network/limits/debugger/max_queued_messages", PROPERTY_HINT_RANGE, "128,8192,1,or_greater"), 2048);
2221
GLOBAL_DEF(PropertyInfo(Variant::INT, "network/limits/debugger/max_errors_per_second", PROPERTY_HINT_RANGE, "1,200,1,or_greater"), 400);
2222
GLOBAL_DEF(PropertyInfo(Variant::INT, "network/limits/debugger/max_warnings_per_second", PROPERTY_HINT_RANGE, "1,200,1,or_greater"), 400);
2223
2224
EngineDebugger::initialize(debug_uri, skip_breakpoints, ignore_error_breaks, breakpoints, []() {
2225
if (editor_pid) {
2226
DisplayServer::get_singleton()->enable_for_stealing_focus(editor_pid);
2227
}
2228
});
2229
2230
#ifdef TOOLS_ENABLED
2231
if (editor) {
2232
packed_data->set_disabled(true);
2233
}
2234
#endif
2235
2236
GLOBAL_DEF("debug/file_logging/enable_file_logging", false);
2237
// Only file logging by default on desktop platforms as logs can't be
2238
// accessed easily on mobile/Web platforms (if at all).
2239
// This also prevents logs from being created for the editor instance, as feature tags
2240
// are disabled while in the editor (even if they should logically apply).
2241
GLOBAL_DEF("debug/file_logging/enable_file_logging.pc", true);
2242
GLOBAL_DEF("debug/file_logging/log_path", "user://logs/godot.log");
2243
GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/file_logging/max_log_files", PROPERTY_HINT_RANGE, "0,20,1,or_greater"), 5);
2244
2245
// If `--log-file` is used to override the log path, allow creating logs for the project manager or editor
2246
// and even if file logging is disabled in the Project Settings.
2247
// `--log-file` can be used with any path (including absolute paths outside the project folder),
2248
// so check for filesystem access if it's used.
2249
if (FileAccess::get_create_func(!log_file.is_empty() ? FileAccess::ACCESS_FILESYSTEM : FileAccess::ACCESS_USERDATA) &&
2250
(!log_file.is_empty() || (!project_manager && !editor && GLOBAL_GET("debug/file_logging/enable_file_logging")))) {
2251
// Don't create logs for the project manager as they would be written to
2252
// the current working directory, which is inconvenient.
2253
String base_path;
2254
int max_files;
2255
if (!log_file.is_empty()) {
2256
base_path = log_file;
2257
// Ensure log file name respects the specified override by disabling log rotation.
2258
max_files = 1;
2259
} else {
2260
base_path = GLOBAL_GET("debug/file_logging/log_path");
2261
max_files = GLOBAL_GET("debug/file_logging/max_log_files");
2262
}
2263
OS::get_singleton()->add_logger(memnew(RotatedFileLogger(base_path, max_files)));
2264
}
2265
2266
if (main_args.is_empty() && String(GLOBAL_GET("application/run/main_scene")) == "") {
2267
#ifdef TOOLS_ENABLED
2268
if (!editor && !project_manager) {
2269
#endif
2270
const String error_msg = "Error: Can't run project: no main scene defined in the project.\n";
2271
OS::get_singleton()->print("%s", error_msg.utf8().get_data());
2272
OS::get_singleton()->alert(error_msg);
2273
goto error;
2274
#ifdef TOOLS_ENABLED
2275
}
2276
#endif
2277
}
2278
2279
if (editor || project_manager) {
2280
Engine::get_singleton()->set_editor_hint(true);
2281
use_custom_res = false;
2282
input_map->load_default(); //keys for editor
2283
} else {
2284
input_map->load_from_project_settings(); //keys for game
2285
}
2286
2287
if (bool(GLOBAL_GET("application/run/disable_stdout"))) {
2288
quiet_stdout = true;
2289
}
2290
if (bool(GLOBAL_GET("application/run/disable_stderr"))) {
2291
CoreGlobals::print_error_enabled = false;
2292
}
2293
if (!bool(GLOBAL_GET("application/run/print_header"))) {
2294
// --no-header option for project settings.
2295
Engine::get_singleton()->_print_header = false;
2296
}
2297
2298
if (quiet_stdout) {
2299
CoreGlobals::print_line_enabled = false;
2300
}
2301
2302
Logger::set_flush_stdout_on_print(GLOBAL_GET("application/run/flush_stdout_on_print"));
2303
2304
// Rendering drivers configuration.
2305
2306
// Always include all supported drivers as hint, as this is used by the editor host platform
2307
// for project settings. For example, a Linux user should be able to configure that they want
2308
// to export for D3D12 on Windows and Metal on macOS even if their host platform can't use those.
2309
2310
{
2311
// RenderingDevice driver overrides per platform.
2312
GLOBAL_DEF_RST("rendering/rendering_device/driver", "vulkan");
2313
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.windows", PROPERTY_HINT_ENUM, "vulkan,d3d12"), "vulkan");
2314
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.linuxbsd", PROPERTY_HINT_ENUM, "vulkan"), "vulkan");
2315
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.android", PROPERTY_HINT_ENUM, "vulkan"), "vulkan");
2316
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.ios", PROPERTY_HINT_ENUM, "metal,vulkan"), "metal");
2317
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.visionos", PROPERTY_HINT_ENUM, "metal"), "metal");
2318
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.macos", PROPERTY_HINT_ENUM, "metal,vulkan"), "metal");
2319
2320
GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_vulkan", true);
2321
GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_d3d12", true);
2322
GLOBAL_DEF_RST("rendering/rendering_device/fallback_to_opengl3", true);
2323
}
2324
2325
{
2326
// GL Compatibility driver overrides per platform.
2327
GLOBAL_DEF_RST("rendering/gl_compatibility/driver", "opengl3");
2328
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ENUM, "opengl3,opengl3_angle"), "opengl3");
2329
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.linuxbsd", PROPERTY_HINT_ENUM, "opengl3,opengl3_es"), "opengl3");
2330
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.web", PROPERTY_HINT_ENUM, "opengl3"), "opengl3");
2331
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.android", PROPERTY_HINT_ENUM, "opengl3"), "opengl3");
2332
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.ios", PROPERTY_HINT_ENUM, "opengl3"), "opengl3");
2333
GLOBAL_DEF_RST(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, "opengl3,opengl3_angle"), "opengl3");
2334
2335
GLOBAL_DEF_RST("rendering/gl_compatibility/nvidia_disable_threaded_optimization", true);
2336
GLOBAL_DEF_RST("rendering/gl_compatibility/fallback_to_angle", true);
2337
GLOBAL_DEF_RST("rendering/gl_compatibility/fallback_to_native", true);
2338
GLOBAL_DEF_RST("rendering/gl_compatibility/fallback_to_gles", true);
2339
2340
Array force_angle_list;
2341
2342
#define FORCE_ANGLE(m_vendor, m_name) \
2343
{ \
2344
Dictionary device; \
2345
device["vendor"] = m_vendor; \
2346
device["name"] = m_name; \
2347
force_angle_list.push_back(device); \
2348
}
2349
2350
// AMD GPUs.
2351
FORCE_ANGLE("ATI", "Radeon 9"); // ATI Radeon 9000 Series
2352
FORCE_ANGLE("ATI", "Radeon X"); // ATI Radeon X500-X2000 Series
2353
FORCE_ANGLE("ATI", "Radeon HD 2"); // AMD/ATI (Mobility) Radeon HD 2xxx Series
2354
FORCE_ANGLE("ATI", "Radeon HD 3"); // AMD/ATI (Mobility) Radeon HD 3xxx Series
2355
FORCE_ANGLE("ATI", "Radeon HD 4"); // AMD/ATI (Mobility) Radeon HD 4xxx Series
2356
FORCE_ANGLE("ATI", "Radeon HD 5"); // AMD/ATI (Mobility) Radeon HD 5xxx Series
2357
FORCE_ANGLE("ATI", "Radeon HD 6"); // AMD/ATI (Mobility) Radeon HD 6xxx Series
2358
FORCE_ANGLE("ATI", "Radeon HD 7"); // AMD/ATI (Mobility) Radeon HD 7xxx Series
2359
FORCE_ANGLE("ATI", "Radeon HD 8"); // AMD/ATI (Mobility) Radeon HD 8xxx Series
2360
FORCE_ANGLE("ATI", "Radeon(TM) R2 Graphics"); // APUs
2361
FORCE_ANGLE("ATI", "Radeon(TM) R3 Graphics");
2362
FORCE_ANGLE("ATI", "Radeon(TM) R4 Graphics");
2363
FORCE_ANGLE("ATI", "Radeon(TM) R5 Graphics");
2364
FORCE_ANGLE("ATI", "Radeon(TM) R6 Graphics");
2365
FORCE_ANGLE("ATI", "Radeon(TM) R7 Graphics");
2366
FORCE_ANGLE("AMD", "Radeon(TM) R7 Graphics");
2367
FORCE_ANGLE("AMD", "Radeon(TM) R8 Graphics");
2368
FORCE_ANGLE("ATI", "Radeon R5 Graphics");
2369
FORCE_ANGLE("ATI", "Radeon R6 Graphics");
2370
FORCE_ANGLE("ATI", "Radeon R7 Graphics");
2371
FORCE_ANGLE("AMD", "Radeon R7 Graphics");
2372
FORCE_ANGLE("AMD", "Radeon R8 Graphics");
2373
FORCE_ANGLE("ATI", "Radeon R5 2"); // Rx 2xx Series
2374
FORCE_ANGLE("ATI", "Radeon R7 2");
2375
FORCE_ANGLE("ATI", "Radeon R9 2");
2376
FORCE_ANGLE("ATI", "Radeon R5 M2"); // Rx M2xx Series
2377
FORCE_ANGLE("ATI", "Radeon R7 M2");
2378
FORCE_ANGLE("ATI", "Radeon R9 M2");
2379
FORCE_ANGLE("ATI", "Radeon (TM) R9 Fury");
2380
FORCE_ANGLE("ATI", "Radeon (TM) R5 3"); // Rx 3xx Series
2381
FORCE_ANGLE("AMD", "Radeon (TM) R5 3");
2382
FORCE_ANGLE("ATI", "Radeon (TM) R7 3");
2383
FORCE_ANGLE("AMD", "Radeon (TM) R7 3");
2384
FORCE_ANGLE("ATI", "Radeon (TM) R9 3");
2385
FORCE_ANGLE("AMD", "Radeon (TM) R9 3");
2386
FORCE_ANGLE("ATI", "Radeon (TM) R5 M3"); // Rx M3xx Series
2387
FORCE_ANGLE("AMD", "Radeon (TM) R5 M3");
2388
FORCE_ANGLE("ATI", "Radeon (TM) R7 M3");
2389
FORCE_ANGLE("AMD", "Radeon (TM) R7 M3");
2390
FORCE_ANGLE("ATI", "Radeon (TM) R9 M3");
2391
FORCE_ANGLE("AMD", "Radeon (TM) R9 M3");
2392
2393
// Intel GPUs (Gen7-Gen9.5 devices).
2394
FORCE_ANGLE("Intel", "Intel(R) HD Graphics");
2395
FORCE_ANGLE("Intel", "Intel HD Graphics");
2396
FORCE_ANGLE("Intel", "Intel(R) Vallyview Graphics");
2397
FORCE_ANGLE("Intel", "Intel(R) Iris(TM) Graphics 5100");
2398
FORCE_ANGLE("Intel", "Intel(R) Iris(TM) Pro Graphics 5200");
2399
FORCE_ANGLE("Intel", "Intel(R) Iris(TM) Graphics 6100");
2400
FORCE_ANGLE("Intel", "Intel(R) Iris(TM) Pro Graphics 6200");
2401
FORCE_ANGLE("Intel", "Intel(R) Iris(TM) Pro Graphics P6300");
2402
FORCE_ANGLE("Intel", "Intel(R) Iris Graphics 540");
2403
FORCE_ANGLE("Intel", "Intel(R) Iris Plus Graphics 640");
2404
FORCE_ANGLE("Intel", "Intel(R) Iris Plus Graphics 650");
2405
FORCE_ANGLE("Intel", "Intel(R) Iris Pro Graphics 580");
2406
FORCE_ANGLE("Intel", "Intel(R) Iris Pro Graphics P580");
2407
2408
#undef FORCE_ANGLE
2409
2410
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())), force_angle_list);
2411
}
2412
2413
// Start with RenderingDevice-based backends.
2414
#ifdef RD_ENABLED
2415
renderer_hints = "forward_plus,mobile";
2416
default_renderer_mobile = "mobile";
2417
#endif
2418
2419
// And Compatibility next, or first if Vulkan is disabled.
2420
#ifdef GLES3_ENABLED
2421
if (!renderer_hints.is_empty()) {
2422
renderer_hints += ",";
2423
}
2424
renderer_hints += "gl_compatibility";
2425
if (default_renderer_mobile.is_empty()) {
2426
default_renderer_mobile = "gl_compatibility";
2427
}
2428
// Default to Compatibility when using the project manager.
2429
if (rendering_driver.is_empty() && rendering_method.is_empty() && project_manager) {
2430
rendering_driver = "opengl3";
2431
rendering_method = "gl_compatibility";
2432
default_renderer_mobile = "gl_compatibility";
2433
}
2434
#endif
2435
2436
if (!rendering_method.is_empty()) {
2437
if (rendering_method != "forward_plus" &&
2438
rendering_method != "mobile" &&
2439
rendering_method != "gl_compatibility" &&
2440
rendering_method != "dummy") {
2441
OS::get_singleton()->print("Unknown rendering method '%s', aborting.\nValid options are ",
2442
rendering_method.utf8().get_data());
2443
2444
Vector<String> rendering_method_hints = renderer_hints.split(",");
2445
rendering_method_hints.push_back("dummy");
2446
for (int i = 0; i < rendering_method_hints.size(); i++) {
2447
if (i == rendering_method_hints.size() - 1) {
2448
OS::get_singleton()->print(" and ");
2449
} else if (i != 0) {
2450
OS::get_singleton()->print(", ");
2451
}
2452
OS::get_singleton()->print("'%s'", rendering_method_hints[i].utf8().get_data());
2453
}
2454
2455
OS::get_singleton()->print(".\n");
2456
goto error;
2457
}
2458
}
2459
if (renderer_hints.is_empty()) {
2460
renderer_hints = "dummy";
2461
}
2462
2463
if (!rendering_driver.is_empty()) {
2464
// As the rendering drivers available may depend on the display driver and renderer
2465
// selected, we can't do an exhaustive check here, but we can look through all
2466
// the options in all the display drivers for a match.
2467
2468
bool found = false;
2469
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
2470
Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i);
2471
2472
for (int d = 0; d < r_drivers.size(); d++) {
2473
if (rendering_driver == r_drivers[d]) {
2474
found = true;
2475
break;
2476
}
2477
}
2478
}
2479
2480
if (!found) {
2481
OS::get_singleton()->print("Unknown rendering driver '%s', aborting.\nValid options are ",
2482
rendering_driver.utf8().get_data());
2483
2484
// Deduplicate driver entries, as a rendering driver may be supported by several display servers.
2485
Vector<String> unique_rendering_drivers;
2486
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
2487
Vector<String> r_drivers = DisplayServer::get_create_function_rendering_drivers(i);
2488
2489
for (int d = 0; d < r_drivers.size(); d++) {
2490
if (!unique_rendering_drivers.has(r_drivers[d])) {
2491
unique_rendering_drivers.append(r_drivers[d]);
2492
}
2493
}
2494
}
2495
2496
for (int i = 0; i < unique_rendering_drivers.size(); i++) {
2497
if (i == unique_rendering_drivers.size() - 1) {
2498
OS::get_singleton()->print(" and ");
2499
} else if (i != 0) {
2500
OS::get_singleton()->print(", ");
2501
}
2502
OS::get_singleton()->print("'%s'", unique_rendering_drivers[i].utf8().get_data());
2503
}
2504
2505
OS::get_singleton()->print(".\n");
2506
2507
goto error;
2508
}
2509
2510
// Set a default renderer if none selected. Try to choose one that matches the driver.
2511
if (rendering_method.is_empty()) {
2512
if (rendering_driver == "dummy") {
2513
rendering_method = "dummy";
2514
} else if (rendering_driver == "opengl3" || rendering_driver == "opengl3_angle" || rendering_driver == "opengl3_es") {
2515
rendering_method = "gl_compatibility";
2516
} else {
2517
rendering_method = "forward_plus";
2518
}
2519
}
2520
2521
// Now validate whether the selected driver matches with the renderer.
2522
bool valid_combination = false;
2523
Vector<String> available_drivers;
2524
if (rendering_method == "forward_plus" || rendering_method == "mobile") {
2525
#ifdef VULKAN_ENABLED
2526
available_drivers.push_back("vulkan");
2527
#endif
2528
#ifdef D3D12_ENABLED
2529
available_drivers.push_back("d3d12");
2530
#endif
2531
#ifdef METAL_ENABLED
2532
available_drivers.push_back("metal");
2533
#endif
2534
}
2535
#ifdef GLES3_ENABLED
2536
if (rendering_method == "gl_compatibility") {
2537
available_drivers.push_back("opengl3");
2538
available_drivers.push_back("opengl3_angle");
2539
available_drivers.push_back("opengl3_es");
2540
}
2541
#endif
2542
if (rendering_method == "dummy") {
2543
available_drivers.push_back("dummy");
2544
}
2545
if (available_drivers.is_empty()) {
2546
OS::get_singleton()->print("Unknown renderer name '%s', aborting.\n", rendering_method.utf8().get_data());
2547
goto error;
2548
}
2549
2550
for (int i = 0; i < available_drivers.size(); i++) {
2551
if (rendering_driver == available_drivers[i]) {
2552
valid_combination = true;
2553
break;
2554
}
2555
}
2556
2557
if (!valid_combination) {
2558
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());
2559
2560
for (int d = 0; d < available_drivers.size(); d++) {
2561
OS::get_singleton()->print("'%s', ", available_drivers[d].utf8().get_data());
2562
}
2563
2564
OS::get_singleton()->print(".\n");
2565
2566
goto error;
2567
}
2568
}
2569
2570
default_renderer = renderer_hints.get_slicec(',', 0);
2571
GLOBAL_DEF_RST_BASIC(PropertyInfo(Variant::STRING, "rendering/renderer/rendering_method", PROPERTY_HINT_ENUM, renderer_hints), default_renderer);
2572
GLOBAL_DEF_RST_BASIC("rendering/renderer/rendering_method.mobile", default_renderer_mobile);
2573
GLOBAL_DEF_RST_BASIC(PropertyInfo(Variant::STRING, "rendering/renderer/rendering_method.web", PROPERTY_HINT_ENUM, "gl_compatibility"), "gl_compatibility"); // This is a bit of a hack until we have WebGPU support.
2574
2575
// Default to ProjectSettings default if nothing set on the command line.
2576
if (rendering_method.is_empty()) {
2577
rendering_method = GLOBAL_GET("rendering/renderer/rendering_method");
2578
rendering_method_source = OS::RenderingSource::RENDERING_SOURCE_PROJECT_SETTING;
2579
}
2580
2581
if (rendering_driver.is_empty()) {
2582
if (rendering_method == "dummy") {
2583
rendering_driver = "dummy";
2584
} else if (rendering_method == "gl_compatibility") {
2585
rendering_driver = GLOBAL_GET("rendering/gl_compatibility/driver");
2586
rendering_driver_source = OS::RenderingSource::RENDERING_SOURCE_PROJECT_SETTING;
2587
} else {
2588
rendering_driver = GLOBAL_GET("rendering/rendering_device/driver");
2589
rendering_driver_source = OS::RenderingSource::RENDERING_SOURCE_PROJECT_SETTING;
2590
}
2591
}
2592
2593
// always convert to lower case for consistency in the code
2594
rendering_driver = rendering_driver.to_lower();
2595
2596
OS::get_singleton()->set_current_rendering_driver_name(rendering_driver, rendering_driver_source);
2597
OS::get_singleton()->set_current_rendering_method(rendering_method, rendering_method_source);
2598
2599
#ifdef TOOLS_ENABLED
2600
if (!force_res && project_manager) {
2601
// Ensure splash screen size matches the project manager window size
2602
// (see `editor/project_manager.cpp` for defaults).
2603
window_size.width = ProjectManager::DEFAULT_WINDOW_WIDTH;
2604
window_size.height = ProjectManager::DEFAULT_WINDOW_HEIGHT;
2605
}
2606
#endif
2607
2608
if (use_custom_res) {
2609
if (!force_res) {
2610
window_size.width = GLOBAL_GET("display/window/size/viewport_width");
2611
window_size.height = GLOBAL_GET("display/window/size/viewport_height");
2612
2613
if (globals->has_setting("display/window/size/window_width_override") &&
2614
globals->has_setting("display/window/size/window_height_override")) {
2615
int desired_width = GLOBAL_GET("display/window/size/window_width_override");
2616
if (desired_width > 0) {
2617
window_size.width = desired_width;
2618
}
2619
int desired_height = GLOBAL_GET("display/window/size/window_height_override");
2620
if (desired_height > 0) {
2621
window_size.height = desired_height;
2622
}
2623
}
2624
}
2625
2626
if (!bool(GLOBAL_GET("display/window/size/resizable"))) {
2627
window_flags |= DisplayServer::WINDOW_FLAG_RESIZE_DISABLED_BIT;
2628
}
2629
if (bool(GLOBAL_GET("display/window/size/minimize_disabled"))) {
2630
window_flags |= DisplayServer::WINDOW_FLAG_MINIMIZE_DISABLED_BIT;
2631
}
2632
if (bool(GLOBAL_GET("display/window/size/maximize_disabled"))) {
2633
window_flags |= DisplayServer::WINDOW_FLAG_MAXIMIZE_DISABLED_BIT;
2634
}
2635
if (bool(GLOBAL_GET("display/window/size/borderless"))) {
2636
window_flags |= DisplayServer::WINDOW_FLAG_BORDERLESS_BIT;
2637
}
2638
if (bool(GLOBAL_GET("display/window/size/always_on_top"))) {
2639
window_flags |= DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP_BIT;
2640
}
2641
if (bool(GLOBAL_GET("display/window/size/transparent"))) {
2642
window_flags |= DisplayServer::WINDOW_FLAG_TRANSPARENT_BIT;
2643
}
2644
if (bool(GLOBAL_GET("display/window/size/extend_to_title"))) {
2645
window_flags |= DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE_BIT;
2646
}
2647
if (bool(GLOBAL_GET("display/window/size/no_focus"))) {
2648
window_flags |= DisplayServer::WINDOW_FLAG_NO_FOCUS_BIT;
2649
}
2650
if (bool(GLOBAL_GET("display/window/size/sharp_corners"))) {
2651
window_flags |= DisplayServer::WINDOW_FLAG_SHARP_CORNERS_BIT;
2652
}
2653
window_mode = (DisplayServer::WindowMode)(GLOBAL_GET("display/window/size/mode").operator int());
2654
int initial_position_type = GLOBAL_GET("display/window/size/initial_position_type").operator int();
2655
if (initial_position_type == Window::WINDOW_INITIAL_POSITION_ABSOLUTE) { // Absolute.
2656
if (!init_use_custom_pos) {
2657
init_custom_pos = GLOBAL_GET("display/window/size/initial_position").operator Vector2i();
2658
init_use_custom_pos = true;
2659
}
2660
} else if (initial_position_type == Window::WINDOW_INITIAL_POSITION_CENTER_PRIMARY_SCREEN || initial_position_type == Window::WINDOW_INITIAL_POSITION_CENTER_MAIN_WINDOW_SCREEN) { // Center of Primary Screen.
2661
if (!init_use_custom_screen) {
2662
init_screen = DisplayServer::SCREEN_PRIMARY;
2663
init_use_custom_screen = true;
2664
}
2665
} else if (initial_position_type == Window::WINDOW_INITIAL_POSITION_CENTER_OTHER_SCREEN) { // Center of Other Screen.
2666
if (!init_use_custom_screen) {
2667
init_screen = GLOBAL_GET("display/window/size/initial_screen").operator int();
2668
init_use_custom_screen = true;
2669
}
2670
} else if (initial_position_type == Window::WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_MOUSE_FOCUS) { // Center of Screen With Mouse Pointer.
2671
if (!init_use_custom_screen) {
2672
init_screen = DisplayServer::SCREEN_WITH_MOUSE_FOCUS;
2673
init_use_custom_screen = true;
2674
}
2675
} else if (initial_position_type == Window::WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_KEYBOARD_FOCUS) { // Center of Screen With Keyboard Focus.
2676
if (!init_use_custom_screen) {
2677
init_screen = DisplayServer::SCREEN_WITH_KEYBOARD_FOCUS;
2678
init_use_custom_screen = true;
2679
}
2680
}
2681
}
2682
2683
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", true);
2684
OS::get_singleton()->_allow_layered = GLOBAL_DEF_RST("display/window/per_pixel_transparency/allowed", false);
2685
2686
load_shell_env = GLOBAL_DEF("application/run/load_shell_environment", false);
2687
2688
#ifdef TOOLS_ENABLED
2689
if (editor || project_manager) {
2690
// The editor and project manager always detect and use hiDPI if needed.
2691
OS::get_singleton()->_allow_hidpi = true;
2692
load_shell_env = true;
2693
}
2694
#endif
2695
if (load_shell_env) {
2696
OS::get_singleton()->load_shell_environment();
2697
}
2698
2699
if (separate_thread_render == -1) {
2700
separate_thread_render = (int)GLOBAL_DEF("rendering/driver/threads/thread_model", OS::RENDER_THREAD_SAFE) == OS::RENDER_SEPARATE_THREAD;
2701
}
2702
2703
if (editor || project_manager) {
2704
// Editor and project manager cannot run with rendering in a separate thread (they will crash on startup).
2705
separate_thread_render = 0;
2706
}
2707
#if !defined(THREADS_ENABLED)
2708
separate_thread_render = 0;
2709
#endif
2710
OS::get_singleton()->_separate_thread_render = separate_thread_render;
2711
2712
/* Determine audio and video drivers */
2713
2714
// Display driver, e.g. X11, Wayland.
2715
// Make sure that headless is the last one, which it is assumed to be by design.
2716
DEV_ASSERT(NULL_DISPLAY_DRIVER == DisplayServer::get_create_function_name(DisplayServer::get_create_function_count() - 1));
2717
2718
GLOBAL_DEF_NOVAL("display/display_server/driver", "default");
2719
GLOBAL_DEF_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.windows", PROPERTY_HINT_ENUM, "default,windows,headless"), "default");
2720
GLOBAL_DEF_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.linuxbsd", PROPERTY_HINT_ENUM, "default,x11,wayland,headless"), "default");
2721
GLOBAL_DEF_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.android", PROPERTY_HINT_ENUM, "default,android,headless"), "default");
2722
GLOBAL_DEF_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.ios", PROPERTY_HINT_ENUM, "default,iOS,headless"), "default");
2723
GLOBAL_DEF_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.visionos", PROPERTY_HINT_ENUM, "default,visionOS,headless"), "default");
2724
GLOBAL_DEF_NOVAL(PropertyInfo(Variant::STRING, "display/display_server/driver.macos", PROPERTY_HINT_ENUM, "default,macos,headless"), "default");
2725
2726
GLOBAL_DEF_RST_NOVAL("audio/driver/driver", AudioDriverManager::get_driver(0)->get_name());
2727
if (audio_driver.is_empty()) { // Specified in project.godot.
2728
if (project_manager) {
2729
// The project manager doesn't need to play sound (TTS audio output is not emitted by Godot, but by the system itself).
2730
// Disable audio output so it doesn't appear in the list of applications outputting sound in the OS.
2731
// On macOS, this also prevents the project manager from inhibiting suspend.
2732
audio_driver = "Dummy";
2733
} else {
2734
audio_driver = GLOBAL_GET("audio/driver/driver");
2735
}
2736
}
2737
2738
// Make sure that dummy is the last one, which it is assumed to be by design.
2739
DEV_ASSERT(NULL_AUDIO_DRIVER == AudioDriverManager::get_driver(AudioDriverManager::get_driver_count() - 1)->get_name());
2740
for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
2741
if (audio_driver == AudioDriverManager::get_driver(i)->get_name()) {
2742
audio_driver_idx = i;
2743
break;
2744
}
2745
}
2746
2747
if (audio_driver_idx < 0) {
2748
// If the requested driver wasn't found, pick the first entry.
2749
// If all else failed it would be the dummy driver (no sound).
2750
audio_driver_idx = 0;
2751
}
2752
2753
if (Engine::get_singleton()->get_write_movie_path() != String()) {
2754
// Always use dummy driver for audio driver (which is last), also in no threaded mode.
2755
audio_driver_idx = AudioDriverManager::get_driver_count() - 1;
2756
AudioDriverDummy::get_dummy_singleton()->set_use_threads(false);
2757
}
2758
2759
{
2760
window_orientation = DisplayServer::ScreenOrientation(int(GLOBAL_DEF_BASIC("display/window/handheld/orientation", DisplayServer::ScreenOrientation::SCREEN_LANDSCAPE)));
2761
}
2762
{
2763
window_vsync_mode = DisplayServer::VSyncMode(int(GLOBAL_DEF_BASIC("display/window/vsync/vsync_mode", DisplayServer::VSyncMode::VSYNC_ENABLED)));
2764
if (disable_vsync) {
2765
window_vsync_mode = DisplayServer::VSyncMode::VSYNC_DISABLED;
2766
}
2767
}
2768
2769
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "audio/driver/output_latency", PROPERTY_HINT_RANGE, "1,100,1"), 15);
2770
// Use a safer default output_latency for web to avoid audio cracking on low-end devices, especially mobile.
2771
GLOBAL_DEF_RST("audio/driver/output_latency.web", 50);
2772
2773
Engine::get_singleton()->set_audio_output_latency(GLOBAL_GET("audio/driver/output_latency"));
2774
2775
#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
2776
OS::get_singleton()->set_environment("MVK_CONFIG_LOG_LEVEL", OS::get_singleton()->_verbose_stdout ? "3" : "1"); // 1 = Errors only, 3 = Info
2777
#endif
2778
2779
if (frame_delay == 0) {
2780
frame_delay = GLOBAL_DEF(PropertyInfo(Variant::INT, "application/run/frame_delay_msec", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), 0);
2781
if (Engine::get_singleton()->is_editor_hint()) {
2782
frame_delay = 0;
2783
}
2784
}
2785
2786
if (audio_output_latency >= 1) {
2787
Engine::get_singleton()->set_audio_output_latency(audio_output_latency);
2788
}
2789
2790
GLOBAL_DEF("display/window/ios/allow_high_refresh_rate", true);
2791
GLOBAL_DEF("display/window/ios/hide_home_indicator", true);
2792
GLOBAL_DEF("display/window/ios/hide_status_bar", true);
2793
GLOBAL_DEF("display/window/ios/suppress_ui_gesture", true);
2794
2795
#ifndef _3D_DISABLED
2796
// XR project settings.
2797
GLOBAL_DEF_RST_BASIC("xr/openxr/enabled", false);
2798
GLOBAL_DEF(PropertyInfo(Variant::STRING, "xr/openxr/target_api_version"), "");
2799
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "xr/openxr/default_action_map", PROPERTY_HINT_FILE, "*.tres"), "res://openxr_action_map.tres");
2800
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/form_factor", PROPERTY_HINT_ENUM, "Head Mounted,Handheld"), "0");
2801
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/view_configuration", PROPERTY_HINT_ENUM, "Mono,Stereo"), "1"); // "Mono,Stereo,Quad,Observer"
2802
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/reference_space", PROPERTY_HINT_ENUM, "Local,Stage,Local Floor"), "1");
2803
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/environment_blend_mode", PROPERTY_HINT_ENUM, "Opaque,Additive,Alpha"), "0");
2804
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/foveation_level", PROPERTY_HINT_ENUM, "Off,Low,Medium,High"), "0");
2805
GLOBAL_DEF_BASIC("xr/openxr/foveation_dynamic", false);
2806
2807
GLOBAL_DEF_BASIC("xr/openxr/submit_depth_buffer", false);
2808
GLOBAL_DEF_BASIC("xr/openxr/startup_alert", true);
2809
2810
// OpenXR project extensions settings.
2811
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/extensions/debug_utils", PROPERTY_HINT_ENUM, "Disabled,Error,Warning,Info,Verbose"), "0");
2812
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/extensions/debug_message_types", PROPERTY_HINT_FLAGS, "General,Validation,Performance,Conformance"), "15");
2813
GLOBAL_DEF_BASIC("xr/openxr/extensions/frame_synthesis", false);
2814
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking", false);
2815
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_unobstructed_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_UNOBSTRUCTED_EXT
2816
GLOBAL_DEF_BASIC("xr/openxr/extensions/hand_tracking_controller_data_source", false); // XR_HAND_TRACKING_DATA_SOURCE_CONTROLLER_EXT
2817
GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/hand_interaction_profile", false);
2818
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enabled", false);
2819
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_spatial_anchors", false);
2820
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_persistent_anchors", false);
2821
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_builtin_anchor_detection", false);
2822
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_plane_tracking", false);
2823
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_builtin_plane_detection", false);
2824
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_marker_tracking", false);
2825
GLOBAL_DEF_BASIC("xr/openxr/extensions/spatial_entity/enable_builtin_marker_tracking", false);
2826
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/extensions/spatial_entity/aruco_dict", PROPERTY_HINT_ENUM, "4x4 50 IDs,4x4 100 IDs,4x4 250 IDs,4x4 1000 IDs,5x5 50 IDs,5x5 100 IDs,5x5 250 IDs,5x5 1000 IDs,6x6 50 IDs,6x6 100 IDs,6x6 250 IDs,6x6 1000 IDs,7x7 50 IDs,7x7 100 IDs,7x7 250 IDs,7x7 1000 IDs"), "15");
2827
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/extensions/spatial_entity/april_tag_dict", PROPERTY_HINT_ENUM, "4x4H5,5x5H9,6x6H10,6x6H11"), "3");
2828
GLOBAL_DEF_RST_BASIC("xr/openxr/extensions/eye_gaze_interaction", false);
2829
GLOBAL_DEF_BASIC("xr/openxr/extensions/render_model", false);
2830
GLOBAL_DEF_BASIC("xr/openxr/extensions/user_presence", false);
2831
2832
// OpenXR Binding modifier settings
2833
GLOBAL_DEF_BASIC("xr/openxr/binding_modifiers/analog_threshold", false);
2834
GLOBAL_DEF_RST_BASIC("xr/openxr/binding_modifiers/dpad_binding", false);
2835
2836
#ifdef TOOLS_ENABLED
2837
// Disabled for now, using XR inside of the editor we'll be working on during the coming months.
2838
2839
// editor settings (it seems we're too early in the process when setting up rendering, to access editor settings...)
2840
// EDITOR_DEF_RST("xr/openxr/in_editor", false);
2841
// GLOBAL_DEF("xr/openxr/in_editor", false);
2842
#endif // TOOLS_ENABLED
2843
#endif // _3D_DISABLED
2844
2845
Engine::get_singleton()->set_frame_delay(frame_delay);
2846
2847
message_queue = memnew(MessageQueue);
2848
2849
Thread::release_main_thread(); // If setup2() is called from another thread, that one will become main thread, so preventively release this one.
2850
set_current_thread_safe_for_nodes(false);
2851
2852
#if defined(STEAMAPI_ENABLED)
2853
if (editor || project_manager) {
2854
steam_tracker = memnew(SteamTracker);
2855
}
2856
#endif
2857
2858
OS::get_singleton()->benchmark_end_measure("Startup", "Main::Setup");
2859
2860
if (p_second_phase) {
2861
exit_err = setup2();
2862
if (exit_err != OK) {
2863
goto error;
2864
}
2865
}
2866
2867
return OK;
2868
2869
error:
2870
2871
text_driver = "";
2872
display_driver = "";
2873
audio_driver = "";
2874
tablet_driver = "";
2875
Engine::get_singleton()->set_write_movie_path(String());
2876
project_path = "";
2877
2878
args.clear();
2879
main_args.clear();
2880
2881
if (show_help) {
2882
print_help(execpath);
2883
}
2884
2885
if (editor) {
2886
OS::get_singleton()->remove_lock_file();
2887
}
2888
2889
EngineDebugger::deinitialize();
2890
2891
if (performance) {
2892
memdelete(performance);
2893
}
2894
if (input_map) {
2895
memdelete(input_map);
2896
}
2897
if (translation_server) {
2898
memdelete(translation_server);
2899
}
2900
if (globals) {
2901
memdelete(globals);
2902
}
2903
if (packed_data) {
2904
memdelete(packed_data);
2905
}
2906
2907
unregister_core_driver_types();
2908
unregister_core_extensions();
2909
2910
if (engine) {
2911
memdelete(engine);
2912
}
2913
2914
unregister_core_types();
2915
2916
OS::get_singleton()->_cmdline.clear();
2917
OS::get_singleton()->_user_args.clear();
2918
2919
if (message_queue) {
2920
memdelete(message_queue);
2921
}
2922
2923
OS::get_singleton()->benchmark_end_measure("Startup", "Main::Setup");
2924
2925
#if defined(STEAMAPI_ENABLED)
2926
if (steam_tracker) {
2927
memdelete(steam_tracker);
2928
}
2929
#endif
2930
2931
OS::get_singleton()->finalize_core();
2932
locale = String();
2933
2934
return exit_err;
2935
}
2936
2937
Error _parse_resource_dummy(void *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
2938
VariantParser::Token token;
2939
VariantParser::get_token(p_stream, token, line, r_err_str);
2940
if (token.type != VariantParser::TK_NUMBER && token.type != VariantParser::TK_STRING) {
2941
r_err_str = "Expected number (old style sub-resource index) or String (ext-resource ID)";
2942
return ERR_PARSE_ERROR;
2943
}
2944
2945
r_res.unref();
2946
2947
VariantParser::get_token(p_stream, token, line, r_err_str);
2948
if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
2949
r_err_str = "Expected ')'";
2950
return ERR_PARSE_ERROR;
2951
}
2952
2953
return OK;
2954
}
2955
2956
Error Main::setup2(bool p_show_boot_logo) {
2957
GodotProfileZone("setup2");
2958
OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Setup2");
2959
2960
Thread::make_main_thread(); // Make whatever thread call this the main thread.
2961
set_current_thread_safe_for_nodes(true);
2962
2963
// Don't use rich formatting to prevent ANSI escape codes from being written to log files.
2964
print_header(false);
2965
2966
#ifdef TOOLS_ENABLED
2967
int accessibility_mode_editor = 0;
2968
int tablet_driver_editor = -1;
2969
if (editor || project_manager || cmdline_tool) {
2970
OS::get_singleton()->benchmark_begin_measure("Startup", "Initialize Early Settings");
2971
2972
EditorPaths::create();
2973
2974
// Editor setting class is not available, load config directly.
2975
if (!init_use_custom_screen && (editor || project_manager) && EditorPaths::get_singleton()->are_paths_valid()) {
2976
ERR_FAIL_COND_V(!DirAccess::dir_exists_absolute(EditorPaths::get_singleton()->get_config_dir()), FAILED);
2977
2978
String config_file_path = EditorSettings::get_existing_settings_path();
2979
if (FileAccess::exists(config_file_path)) {
2980
Error err;
2981
Ref<FileAccess> f = FileAccess::open(config_file_path, FileAccess::READ, &err);
2982
if (f.is_valid()) {
2983
VariantParser::StreamFile stream;
2984
stream.f = f;
2985
2986
String assign;
2987
Variant value;
2988
VariantParser::Tag next_tag;
2989
2990
int lines = 0;
2991
String error_text;
2992
2993
VariantParser::ResourceParser rp_new;
2994
rp_new.ext_func = _parse_resource_dummy;
2995
rp_new.sub_func = _parse_resource_dummy;
2996
2997
bool screen_found = false;
2998
String screen_property;
2999
3000
bool prefer_wayland_found = false;
3001
bool prefer_wayland = false;
3002
3003
bool tablet_found = false;
3004
3005
bool ac_found = false;
3006
3007
if (editor) {
3008
screen_property = "interface/editor/editor_screen";
3009
} else if (project_manager) {
3010
screen_property = "interface/editor/project_manager_screen";
3011
} else {
3012
// Skip.
3013
screen_found = true;
3014
}
3015
3016
if (!display_driver.is_empty()) {
3017
// Skip.
3018
prefer_wayland_found = true;
3019
}
3020
3021
while (!screen_found || !init_expand_to_title_found || !init_display_scale_found || !init_custom_scale_found || !prefer_wayland_found || !tablet_found || !ac_found) {
3022
assign = Variant();
3023
next_tag.fields.clear();
3024
next_tag.name = String();
3025
3026
err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp_new, true);
3027
if (err == ERR_FILE_EOF) {
3028
break;
3029
}
3030
3031
if (err == OK && !assign.is_empty()) {
3032
if (!screen_found && assign == screen_property) {
3033
init_screen = value;
3034
screen_found = true;
3035
3036
if (editor) {
3037
restore_editor_window_layout = value.operator int() == EditorSettings::InitialScreen::INITIAL_SCREEN_AUTO;
3038
}
3039
}
3040
if (!ac_found && assign == "interface/accessibility/accessibility_support") {
3041
accessibility_mode_editor = value;
3042
ac_found = true;
3043
} else if (!init_expand_to_title_found && assign == "interface/editor/expand_to_title") {
3044
init_expand_to_title = value;
3045
init_expand_to_title_found = true;
3046
} else if (!init_display_scale_found && assign == "interface/editor/display_scale") {
3047
init_display_scale = value;
3048
init_display_scale_found = true;
3049
} else if (!init_custom_scale_found && assign == "interface/editor/custom_display_scale") {
3050
init_custom_scale = value;
3051
init_custom_scale_found = true;
3052
} else if (!prefer_wayland_found && assign == "run/platforms/linuxbsd/prefer_wayland") {
3053
prefer_wayland = value;
3054
prefer_wayland_found = true;
3055
} else if (!tablet_found && assign == "interface/editor/tablet_driver") {
3056
tablet_driver_editor = value;
3057
tablet_found = true;
3058
}
3059
}
3060
}
3061
3062
if (display_driver.is_empty()) {
3063
if (prefer_wayland) {
3064
display_driver = "wayland";
3065
} else {
3066
display_driver = "default";
3067
}
3068
}
3069
}
3070
}
3071
}
3072
3073
if (found_project && EditorPaths::get_singleton()->is_self_contained()) {
3074
if (ProjectSettings::get_singleton()->get_resource_path() == OS::get_singleton()->get_executable_path().get_base_dir()) {
3075
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.");
3076
OS::get_singleton()->set_exit_code(EXIT_FAILURE);
3077
return FAILED;
3078
}
3079
}
3080
3081
bool has_command_line_window_override = init_use_custom_pos || init_use_custom_screen || init_windowed;
3082
if (editor && !has_command_line_window_override && restore_editor_window_layout) {
3083
Ref<ConfigFile> config;
3084
config.instantiate();
3085
// Load and amend existing config if it exists.
3086
Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
3087
if (err == OK) {
3088
init_screen = config->get_value("EditorWindow", "screen", init_screen);
3089
String mode = config->get_value("EditorWindow", "mode", "maximized");
3090
window_size = config->get_value("EditorWindow", "size", window_size);
3091
if (mode == "windowed") {
3092
window_mode = DisplayServer::WINDOW_MODE_WINDOWED;
3093
init_windowed = true;
3094
} else if (mode == "fullscreen") {
3095
window_mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
3096
init_fullscreen = true;
3097
} else {
3098
window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
3099
init_maximized = true;
3100
}
3101
3102
if (init_windowed) {
3103
init_use_custom_pos = true;
3104
init_custom_pos = config->get_value("EditorWindow", "position", Vector2i(0, 0));
3105
}
3106
}
3107
}
3108
3109
if (init_screen == EditorSettings::InitialScreen::INITIAL_SCREEN_AUTO) {
3110
init_screen = DisplayServer::SCREEN_PRIMARY;
3111
}
3112
3113
OS::get_singleton()->benchmark_end_measure("Startup", "Initialize Early Settings");
3114
}
3115
#endif
3116
3117
OS::get_singleton()->benchmark_begin_measure("Startup", "Servers");
3118
3119
tsman = memnew(TextServerManager);
3120
if (tsman) {
3121
Ref<TextServerDummy> ts;
3122
ts.instantiate();
3123
tsman->add_interface(ts);
3124
}
3125
3126
#ifndef PHYSICS_3D_DISABLED
3127
physics_server_3d_manager = memnew(PhysicsServer3DManager);
3128
#endif // PHYSICS_3D_DISABLED
3129
#ifndef PHYSICS_2D_DISABLED
3130
physics_server_2d_manager = memnew(PhysicsServer2DManager);
3131
#endif // PHYSICS_2D_DISABLED
3132
3133
#ifndef NAVIGATION_2D_DISABLED
3134
NavigationServer2DManager::initialize_server_manager();
3135
#endif // NAVIGATION_2D_DISABLED
3136
#ifndef NAVIGATION_3D_DISABLED
3137
NavigationServer3DManager::initialize_server_manager();
3138
#endif // NAVIGATION_3D_DISABLED
3139
3140
register_server_types();
3141
{
3142
OS::get_singleton()->benchmark_begin_measure("Servers", "Modules and Extensions");
3143
3144
initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
3145
GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
3146
3147
OS::get_singleton()->benchmark_end_measure("Servers", "Modules and Extensions");
3148
}
3149
3150
/* Initialize Input */
3151
3152
{
3153
OS::get_singleton()->benchmark_begin_measure("Servers", "Input");
3154
3155
input = memnew(Input);
3156
OS::get_singleton()->initialize_joypads();
3157
3158
OS::get_singleton()->benchmark_end_measure("Servers", "Input");
3159
}
3160
3161
/* Initialize Display Server */
3162
3163
{
3164
OS::get_singleton()->benchmark_begin_measure("Servers", "Display");
3165
3166
if (display_driver.is_empty()) {
3167
display_driver = GLOBAL_GET("display/display_server/driver");
3168
}
3169
3170
int display_driver_idx = -1;
3171
3172
if (display_driver.is_empty() || display_driver == "default") {
3173
display_driver_idx = 0;
3174
} else {
3175
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
3176
String name = DisplayServer::get_create_function_name(i);
3177
if (display_driver == name) {
3178
display_driver_idx = i;
3179
break;
3180
}
3181
}
3182
3183
if (display_driver_idx < 0) {
3184
// If the requested driver wasn't found, pick the first entry.
3185
// If all else failed it would be the headless server.
3186
display_driver_idx = 0;
3187
}
3188
}
3189
3190
Vector2i *window_position = nullptr;
3191
Vector2i position = init_custom_pos;
3192
if (init_use_custom_pos) {
3193
window_position = &position;
3194
}
3195
3196
Color boot_bg_color = GLOBAL_DEF_BASIC("application/boot_splash/bg_color", boot_splash_bg_color);
3197
DisplayServer::set_early_window_clear_color_override(true, boot_bg_color);
3198
3199
DisplayServer::Context context;
3200
if (editor) {
3201
context = DisplayServer::CONTEXT_EDITOR;
3202
} else if (project_manager) {
3203
context = DisplayServer::CONTEXT_PROJECTMAN;
3204
} else {
3205
context = DisplayServer::CONTEXT_ENGINE;
3206
}
3207
3208
if (init_embed_parent_window_id) {
3209
// Reset flags and other settings to be sure it's borderless and windowed. The position and size should have been initialized correctly
3210
// from --position and --resolution parameters.
3211
window_mode = DisplayServer::WINDOW_MODE_WINDOWED;
3212
window_flags = DisplayServer::WINDOW_FLAG_BORDERLESS_BIT;
3213
if (bool(GLOBAL_GET("display/window/size/transparent"))) {
3214
window_flags |= DisplayServer::WINDOW_FLAG_TRANSPARENT_BIT;
3215
}
3216
}
3217
3218
#ifdef TOOLS_ENABLED
3219
if ((project_manager || editor) && init_expand_to_title) {
3220
window_flags |= DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE_BIT;
3221
}
3222
#endif
3223
3224
if (!accessibility_mode_set) {
3225
#ifdef TOOLS_ENABLED
3226
if (editor || project_manager || cmdline_tool) {
3227
accessibility_mode = (DisplayServer::AccessibilityMode)accessibility_mode_editor;
3228
} else {
3229
#else
3230
{
3231
#endif
3232
accessibility_mode = (DisplayServer::AccessibilityMode)GLOBAL_GET("accessibility/general/accessibility_support").operator int64_t();
3233
}
3234
}
3235
DisplayServer::accessibility_set_mode(accessibility_mode);
3236
3237
String rendering_driver = OS::get_singleton()->get_current_rendering_driver_name();
3238
Error err;
3239
display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, init_screen, context, init_embed_parent_window_id, err);
3240
if (err != OK || display_server == nullptr) {
3241
String last_name = DisplayServer::get_create_function_name(display_driver_idx);
3242
3243
// We can't use this display server, try other ones as fallback.
3244
// Skip headless (always last registered) because that's not what users
3245
// would expect if they didn't request it explicitly.
3246
for (int i = 0; i < DisplayServer::get_create_function_count() - 1; i++) {
3247
if (i == display_driver_idx) {
3248
continue; // Don't try the same twice.
3249
}
3250
String name = DisplayServer::get_create_function_name(i);
3251
WARN_PRINT(vformat("Display driver %s failed, falling back to %s.", last_name, name));
3252
3253
display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_position, window_size, init_screen, context, init_embed_parent_window_id, err);
3254
if (err == OK && display_server != nullptr) {
3255
break;
3256
}
3257
}
3258
}
3259
3260
if (err != OK || display_server == nullptr) {
3261
ERR_PRINT("Unable to create DisplayServer, all display drivers failed.\nUse \"--headless\" command line argument to run the engine in headless mode if this is desired (e.g. for continuous integration).");
3262
3263
if (display_server) {
3264
memdelete(display_server);
3265
}
3266
3267
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
3268
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
3269
unregister_server_types();
3270
3271
if (input) {
3272
memdelete(input);
3273
}
3274
if (tsman) {
3275
memdelete(tsman);
3276
}
3277
#ifndef PHYSICS_3D_DISABLED
3278
if (physics_server_3d_manager) {
3279
memdelete(physics_server_3d_manager);
3280
}
3281
#endif // PHYSICS_3D_DISABLED
3282
#ifndef PHYSICS_2D_DISABLED
3283
if (physics_server_2d_manager) {
3284
memdelete(physics_server_2d_manager);
3285
}
3286
#endif // PHYSICS_2D_DISABLED
3287
3288
return err;
3289
}
3290
3291
#ifdef TOOLS_ENABLED
3292
if (project_manager) {
3293
float ui_scale = init_custom_scale;
3294
switch (init_display_scale) {
3295
case 0:
3296
ui_scale = EditorSettings::get_auto_display_scale();
3297
break;
3298
case 1:
3299
ui_scale = 0.75;
3300
break;
3301
case 2:
3302
ui_scale = 1.0;
3303
break;
3304
case 3:
3305
ui_scale = 1.25;
3306
break;
3307
case 4:
3308
ui_scale = 1.5;
3309
break;
3310
case 5:
3311
ui_scale = 1.75;
3312
break;
3313
case 6:
3314
ui_scale = 2.0;
3315
break;
3316
default:
3317
break;
3318
}
3319
if (!(force_res || use_custom_res)) {
3320
display_server->window_set_size(Size2(window_size) * ui_scale, DisplayServer::MAIN_WINDOW_ID);
3321
}
3322
if (display_server->has_feature(DisplayServer::FEATURE_SUBWINDOWS) && !display_server->has_feature(DisplayServer::FEATURE_SELF_FITTING_WINDOWS)) {
3323
Size2 real_size = DisplayServer::get_singleton()->window_get_size();
3324
Rect2i scr_rect = display_server->screen_get_usable_rect(init_screen);
3325
display_server->window_set_position(scr_rect.position + (scr_rect.size - real_size) / 2, DisplayServer::MAIN_WINDOW_ID);
3326
}
3327
}
3328
#endif
3329
if (display_server->has_feature(DisplayServer::FEATURE_SUBWINDOWS)) {
3330
display_server->show_window(DisplayServer::MAIN_WINDOW_ID);
3331
}
3332
3333
if (display_server->has_feature(DisplayServer::FEATURE_ORIENTATION)) {
3334
display_server->screen_set_orientation(window_orientation);
3335
}
3336
3337
OS::get_singleton()->benchmark_end_measure("Servers", "Display");
3338
}
3339
3340
// Max FPS needs to be set after the DisplayServer is created.
3341
RenderingDevice *rd = RenderingDevice::get_singleton();
3342
if (rd) {
3343
rd->_set_max_fps(engine->get_max_fps());
3344
}
3345
3346
#ifdef TOOLS_ENABLED
3347
// If the editor is running in windowed mode, ensure the window rect fits
3348
// the screen in case screen count or position has changed.
3349
if (editor && init_windowed) {
3350
// We still need to check we are actually in windowed mode, because
3351
// certain platform might only support one fullscreen window.
3352
if (DisplayServer::get_singleton()->window_get_mode() == DisplayServer::WINDOW_MODE_WINDOWED) {
3353
Vector2i current_size = DisplayServer::get_singleton()->window_get_size();
3354
Vector2i current_pos = DisplayServer::get_singleton()->window_get_position();
3355
int screen = DisplayServer::get_singleton()->window_get_current_screen();
3356
Rect2i screen_rect = DisplayServer::get_singleton()->screen_get_usable_rect(screen);
3357
3358
Vector2i adjusted_end = screen_rect.get_end().min(current_pos + current_size);
3359
Vector2i adjusted_pos = screen_rect.get_position().max(adjusted_end - current_size);
3360
Vector2i adjusted_size = DisplayServer::get_singleton()->window_get_min_size().max(adjusted_end - adjusted_pos);
3361
3362
if (current_pos != adjusted_end || current_size != adjusted_size) {
3363
DisplayServer::get_singleton()->window_set_position(adjusted_pos);
3364
DisplayServer::get_singleton()->window_set_size(adjusted_size);
3365
}
3366
}
3367
}
3368
#endif
3369
3370
if (GLOBAL_GET("debug/settings/stdout/print_fps") || print_fps) {
3371
// Print requested V-Sync mode at startup to diagnose the printed FPS not going above the monitor refresh rate.
3372
switch (window_vsync_mode) {
3373
case DisplayServer::VSyncMode::VSYNC_DISABLED:
3374
print_line("Requested V-Sync mode: Disabled");
3375
break;
3376
case DisplayServer::VSyncMode::VSYNC_ENABLED:
3377
print_line("Requested V-Sync mode: Enabled - FPS will likely be capped to the monitor refresh rate.");
3378
break;
3379
case DisplayServer::VSyncMode::VSYNC_ADAPTIVE:
3380
print_line("Requested V-Sync mode: Adaptive");
3381
break;
3382
case DisplayServer::VSyncMode::VSYNC_MAILBOX:
3383
print_line("Requested V-Sync mode: Mailbox");
3384
break;
3385
}
3386
}
3387
3388
if (OS::get_singleton()->_separate_thread_render) {
3389
WARN_PRINT("The separate rendering thread feature is experimental. Feel free to try it since it will eventually become a stable feature.\n"
3390
"However, bear in mind that at the moment it can lead to project crashes or instability.\n"
3391
"So, unless you want to test the engine, set the \"rendering/driver/threads/thread_model\" project setting to 'Safe'.");
3392
}
3393
3394
/* Initialize Pen Tablet Driver */
3395
3396
{
3397
OS::get_singleton()->benchmark_begin_measure("Servers", "Tablet Driver");
3398
3399
GLOBAL_DEF_RST_NOVAL("input_devices/pen_tablet/driver", "");
3400
GLOBAL_DEF_RST_NOVAL(PropertyInfo(Variant::STRING, "input_devices/pen_tablet/driver.windows", PROPERTY_HINT_ENUM, "auto,winink,wintab,dummy"), "");
3401
3402
#ifdef TOOLS_ENABLED
3403
if (tablet_driver.is_empty() && tablet_driver_editor != -1) {
3404
tablet_driver = DisplayServer::get_singleton()->tablet_get_driver_name(tablet_driver_editor);
3405
}
3406
#endif
3407
3408
if (tablet_driver.is_empty()) { // specified in project.godot
3409
tablet_driver = GLOBAL_GET("input_devices/pen_tablet/driver");
3410
if (tablet_driver.is_empty()) {
3411
tablet_driver = DisplayServer::get_singleton()->tablet_get_driver_name(0);
3412
}
3413
}
3414
3415
for (int i = 0; i < DisplayServer::get_singleton()->tablet_get_driver_count(); i++) {
3416
if (tablet_driver == DisplayServer::get_singleton()->tablet_get_driver_name(i)) {
3417
DisplayServer::get_singleton()->tablet_set_current_driver(DisplayServer::get_singleton()->tablet_get_driver_name(i));
3418
break;
3419
}
3420
}
3421
3422
if (DisplayServer::get_singleton()->tablet_get_current_driver().is_empty()) {
3423
DisplayServer::get_singleton()->tablet_set_current_driver(DisplayServer::get_singleton()->tablet_get_driver_name(0));
3424
}
3425
3426
print_verbose("Using \"" + DisplayServer::get_singleton()->tablet_get_current_driver() + "\" pen tablet driver...");
3427
3428
OS::get_singleton()->benchmark_end_measure("Servers", "Tablet Driver");
3429
}
3430
3431
/* Initialize Rendering Server */
3432
3433
{
3434
OS::get_singleton()->benchmark_begin_measure("Servers", "Rendering");
3435
3436
rendering_server = memnew(RenderingServerDefault(OS::get_singleton()->is_separate_thread_rendering_enabled()));
3437
3438
rendering_server->init();
3439
//rendering_server->call_set_use_vsync(OS::get_singleton()->_use_vsync);
3440
rendering_server->set_render_loop_enabled(!disable_render_loop);
3441
3442
if (profile_gpu || (!editor && bool(GLOBAL_GET("debug/settings/stdout/print_gpu_profile")))) {
3443
rendering_server->set_print_gpu_profile(true);
3444
}
3445
3446
OS::get_singleton()->benchmark_end_measure("Servers", "Rendering");
3447
}
3448
3449
#ifdef UNIX_ENABLED
3450
// Print warning after initializing the renderer but before initializing audio.
3451
if (OS::get_singleton()->get_environment("USER") == "root" && !OS::get_singleton()->has_environment("GODOT_SILENCE_ROOT_WARNING")) {
3452
WARN_PRINT("Started the engine as `root`/superuser. This is a security risk, and subsystems like audio may not work correctly.\nSet the environment variable `GODOT_SILENCE_ROOT_WARNING` to 1 to silence this warning.");
3453
}
3454
#endif
3455
3456
/* Initialize Audio Driver */
3457
3458
{
3459
OS::get_singleton()->benchmark_begin_measure("Servers", "Audio");
3460
3461
AudioDriverManager::initialize(audio_driver_idx);
3462
3463
// Right moment to create and initialize the audio server.
3464
audio_server = memnew(AudioServer);
3465
audio_server->init();
3466
3467
OS::get_singleton()->benchmark_end_measure("Servers", "Audio");
3468
}
3469
3470
#ifndef XR_DISABLED
3471
/* Initialize XR Server */
3472
3473
{
3474
OS::get_singleton()->benchmark_begin_measure("Servers", "XR");
3475
3476
xr_server = memnew(XRServer);
3477
3478
OS::get_singleton()->benchmark_end_measure("Servers", "XR");
3479
}
3480
#endif // XR_DISABLED
3481
3482
OS::get_singleton()->benchmark_end_measure("Startup", "Servers");
3483
3484
#ifndef WEB_ENABLED
3485
// Add a blank line for readability.
3486
Engine::get_singleton()->print_header("");
3487
#endif // WEB_ENABLED
3488
3489
register_core_singletons();
3490
3491
/* Initialize the main window and boot screen */
3492
3493
{
3494
OS::get_singleton()->benchmark_begin_measure("Startup", "Setup Window and Boot");
3495
3496
MAIN_PRINT("Main: Setup Logo");
3497
3498
if (!init_embed_parent_window_id) {
3499
if (init_windowed) {
3500
//do none..
3501
} else if (init_maximized) {
3502
DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_MAXIMIZED);
3503
} else if (init_fullscreen) {
3504
DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_FULLSCREEN);
3505
}
3506
if (init_always_on_top) {
3507
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP, true);
3508
}
3509
}
3510
3511
Color clear = GLOBAL_DEF_BASIC("rendering/environment/defaults/default_clear_color", Color(0.3, 0.3, 0.3));
3512
RenderingServer::get_singleton()->set_default_clear_color(clear);
3513
3514
if (p_show_boot_logo) {
3515
setup_boot_logo();
3516
}
3517
3518
MAIN_PRINT("Main: Clear Color");
3519
3520
DisplayServer::set_early_window_clear_color_override(false);
3521
3522
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/config/icon", PROPERTY_HINT_FILE, "*.png,*.bmp,*.hdr,*.jpg,*.jpeg,*.svg,*.tga,*.exr,*.webp"), String());
3523
GLOBAL_DEF(PropertyInfo(Variant::STRING, "application/config/macos_native_icon", PROPERTY_HINT_FILE, "*.icns"), String());
3524
GLOBAL_DEF(PropertyInfo(Variant::STRING, "application/config/windows_native_icon", PROPERTY_HINT_FILE, "*.ico"), String());
3525
3526
MAIN_PRINT("Main: Touch Input");
3527
3528
Input *id = Input::get_singleton();
3529
if (id) {
3530
bool agile_input_event_flushing = GLOBAL_DEF("input_devices/buffering/agile_event_flushing", false);
3531
id->set_agile_input_event_flushing(agile_input_event_flushing);
3532
3533
if (bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_touch_from_mouse", false)) &&
3534
!(editor || project_manager)) {
3535
if (!DisplayServer::get_singleton()->is_touchscreen_available()) {
3536
//only if no touchscreen ui hint, set emulation
3537
id->set_emulate_touch_from_mouse(true);
3538
}
3539
}
3540
3541
id->set_emulate_mouse_from_touch(bool(GLOBAL_DEF_BASIC("input_devices/pointing/emulate_mouse_from_touch", true)));
3542
3543
if (editor) {
3544
id->set_emulate_mouse_from_touch(true);
3545
}
3546
}
3547
3548
OS::get_singleton()->benchmark_end_measure("Startup", "Setup Window and Boot");
3549
}
3550
3551
MAIN_PRINT("Main: Load Translations and Remaps");
3552
3553
/* Setup translations and remaps */
3554
3555
{
3556
OS::get_singleton()->benchmark_begin_measure("Startup", "Translations and Remaps");
3557
3558
translation_server->setup(); //register translations, load them, etc.
3559
if (!locale.is_empty()) {
3560
translation_server->set_locale(locale);
3561
}
3562
translation_server->load_project_translations(translation_server->get_main_domain());
3563
ResourceLoader::load_translation_remaps(); //load remaps for resources
3564
3565
OS::get_singleton()->benchmark_end_measure("Startup", "Translations and Remaps");
3566
}
3567
3568
MAIN_PRINT("Main: Load TextServer");
3569
3570
/* Setup Text Server */
3571
3572
{
3573
OS::get_singleton()->benchmark_begin_measure("Startup", "Text Server");
3574
3575
/* Enum text drivers */
3576
GLOBAL_DEF_RST("internationalization/rendering/text_driver", "");
3577
String text_driver_options;
3578
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
3579
const String driver_name = TextServerManager::get_singleton()->get_interface(i)->get_name();
3580
if (driver_name == "Dummy") {
3581
// Dummy text driver cannot draw any text, making the editor unusable if selected.
3582
continue;
3583
}
3584
if (!text_driver_options.is_empty() && !text_driver_options.contains_char(',')) {
3585
// Not the first option; add a comma before it as a separator for the property hint.
3586
text_driver_options += ",";
3587
}
3588
text_driver_options += driver_name;
3589
}
3590
ProjectSettings::get_singleton()->set_custom_property_info(PropertyInfo(Variant::STRING, "internationalization/rendering/text_driver", PROPERTY_HINT_ENUM, text_driver_options));
3591
3592
/* Determine text driver */
3593
if (text_driver.is_empty()) {
3594
text_driver = GLOBAL_GET("internationalization/rendering/text_driver");
3595
}
3596
3597
if (!text_driver.is_empty()) {
3598
/* Load user selected text server. */
3599
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
3600
if (TextServerManager::get_singleton()->get_interface(i)->get_name() == text_driver) {
3601
text_driver_idx = i;
3602
break;
3603
}
3604
}
3605
}
3606
3607
if (text_driver_idx < 0) {
3608
/* If not selected, use one with the most features available. */
3609
int max_features = 0;
3610
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
3611
uint32_t features = TextServerManager::get_singleton()->get_interface(i)->get_features();
3612
int feature_number = 0;
3613
while (features) {
3614
feature_number += features & 1;
3615
features >>= 1;
3616
}
3617
if (feature_number >= max_features) {
3618
max_features = feature_number;
3619
text_driver_idx = i;
3620
}
3621
}
3622
}
3623
if (text_driver_idx >= 0) {
3624
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(text_driver_idx);
3625
TextServerManager::get_singleton()->set_primary_interface(ts);
3626
if (ts->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
3627
ts->load_support_data("res://" + ts->get_support_data_filename());
3628
}
3629
} else {
3630
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "TextServer: Unable to create TextServer interface.");
3631
}
3632
3633
OS::get_singleton()->benchmark_end_measure("Startup", "Text Server");
3634
}
3635
3636
MAIN_PRINT("Main: Load Scene Types");
3637
3638
OS::get_singleton()->benchmark_begin_measure("Startup", "Scene");
3639
3640
// Initialize ThemeDB early so that scene types can register their theme items.
3641
// Default theme will be initialized later, after modules and ScriptServer are ready.
3642
initialize_theme_db();
3643
3644
#if !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
3645
MAIN_PRINT("Main: Load Navigation");
3646
#endif // !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
3647
3648
#ifndef NAVIGATION_3D_DISABLED
3649
NavigationServer3DManager::initialize_server();
3650
#endif // NAVIGATION_3D_DISABLED
3651
#ifndef NAVIGATION_2D_DISABLED
3652
NavigationServer2DManager::initialize_server();
3653
#endif // NAVIGATION_2D_DISABLED
3654
3655
register_scene_types();
3656
register_driver_types();
3657
3658
register_scene_singletons();
3659
3660
{
3661
OS::get_singleton()->benchmark_begin_measure("Scene", "Modules and Extensions");
3662
3663
initialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE);
3664
GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SCENE);
3665
3666
OS::get_singleton()->benchmark_end_measure("Scene", "Modules and Extensions");
3667
3668
// We need to initialize the movie writer here in case
3669
// one of the user-provided GDExtensions subclasses MovieWriter.
3670
if (Engine::get_singleton()->get_write_movie_path() != String()) {
3671
movie_writer = MovieWriter::find_writer_for_file(Engine::get_singleton()->get_write_movie_path());
3672
if (movie_writer == nullptr) {
3673
ERR_PRINT("Can't find movie writer for file type, aborting: " + Engine::get_singleton()->get_write_movie_path());
3674
Engine::get_singleton()->set_write_movie_path(String());
3675
}
3676
}
3677
}
3678
3679
PackedStringArray extensions;
3680
extensions.push_back("gd");
3681
if (ClassDB::class_exists("CSharpScript")) {
3682
extensions.push_back("cs");
3683
}
3684
extensions.push_back("gdshader");
3685
GLOBAL_DEF_NOVAL(PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions"), extensions); // Note: should be defined after Scene level modules init to see .NET.
3686
3687
OS::get_singleton()->benchmark_end_measure("Startup", "Scene");
3688
3689
#ifdef TOOLS_ENABLED
3690
ClassDB::set_current_api(ClassDB::API_EDITOR);
3691
register_editor_types();
3692
3693
{
3694
OS::get_singleton()->benchmark_begin_measure("Editor", "Modules and Extensions");
3695
3696
initialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR);
3697
GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR);
3698
3699
OS::get_singleton()->benchmark_end_measure("Editor", "Modules and Extensions");
3700
}
3701
3702
ClassDB::set_current_api(ClassDB::API_CORE);
3703
3704
#endif
3705
3706
MAIN_PRINT("Main: Load Platforms");
3707
3708
OS::get_singleton()->benchmark_begin_measure("Startup", "Platforms");
3709
3710
register_platform_apis();
3711
3712
OS::get_singleton()->benchmark_end_measure("Startup", "Platforms");
3713
3714
GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "display/mouse_cursor/custom_image", PROPERTY_HINT_FILE, "*.png,*.bmp,*.hdr,*.jpg,*.jpeg,*.svg,*.tga,*.exr,*.webp"), String());
3715
GLOBAL_DEF_BASIC("display/mouse_cursor/custom_image_hotspot", Vector2());
3716
GLOBAL_DEF_BASIC("display/mouse_cursor/tooltip_position_offset", Point2(10, 10));
3717
3718
if (String(GLOBAL_GET("display/mouse_cursor/custom_image")) != String()) {
3719
Ref<Texture2D> cursor = ResourceLoader::load(
3720
GLOBAL_GET("display/mouse_cursor/custom_image"));
3721
if (cursor.is_valid()) {
3722
Vector2 hotspot = GLOBAL_GET("display/mouse_cursor/custom_image_hotspot");
3723
Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CursorShape::CURSOR_ARROW, hotspot);
3724
}
3725
}
3726
3727
OS::get_singleton()->benchmark_begin_measure("Startup", "Finalize Setup");
3728
3729
camera_server = CameraServer::create();
3730
3731
MAIN_PRINT("Main: Load Physics");
3732
3733
initialize_physics();
3734
3735
register_server_singletons();
3736
3737
// This loads global classes, so it must happen before custom loaders and savers are registered
3738
ScriptServer::init_languages();
3739
3740
#if TOOLS_ENABLED
3741
3742
// Setting up the callback to execute a scan for UIDs on disk when a UID
3743
// does not exist in the UID cache on startup. This prevents invalid UID errors
3744
// when opening a project without a UID cache file or with an invalid cache.
3745
if (editor) {
3746
ResourceUID::scan_for_uid_on_startup = EditorFileSystem::scan_for_uid;
3747
}
3748
3749
#endif
3750
3751
theme_db->initialize_theme();
3752
audio_server->load_default_bus_layout();
3753
3754
#if defined(MODULE_MONO_ENABLED) && defined(TOOLS_ENABLED)
3755
// Hacky to have it here, but we don't have good facility yet to let modules
3756
// register command line options to call at the right time. This needs to happen
3757
// after init'ing the ScriptServer, but also after init'ing the ThemeDB,
3758
// for the C# docs generation in the bindings.
3759
List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
3760
BindingsGenerator::handle_cmdline_args(cmdline_args);
3761
#endif
3762
3763
if (use_debug_profiler && EngineDebugger::is_active()) {
3764
// Start the "scripts" profiler, used in local debugging.
3765
// We could add more, and make the CLI arg require a comma-separated list of profilers.
3766
EngineDebugger::get_singleton()->profiler_enable("scripts", true);
3767
}
3768
3769
if (!project_manager) {
3770
// If not running the project manager, and now that the engine is
3771
// able to load resources, load the global shader variables.
3772
// If running on editor, don't load the textures because the editor
3773
// may want to import them first. Editor will reload those later.
3774
rendering_server->global_shader_parameters_load_settings(!editor);
3775
}
3776
3777
OS::get_singleton()->benchmark_end_measure("Startup", "Finalize Setup");
3778
3779
_start_success = true;
3780
3781
ClassDB::set_current_api(ClassDB::API_NONE); //no more APIs are registered at this point
3782
3783
print_verbose("CORE API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_CORE)));
3784
print_verbose("EDITOR API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_EDITOR)));
3785
MAIN_PRINT("Main: Done");
3786
3787
OS::get_singleton()->benchmark_end_measure("Startup", "Main::Setup2");
3788
3789
return OK;
3790
}
3791
3792
void Main::setup_boot_logo() {
3793
GodotProfileZone("setup_boot_logo");
3794
MAIN_PRINT("Main: Load Boot Image");
3795
3796
#if !defined(TOOLS_ENABLED) && defined(WEB_ENABLED)
3797
bool show_logo = false;
3798
#else
3799
bool show_logo = true;
3800
#endif
3801
3802
if (show_logo) { //boot logo!
3803
const bool boot_logo_image = GLOBAL_DEF_BASIC("application/boot_splash/show_image", true);
3804
3805
const RenderingServer::SplashStretchMode boot_stretch_mode = GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "application/boot_splash/stretch_mode", PROPERTY_HINT_ENUM, "Disabled,Keep,Keep Width,Keep Height,Cover,Ignore"), 1);
3806
const bool boot_logo_filter = GLOBAL_DEF_BASIC("application/boot_splash/use_filter", true);
3807
String boot_logo_path = GLOBAL_DEF_BASIC(PropertyInfo(Variant::STRING, "application/boot_splash/image", PROPERTY_HINT_FILE, "*.png"), String());
3808
3809
// If the UID cache is missing or invalid, it could be 'normal' for the UID to not exist in memory.
3810
// It's too soon to scan the project files since the ResourceFormatImporter is not loaded yet,
3811
// so to prevent printing errors, we will just skip the custom boot logo this time.
3812
if (boot_logo_path.begins_with("uid://")) {
3813
const ResourceUID::ID logo_id = ResourceUID::get_singleton()->text_to_id(boot_logo_path);
3814
if (ResourceUID::get_singleton()->has_id(logo_id)) {
3815
boot_logo_path = ResourceUID::get_singleton()->get_id_path(logo_id).strip_edges();
3816
} else {
3817
boot_logo_path = String();
3818
}
3819
}
3820
3821
Ref<Image> boot_logo;
3822
3823
if (boot_logo_image) {
3824
if (!boot_logo_path.is_empty()) {
3825
boot_logo.instantiate();
3826
Error load_err = ImageLoader::load_image(boot_logo_path, boot_logo);
3827
if (load_err) {
3828
String msg = (boot_logo_path.ends_with(".png") ? "" : "The only supported format is PNG.");
3829
ERR_PRINT("Non-existing or invalid boot splash at '" + boot_logo_path + +"'. " + msg + " Loading default splash.");
3830
}
3831
}
3832
} else {
3833
// Create a 1×1 transparent image. This will effectively hide the splash image.
3834
boot_logo.instantiate();
3835
boot_logo->initialize_data(1, 1, false, Image::FORMAT_RGBA8);
3836
boot_logo->set_pixel(0, 0, Color(0, 0, 0, 0));
3837
}
3838
3839
Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color");
3840
3841
#if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
3842
boot_bg_color = GLOBAL_DEF_BASIC("application/boot_splash/bg_color", (editor || project_manager) ? boot_splash_editor_bg_color : boot_splash_bg_color);
3843
#endif
3844
if (boot_logo.is_valid()) {
3845
RenderingServer::get_singleton()->set_boot_image_with_stretch(boot_logo, boot_bg_color, boot_stretch_mode, boot_logo_filter);
3846
3847
} else {
3848
#ifndef NO_DEFAULT_BOOT_LOGO
3849
MAIN_PRINT("Main: Create bootsplash");
3850
#if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
3851
Ref<Image> splash = (editor || project_manager) ? memnew(Image(boot_splash_editor_png)) : memnew(Image(boot_splash_png));
3852
#else
3853
Ref<Image> splash = memnew(Image(boot_splash_png));
3854
#endif
3855
3856
MAIN_PRINT("Main: ClearColor");
3857
RenderingServer::get_singleton()->set_default_clear_color(boot_bg_color);
3858
MAIN_PRINT("Main: Image");
3859
RenderingServer::get_singleton()->set_boot_image_with_stretch(splash, boot_bg_color, RenderingServer::SPLASH_STRETCH_MODE_DISABLED);
3860
#endif
3861
}
3862
3863
#if defined(TOOLS_ENABLED) && defined(MACOS_ENABLED)
3864
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_ICON) && OS::get_singleton()->get_bundle_icon_path().is_empty()) {
3865
Ref<Image> icon = memnew(Image(app_icon_png));
3866
DisplayServer::get_singleton()->set_icon(icon);
3867
}
3868
#endif
3869
}
3870
RenderingServer::get_singleton()->set_default_clear_color(
3871
GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
3872
}
3873
3874
String Main::get_locale_override() {
3875
return locale;
3876
}
3877
3878
// everything the main loop needs to know about frame timings
3879
static MainTimerSync main_timer_sync;
3880
3881
// Return value should be EXIT_SUCCESS if we start successfully
3882
// and should move on to `OS::run`, and EXIT_FAILURE otherwise for
3883
// an early exit with that error code.
3884
int Main::start() {
3885
GodotProfileZone("start");
3886
OS::get_singleton()->benchmark_begin_measure("Startup", "Main::Start");
3887
3888
ERR_FAIL_COND_V(!_start_success, EXIT_FAILURE);
3889
3890
bool has_icon = false;
3891
String positional_arg;
3892
String game_path;
3893
String script;
3894
String main_loop_type;
3895
bool check_only = false;
3896
3897
#ifdef TOOLS_ENABLED
3898
String doc_tool_path;
3899
bool doc_tool_implicit_cwd = false;
3900
BitField<DocTools::GenerateFlags> gen_flags = {};
3901
String _export_preset;
3902
Vector<String> patches;
3903
bool export_debug = false;
3904
bool export_pack_only = false;
3905
bool install_android_build_template = false;
3906
bool export_patch = false;
3907
#ifdef MODULE_GDSCRIPT_ENABLED
3908
String gdscript_docs_path;
3909
#endif
3910
#ifndef DISABLE_DEPRECATED
3911
bool converting_project = false;
3912
bool validating_converting_project = false;
3913
#endif // DISABLE_DEPRECATED
3914
#endif // TOOLS_ENABLED
3915
3916
main_timer_sync.init(OS::get_singleton()->get_ticks_usec());
3917
List<String> args = OS::get_singleton()->get_cmdline_args();
3918
3919
for (List<String>::Element *E = args.front(); E; E = E->next()) {
3920
// First check parameters that do not have an argument to the right.
3921
3922
// Doctest Unit Testing Handler
3923
// Designed to override and pass arguments to the unit test handler.
3924
if (E->get() == "--check-only") {
3925
check_only = true;
3926
#ifdef TOOLS_ENABLED
3927
} else if (E->get() == "--no-docbase") {
3928
gen_flags.set_flag(DocTools::GENERATE_FLAG_SKIP_BASIC_TYPES);
3929
} else if (E->get() == "--gdextension-docs") {
3930
gen_flags.set_flag(DocTools::GENERATE_FLAG_SKIP_BASIC_TYPES);
3931
gen_flags.set_flag(DocTools::GENERATE_FLAG_EXTENSION_CLASSES_ONLY);
3932
#ifndef DISABLE_DEPRECATED
3933
} else if (E->get() == "--convert-3to4") {
3934
converting_project = true;
3935
} else if (E->get() == "--validate-conversion-3to4") {
3936
validating_converting_project = true;
3937
#endif // DISABLE_DEPRECATED
3938
} else if (E->get() == "-e" || E->get() == "--editor") {
3939
editor = true;
3940
} else if (E->get() == "-p" || E->get() == "--project-manager") {
3941
project_manager = true;
3942
} else if (E->get() == "--recovery-mode") {
3943
recovery_mode = true;
3944
} else if (E->get() == "--install-android-build-template") {
3945
install_android_build_template = true;
3946
#endif // TOOLS_ENABLED
3947
} else if (E->get() == "--scene") {
3948
#if defined(OVERRIDE_PATH_ENABLED)
3949
E = E->next();
3950
if (E) {
3951
game_path = ResourceUID::ensure_path(E->get());
3952
} else {
3953
ERR_FAIL_V_MSG(EXIT_FAILURE, "Missing scene path, aborting.");
3954
}
3955
#else
3956
ERR_PRINT(
3957
"`--scene` was specified on the command line, but this Godot binary was compiled without support for path overrides. Aborting.\n"
3958
"To be able to use it, use the `disable_path_overrides=no` SCons option when compiling Godot.\n");
3959
return EXIT_FAILURE;
3960
#endif // defined(OVERRIDE_PATH_ENABLED)
3961
} else if (E->get().length() && E->get()[0] != '-' && positional_arg.is_empty() && game_path.is_empty()) {
3962
positional_arg = E->get();
3963
3964
String scene_path = ResourceUID::ensure_path(E->get());
3965
if (scene_path.ends_with(".scn") ||
3966
scene_path.ends_with(".tscn") ||
3967
scene_path.ends_with(".escn") ||
3968
scene_path.ends_with(".res") ||
3969
scene_path.ends_with(".tres")) {
3970
// Only consider the positional argument to be a scene path if it ends with
3971
// a file extension associated with Godot scenes. This makes it possible
3972
// for projects to parse command-line arguments for custom CLI arguments
3973
// or other file extensions without trouble. This can be used to implement
3974
// "drag-and-drop onto executable" logic, which can prove helpful
3975
// for non-game applications.
3976
#if defined(OVERRIDE_PATH_ENABLED)
3977
game_path = scene_path;
3978
#else
3979
ERR_PRINT(
3980
"Scene path was specified on the command line, but this Godot binary was compiled without support for path overrides. Aborting.\n"
3981
"To be able to use it, use the `disable_path_overrides=no` SCons option when compiling Godot.\n");
3982
return EXIT_FAILURE;
3983
#endif // defined(OVERRIDE_PATH_ENABLED)
3984
}
3985
}
3986
// Then parameters that have an argument to the right.
3987
else if (E->next()) {
3988
bool parsed_pair = true;
3989
if (E->get() == "-s" || E->get() == "--script") {
3990
script = E->next()->get();
3991
} else if (E->get() == "--main-loop") {
3992
main_loop_type = E->next()->get();
3993
#ifdef TOOLS_ENABLED
3994
} else if (E->get() == "--doctool") {
3995
doc_tool_path = E->next()->get();
3996
if (doc_tool_path.begins_with("-")) {
3997
// Assuming other command line arg, so default to cwd.
3998
doc_tool_path = ".";
3999
doc_tool_implicit_cwd = true;
4000
parsed_pair = false;
4001
}
4002
#ifdef MODULE_GDSCRIPT_ENABLED
4003
} else if (E->get() == "--gdscript-docs") {
4004
gdscript_docs_path = E->next()->get();
4005
#endif
4006
} else if (E->get() == "--export-release") {
4007
ERR_FAIL_COND_V_MSG(!editor && !found_project, EXIT_FAILURE, "Please provide a valid project path when exporting, aborting.");
4008
editor = true; //needs editor
4009
_export_preset = E->next()->get();
4010
} else if (E->get() == "--export-debug") {
4011
ERR_FAIL_COND_V_MSG(!editor && !found_project, EXIT_FAILURE, "Please provide a valid project path when exporting, aborting.");
4012
editor = true; //needs editor
4013
_export_preset = E->next()->get();
4014
export_debug = true;
4015
} else if (E->get() == "--export-pack") {
4016
ERR_FAIL_COND_V_MSG(!editor && !found_project, EXIT_FAILURE, "Please provide a valid project path when exporting, aborting.");
4017
editor = true;
4018
_export_preset = E->next()->get();
4019
export_pack_only = true;
4020
} else if (E->get() == "--export-patch") {
4021
ERR_FAIL_COND_V_MSG(!editor && !found_project, EXIT_FAILURE, "Please provide a valid project path when exporting, aborting.");
4022
editor = true;
4023
_export_preset = E->next()->get();
4024
export_pack_only = true;
4025
export_patch = true;
4026
} else if (E->get() == "--patches") {
4027
patches = E->next()->get().split(",", false);
4028
#endif
4029
} else {
4030
// The parameter does not match anything known, don't skip the next argument
4031
parsed_pair = false;
4032
}
4033
if (parsed_pair) {
4034
E = E->next();
4035
}
4036
} else if (E->get().begins_with("--export-")) {
4037
ERR_FAIL_V_MSG(EXIT_FAILURE, "Missing export preset name, aborting.");
4038
}
4039
#ifdef TOOLS_ENABLED
4040
// Handle case where no path is given to --doctool.
4041
else if (E->get() == "--doctool") {
4042
doc_tool_path = ".";
4043
doc_tool_implicit_cwd = true;
4044
}
4045
#endif
4046
}
4047
4048
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);
4049
if (Engine::get_singleton()->is_editor_hint()) {
4050
minimum_time_msec = 0;
4051
}
4052
4053
#ifdef TOOLS_ENABLED
4054
#ifdef MODULE_GDSCRIPT_ENABLED
4055
if (!doc_tool_path.is_empty() && gdscript_docs_path.is_empty()) {
4056
#else
4057
if (!doc_tool_path.is_empty()) {
4058
#endif
4059
// Needed to instance editor-only classes for their default values
4060
Engine::get_singleton()->set_editor_hint(true);
4061
4062
// Translate the class reference only when `-l LOCALE` parameter is given.
4063
if (!locale.is_empty() && locale != "en") {
4064
load_doc_translations(locale);
4065
}
4066
4067
{
4068
Ref<DirAccess> da = DirAccess::open(doc_tool_path);
4069
ERR_FAIL_COND_V_MSG(da.is_null(), EXIT_FAILURE, "Argument supplied to --doctool must be a valid directory path.");
4070
// Ensure that doctool is running in the root dir, but only if
4071
// user did not manually specify a path as argument.
4072
if (doc_tool_implicit_cwd) {
4073
ERR_FAIL_COND_V_MSG(!da->dir_exists("doc"), EXIT_FAILURE, "--doctool must be run from the Godot repository's root folder, or specify a path that points there.");
4074
}
4075
}
4076
4077
#ifndef MODULE_MONO_ENABLED
4078
// Hack to define .NET-specific project settings even on non-.NET builds,
4079
// so that we don't lose their descriptions and default values in DocTools.
4080
// Default values should be synced with mono_gd/gd_mono.cpp.
4081
GLOBAL_DEF("dotnet/project/assembly_name", "");
4082
GLOBAL_DEF("dotnet/project/solution_directory", "");
4083
GLOBAL_DEF(PropertyInfo(Variant::INT, "dotnet/project/assembly_reload_attempts", PROPERTY_HINT_RANGE, "1,16,1,or_greater"), 3);
4084
#endif
4085
4086
Error err;
4087
DocTools doc;
4088
doc.generate(gen_flags);
4089
4090
DocTools docsrc;
4091
HashMap<String, String> doc_data_classes;
4092
HashSet<String> checked_paths;
4093
print_line("Loading docs...");
4094
4095
const bool gdextension_docs = gen_flags.has_flag(DocTools::GENERATE_FLAG_EXTENSION_CLASSES_ONLY);
4096
4097
if (!gdextension_docs) {
4098
for (int i = 0; i < _doc_data_class_path_count; i++) {
4099
// Custom modules are always located by absolute path.
4100
String path = _doc_data_class_paths[i].path;
4101
if (path.is_relative_path()) {
4102
path = doc_tool_path.path_join(path);
4103
}
4104
String name = _doc_data_class_paths[i].name;
4105
doc_data_classes[name] = path;
4106
if (!checked_paths.has(path)) {
4107
checked_paths.insert(path);
4108
4109
// Create the module documentation directory if it doesn't exist
4110
Ref<DirAccess> da = DirAccess::create_for_path(path);
4111
err = da->make_dir_recursive(path);
4112
ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error: Can't create directory: " + path + ": " + itos(err));
4113
4114
print_line("Loading docs from: " + path);
4115
err = docsrc.load_classes(path);
4116
ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error loading docs from: " + path + ": " + itos(err));
4117
}
4118
}
4119
}
4120
4121
// For GDExtension docs, use a path that is compatible with Godot modules.
4122
String index_path = gdextension_docs ? doc_tool_path.path_join("doc_classes") : doc_tool_path.path_join("doc/classes");
4123
// Create the main documentation directory if it doesn't exist
4124
Ref<DirAccess> da = DirAccess::create_for_path(index_path);
4125
err = da->make_dir_recursive(index_path);
4126
ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error: Can't create index directory: " + index_path + ": " + itos(err));
4127
4128
print_line("Loading classes from: " + index_path);
4129
err = docsrc.load_classes(index_path);
4130
ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error loading classes from: " + index_path + ": " + itos(err));
4131
checked_paths.insert(index_path);
4132
4133
print_line("Merging docs...");
4134
doc.merge_from(docsrc);
4135
4136
for (const String &E : checked_paths) {
4137
print_line("Erasing old docs at: " + E);
4138
err = DocTools::erase_classes(E);
4139
ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error erasing old docs at: " + E + ": " + itos(err));
4140
}
4141
4142
print_line("Generating new docs...");
4143
err = doc.save_classes(index_path, doc_data_classes, !gdextension_docs);
4144
ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error saving new docs:" + itos(err));
4145
4146
print_line("Deleting docs cache...");
4147
if (FileAccess::exists(EditorHelp::get_cache_full_path())) {
4148
DirAccess::remove_file_or_error(EditorHelp::get_cache_full_path());
4149
}
4150
4151
return EXIT_SUCCESS;
4152
}
4153
4154
// GDExtension API and interface.
4155
{
4156
if (dump_gdextension_interface) {
4157
GDExtensionInterfaceDump::generate_gdextension_interface_file("gdextension_interface.json");
4158
}
4159
4160
if (dump_gdextension_interface_header) {
4161
GDExtensionInterfaceHeaderGenerator::generate_gdextension_interface_header("gdextension_interface.h");
4162
}
4163
4164
if (dump_extension_api) {
4165
Engine::get_singleton()->set_editor_hint(true); // "extension_api.json" should always contains editor singletons.
4166
GDExtensionAPIDump::generate_extension_json_file("extension_api.json", include_docs_in_extension_api_dump);
4167
}
4168
4169
if (dump_gdextension_interface || dump_gdextension_interface_header || dump_extension_api) {
4170
return EXIT_SUCCESS;
4171
}
4172
4173
if (validate_extension_api) {
4174
Engine::get_singleton()->set_editor_hint(true); // "extension_api.json" should always contains editor singletons.
4175
bool valid = GDExtensionAPIDump::validate_extension_json_file(validate_extension_api_file) == OK;
4176
return valid ? EXIT_SUCCESS : EXIT_FAILURE;
4177
}
4178
}
4179
4180
#ifndef DISABLE_DEPRECATED
4181
if (converting_project) {
4182
int ret = ProjectConverter3To4(converter_max_kb_file, converter_max_line_length).convert();
4183
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
4184
}
4185
if (validating_converting_project) {
4186
bool ret = ProjectConverter3To4(converter_max_kb_file, converter_max_line_length).validate_conversion();
4187
return ret ? EXIT_SUCCESS : EXIT_FAILURE;
4188
}
4189
#endif // DISABLE_DEPRECATED
4190
4191
#endif // TOOLS_ENABLED
4192
4193
#if defined(OVERRIDE_PATH_ENABLED)
4194
bool disable_override = GLOBAL_GET("application/config/disable_project_settings_override");
4195
if (disable_override) {
4196
script = String();
4197
game_path = String();
4198
main_loop_type = String();
4199
}
4200
#else
4201
script = String();
4202
game_path = String();
4203
main_loop_type = String();
4204
#endif // defined(OVERRIDE_PATH_ENABLED)
4205
4206
if (script.is_empty() && game_path.is_empty()) {
4207
const String main_scene = GLOBAL_GET("application/run/main_scene");
4208
if (main_scene.begins_with("uid://")) {
4209
ResourceUID::ID id = ResourceUID::get_singleton()->text_to_id(main_scene);
4210
if (!editor && !ResourceUID::get_singleton()->has_id(id) && !FileAccess::exists(ResourceUID::get_singleton()->get_cache_file())) {
4211
OS::get_singleton()->alert("Main scene's path could not be resolved from UID. Make sure the project is imported first. Aborting.");
4212
ERR_FAIL_V_MSG(EXIT_FAILURE, "Main scene's path could not be resolved from UID. Make sure the project is imported first. Aborting.");
4213
}
4214
game_path = ResourceUID::get_singleton()->get_id_path(id);
4215
} else {
4216
game_path = main_scene;
4217
}
4218
}
4219
4220
#ifdef TOOLS_ENABLED
4221
if (!editor && !project_manager && !cmdline_tool && script.is_empty() && game_path.is_empty()) {
4222
// If we end up here, it means we didn't manage to detect what we want to run.
4223
// Let's throw an error gently. The code leading to this is pretty brittle so
4224
// this might end up triggered by valid usage, in which case we'll have to
4225
// fine-tune further.
4226
OS::get_singleton()->alert("Couldn't detect whether to run the editor, the project manager or a specific project. Aborting.");
4227
ERR_FAIL_V_MSG(EXIT_FAILURE, "Couldn't detect whether to run the editor, the project manager or a specific project. Aborting.");
4228
}
4229
#endif
4230
4231
MainLoop *main_loop = nullptr;
4232
if (editor) {
4233
main_loop = memnew(SceneTree);
4234
}
4235
if (main_loop_type.is_empty()) {
4236
main_loop_type = GLOBAL_GET("application/run/main_loop_type");
4237
}
4238
4239
if (!script.is_empty()) {
4240
Ref<Script> script_res = ResourceLoader::load(script);
4241
ERR_FAIL_COND_V_MSG(script_res.is_null(), EXIT_FAILURE, "Can't load script: " + script);
4242
4243
if (check_only) {
4244
return script_res->is_valid() ? EXIT_SUCCESS : EXIT_FAILURE;
4245
}
4246
4247
if (script_res->can_instantiate()) {
4248
StringName instance_type = script_res->get_instance_base_type();
4249
Object *obj = ClassDB::instantiate(instance_type);
4250
MainLoop *script_loop = Object::cast_to<MainLoop>(obj);
4251
if (!script_loop) {
4252
if (obj) {
4253
memdelete(obj);
4254
}
4255
OS::get_singleton()->alert(vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script));
4256
ERR_FAIL_V_MSG(EXIT_FAILURE, vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script));
4257
}
4258
4259
script_loop->set_script(script_res);
4260
main_loop = script_loop;
4261
} else {
4262
return EXIT_FAILURE;
4263
}
4264
} else { // Not based on script path.
4265
if (!editor && !ClassDB::class_exists(main_loop_type) && ScriptServer::is_global_class(main_loop_type)) {
4266
String script_path = ScriptServer::get_global_class_path(main_loop_type);
4267
Ref<Script> script_res = ResourceLoader::load(script_path);
4268
if (script_res.is_null()) {
4269
OS::get_singleton()->alert("Error: Could not load MainLoop script type: " + main_loop_type);
4270
ERR_FAIL_V_MSG(EXIT_FAILURE, vformat("Could not load global class %s.", main_loop_type));
4271
}
4272
StringName script_base = script_res->get_instance_base_type();
4273
Object *obj = ClassDB::instantiate(script_base);
4274
MainLoop *script_loop = Object::cast_to<MainLoop>(obj);
4275
if (!script_loop) {
4276
if (obj) {
4277
memdelete(obj);
4278
}
4279
OS::get_singleton()->alert("Error: Invalid MainLoop script base type: " + script_base);
4280
ERR_FAIL_V_MSG(EXIT_FAILURE, vformat("The global class %s does not inherit from SceneTree or MainLoop.", main_loop_type));
4281
}
4282
script_loop->set_script(script_res);
4283
main_loop = script_loop;
4284
}
4285
}
4286
4287
if (!main_loop && main_loop_type.is_empty()) {
4288
main_loop_type = "SceneTree";
4289
}
4290
4291
if (!main_loop) {
4292
if (!ClassDB::class_exists(main_loop_type)) {
4293
OS::get_singleton()->alert("Error: MainLoop type doesn't exist: " + main_loop_type);
4294
return EXIT_FAILURE;
4295
} else {
4296
Object *ml = ClassDB::instantiate(main_loop_type);
4297
ERR_FAIL_NULL_V_MSG(ml, EXIT_FAILURE, "Can't instance MainLoop type.");
4298
4299
main_loop = Object::cast_to<MainLoop>(ml);
4300
if (!main_loop) {
4301
memdelete(ml);
4302
ERR_FAIL_V_MSG(EXIT_FAILURE, "Invalid MainLoop type.");
4303
}
4304
}
4305
}
4306
4307
OS::get_singleton()->set_main_loop(main_loop);
4308
4309
SceneTree *sml = Object::cast_to<SceneTree>(main_loop);
4310
if (sml) {
4311
#ifdef DEBUG_ENABLED
4312
if (debug_collisions) {
4313
sml->set_debug_collisions_hint(true);
4314
}
4315
if (debug_paths) {
4316
sml->set_debug_paths_hint(true);
4317
}
4318
4319
if (debug_navigation) {
4320
sml->set_debug_navigation_hint(true);
4321
#ifndef NAVIGATION_2D_DISABLED
4322
NavigationServer2D::get_singleton()->set_debug_navigation_enabled(true);
4323
#endif // NAVIGATION_2D_DISABLED
4324
#ifndef NAVIGATION_3D_DISABLED
4325
NavigationServer3D::get_singleton()->set_debug_navigation_enabled(true);
4326
#endif // NAVIGATION_3D_DISABLED
4327
}
4328
if (debug_avoidance) {
4329
#ifndef NAVIGATION_2D_DISABLED
4330
NavigationServer2D::get_singleton()->set_debug_avoidance_enabled(true);
4331
#endif // NAVIGATION_2D_DISABLED
4332
#ifndef NAVIGATION_3D_DISABLED
4333
NavigationServer3D::get_singleton()->set_debug_avoidance_enabled(true);
4334
#endif // NAVIGATION_3D_DISABLED
4335
}
4336
if (debug_navigation || debug_avoidance) {
4337
#ifndef NAVIGATION_2D_DISABLED
4338
NavigationServer2D::get_singleton()->set_active(true);
4339
NavigationServer2D::get_singleton()->set_debug_enabled(true);
4340
#endif // NAVIGATION_2D_DISABLED
4341
#ifndef NAVIGATION_3D_DISABLED
4342
NavigationServer3D::get_singleton()->set_active(true);
4343
NavigationServer3D::get_singleton()->set_debug_enabled(true);
4344
#endif // NAVIGATION_3D_DISABLED
4345
}
4346
if (debug_canvas_item_redraw) {
4347
RenderingServer::get_singleton()->canvas_item_set_debug_redraw(true);
4348
}
4349
4350
if (debug_mute_audio) {
4351
AudioServer::get_singleton()->set_debug_mute(true);
4352
}
4353
#endif
4354
4355
if (single_threaded_scene) {
4356
sml->set_disable_node_threading(true);
4357
}
4358
4359
bool embed_subwindows = GLOBAL_GET("display/window/subwindows/embed_subwindows");
4360
4361
if (single_window || (!project_manager && !editor && embed_subwindows) || !DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) {
4362
sml->get_root()->set_embedding_subwindows(true);
4363
}
4364
4365
ResourceLoader::add_custom_loaders();
4366
ResourceSaver::add_custom_savers();
4367
4368
if (!project_manager && !editor) { // game
4369
if (!game_path.is_empty() || !script.is_empty()) {
4370
//autoload
4371
OS::get_singleton()->benchmark_begin_measure("Startup", "Load Autoloads");
4372
HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads(ProjectSettings::get_singleton()->get_autoload_list());
4373
4374
//first pass, add the constants so they exist before any script is loaded
4375
for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
4376
const ProjectSettings::AutoloadInfo &info = E.value;
4377
4378
if (info.is_singleton) {
4379
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
4380
ScriptServer::get_language(i)->add_global_constant(info.name, Variant());
4381
}
4382
}
4383
}
4384
4385
//second pass, load into global constants
4386
List<Node *> to_add;
4387
for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
4388
const ProjectSettings::AutoloadInfo &info = E.value;
4389
4390
Node *n = nullptr;
4391
if (ResourceLoader::get_resource_type(info.path) == "PackedScene") {
4392
// Cache the scene reference before loading it (for cyclic references)
4393
Ref<PackedScene> scn;
4394
scn.instantiate();
4395
scn->set_path(ResourceUID::ensure_path(info.path));
4396
scn->reload_from_file();
4397
ERR_CONTINUE_MSG(scn.is_null(), vformat("Failed to instantiate an autoload, can't load from path: %s.", info.path));
4398
4399
if (scn.is_valid()) {
4400
n = scn->instantiate();
4401
}
4402
} else {
4403
Ref<Resource> res = ResourceLoader::load(info.path);
4404
ERR_CONTINUE_MSG(res.is_null(), vformat("Failed to instantiate an autoload, can't load from path: %s.", info.path));
4405
4406
Ref<Script> script_res = res;
4407
if (script_res.is_valid()) {
4408
StringName ibt = script_res->get_instance_base_type();
4409
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
4410
ERR_CONTINUE_MSG(!valid_type, vformat("Failed to instantiate an autoload, script '%s' does not inherit from 'Node'.", info.path));
4411
4412
Object *obj = ClassDB::instantiate(ibt);
4413
ERR_CONTINUE_MSG(!obj, vformat("Failed to instantiate an autoload, cannot instantiate '%s'.", ibt));
4414
4415
n = Object::cast_to<Node>(obj);
4416
n->set_script(script_res);
4417
}
4418
}
4419
4420
ERR_CONTINUE_MSG(!n, vformat("Failed to instantiate an autoload, path is not pointing to a scene or a script: %s.", info.path));
4421
n->set_name(info.name);
4422
4423
//defer so references are all valid on _ready()
4424
to_add.push_back(n);
4425
4426
if (info.is_singleton) {
4427
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
4428
ScriptServer::get_language(i)->add_global_constant(info.name, n);
4429
}
4430
}
4431
}
4432
4433
for (Node *E : to_add) {
4434
sml->get_root()->add_child(E);
4435
}
4436
OS::get_singleton()->benchmark_end_measure("Startup", "Load Autoloads");
4437
}
4438
}
4439
4440
#ifdef TOOLS_ENABLED
4441
#ifdef MODULE_GDSCRIPT_ENABLED
4442
if (!doc_tool_path.is_empty() && !gdscript_docs_path.is_empty()) {
4443
DocTools docs;
4444
Error err;
4445
4446
Vector<String> paths = get_files_with_extension(gdscript_docs_path, "gd");
4447
ERR_FAIL_COND_V_MSG(paths.is_empty(), EXIT_FAILURE, "Couldn't find any GDScript files under the given directory: " + gdscript_docs_path);
4448
4449
for (const String &path : paths) {
4450
Ref<GDScript> gdscript = ResourceLoader::load(path);
4451
for (const DocData::ClassDoc &class_doc : gdscript->get_documentation()) {
4452
docs.add_doc(class_doc);
4453
}
4454
}
4455
4456
if (doc_tool_implicit_cwd) {
4457
doc_tool_path = "./docs";
4458
}
4459
4460
Ref<DirAccess> da = DirAccess::create_for_path(doc_tool_path);
4461
err = da->make_dir_recursive(doc_tool_path);
4462
ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error: Can't create GDScript docs directory: " + doc_tool_path + ": " + itos(err));
4463
4464
HashMap<String, String> doc_data_classes;
4465
err = docs.save_classes(doc_tool_path, doc_data_classes, false);
4466
ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error saving GDScript docs:" + itos(err));
4467
4468
return EXIT_SUCCESS;
4469
}
4470
#endif // MODULE_GDSCRIPT_ENABLED
4471
4472
EditorNode *editor_node = nullptr;
4473
if (editor) {
4474
OS::get_singleton()->benchmark_begin_measure("Startup", "Editor");
4475
4476
sml->get_root()->set_translation_domain("godot.editor");
4477
if (editor_pseudolocalization) {
4478
translation_server->get_editor_domain()->set_pseudolocalization_enabled(true);
4479
}
4480
4481
editor_node = memnew(EditorNode);
4482
sml->get_root()->add_child(editor_node);
4483
4484
if (!_export_preset.is_empty()) {
4485
editor_node->export_preset(_export_preset, positional_arg, export_debug, export_pack_only, install_android_build_template, export_patch, patches);
4486
game_path = ""; // Do not load anything.
4487
}
4488
4489
OS::get_singleton()->benchmark_end_measure("Startup", "Editor");
4490
}
4491
#endif
4492
sml->set_auto_accept_quit(GLOBAL_GET("application/config/auto_accept_quit"));
4493
sml->set_quit_on_go_back(GLOBAL_GET("application/config/quit_on_go_back"));
4494
4495
if (!editor && !project_manager) {
4496
//standard helpers that can be changed from main config
4497
4498
String stretch_mode = GLOBAL_GET("display/window/stretch/mode");
4499
String stretch_aspect = GLOBAL_GET("display/window/stretch/aspect");
4500
Size2i stretch_size = Size2i(GLOBAL_GET("display/window/size/viewport_width"),
4501
GLOBAL_GET("display/window/size/viewport_height"));
4502
real_t stretch_scale = GLOBAL_GET("display/window/stretch/scale");
4503
String stretch_scale_mode = GLOBAL_GET("display/window/stretch/scale_mode");
4504
4505
Window::ContentScaleMode cs_sm = Window::CONTENT_SCALE_MODE_DISABLED;
4506
if (stretch_mode == "canvas_items") {
4507
cs_sm = Window::CONTENT_SCALE_MODE_CANVAS_ITEMS;
4508
} else if (stretch_mode == "viewport") {
4509
cs_sm = Window::CONTENT_SCALE_MODE_VIEWPORT;
4510
}
4511
4512
Window::ContentScaleAspect cs_aspect = Window::CONTENT_SCALE_ASPECT_IGNORE;
4513
if (stretch_aspect == "keep") {
4514
cs_aspect = Window::CONTENT_SCALE_ASPECT_KEEP;
4515
} else if (stretch_aspect == "keep_width") {
4516
cs_aspect = Window::CONTENT_SCALE_ASPECT_KEEP_WIDTH;
4517
} else if (stretch_aspect == "keep_height") {
4518
cs_aspect = Window::CONTENT_SCALE_ASPECT_KEEP_HEIGHT;
4519
} else if (stretch_aspect == "expand") {
4520
cs_aspect = Window::CONTENT_SCALE_ASPECT_EXPAND;
4521
}
4522
4523
Window::ContentScaleStretch cs_stretch = Window::CONTENT_SCALE_STRETCH_FRACTIONAL;
4524
if (stretch_scale_mode == "integer") {
4525
cs_stretch = Window::CONTENT_SCALE_STRETCH_INTEGER;
4526
}
4527
4528
sml->get_root()->set_content_scale_mode(cs_sm);
4529
sml->get_root()->set_content_scale_aspect(cs_aspect);
4530
sml->get_root()->set_content_scale_stretch(cs_stretch);
4531
sml->get_root()->set_content_scale_size(stretch_size);
4532
sml->get_root()->set_content_scale_factor(stretch_scale);
4533
4534
sml->set_auto_accept_quit(GLOBAL_GET("application/config/auto_accept_quit"));
4535
sml->set_quit_on_go_back(GLOBAL_GET("application/config/quit_on_go_back"));
4536
String appname = GLOBAL_GET("application/config/name");
4537
appname = TranslationServer::get_singleton()->translate(appname);
4538
#ifdef DEBUG_ENABLED
4539
// Append a suffix to the window title to denote that the project is running
4540
// from a debug build (including the editor). Since this results in lower performance,
4541
// this should be clearly presented to the user.
4542
DisplayServer::get_singleton()->window_set_title(vformat("%s (DEBUG)", appname));
4543
#else
4544
DisplayServer::get_singleton()->window_set_title(appname);
4545
#endif
4546
4547
bool snap_controls = GLOBAL_GET("gui/common/snap_controls_to_pixels");
4548
sml->get_root()->set_snap_controls_to_pixels(snap_controls);
4549
4550
int drag_threshold = GLOBAL_GET("gui/common/drag_threshold");
4551
sml->get_root()->set_drag_threshold(drag_threshold);
4552
4553
bool font_oversampling = GLOBAL_GET("gui/fonts/dynamic_fonts/use_oversampling");
4554
sml->get_root()->set_use_oversampling(font_oversampling);
4555
4556
int texture_filter = GLOBAL_GET("rendering/textures/canvas_textures/default_texture_filter");
4557
int texture_repeat = GLOBAL_GET("rendering/textures/canvas_textures/default_texture_repeat");
4558
sml->get_root()->set_default_canvas_item_texture_filter(
4559
Viewport::DefaultCanvasItemTextureFilter(texture_filter));
4560
sml->get_root()->set_default_canvas_item_texture_repeat(
4561
Viewport::DefaultCanvasItemTextureRepeat(texture_repeat));
4562
}
4563
4564
#ifdef TOOLS_ENABLED
4565
if (editor) {
4566
bool editor_embed_subwindows = EDITOR_GET("interface/editor/single_window_mode");
4567
4568
if (editor_embed_subwindows) {
4569
sml->get_root()->set_embedding_subwindows(true);
4570
}
4571
restore_editor_window_layout = EDITOR_GET("interface/editor/editor_screen").operator int() == EditorSettings::InitialScreen::INITIAL_SCREEN_AUTO;
4572
}
4573
#endif
4574
4575
String local_game_path;
4576
if (!game_path.is_empty() && !project_manager) {
4577
local_game_path = game_path.replace_char('\\', '/');
4578
4579
if (!local_game_path.begins_with("res://")) {
4580
bool absolute =
4581
(local_game_path.size() > 1) && (local_game_path[0] == '/' || local_game_path[1] == ':');
4582
4583
if (!absolute) {
4584
if (ProjectSettings::get_singleton()->is_using_datapack()) {
4585
local_game_path = "res://" + local_game_path;
4586
4587
} else {
4588
int sep = local_game_path.rfind_char('/');
4589
4590
if (sep == -1) {
4591
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
4592
ERR_FAIL_COND_V(da.is_null(), EXIT_FAILURE);
4593
4594
local_game_path = da->get_current_dir().path_join(local_game_path);
4595
} else {
4596
Ref<DirAccess> da = DirAccess::open(local_game_path.substr(0, sep));
4597
if (da.is_valid()) {
4598
local_game_path = da->get_current_dir().path_join(
4599
local_game_path.substr(sep + 1));
4600
}
4601
}
4602
}
4603
}
4604
}
4605
4606
local_game_path = ProjectSettings::get_singleton()->localize_path(local_game_path);
4607
4608
#ifdef TOOLS_ENABLED
4609
if (editor) {
4610
if (!recovery_mode && (game_path != ResourceUID::ensure_path(String(GLOBAL_GET("application/run/main_scene"))) || !editor_node->has_scenes_in_session())) {
4611
Error serr = editor_node->load_scene(local_game_path);
4612
if (serr != OK) {
4613
ERR_PRINT("Failed to load scene");
4614
}
4615
}
4616
if (!debug_server_uri.is_empty()) {
4617
EditorDebuggerNode::get_singleton()->start(debug_server_uri);
4618
EditorDebuggerNode::get_singleton()->set_keep_open(true);
4619
}
4620
}
4621
#endif
4622
}
4623
4624
if (!project_manager && !editor) { // game
4625
4626
OS::get_singleton()->benchmark_begin_measure("Startup", "Load Game");
4627
4628
// Load SSL Certificates from Project Settings (or builtin).
4629
Crypto::load_default_certificates(GLOBAL_GET("network/tls/certificate_bundle_override"));
4630
4631
if (!game_path.is_empty()) {
4632
Node *scene = nullptr;
4633
Ref<PackedScene> scenedata = ResourceLoader::load(local_game_path);
4634
if (scenedata.is_valid()) {
4635
scene = scenedata->instantiate();
4636
}
4637
4638
ERR_FAIL_NULL_V_MSG(scene, EXIT_FAILURE, "Failed loading scene: " + local_game_path + ".");
4639
sml->add_current_scene(scene);
4640
4641
#ifdef MACOS_ENABLED
4642
#ifndef TOOLS_ENABLED
4643
if ((FileAccess::exists(OS::get_singleton()->get_bundle_resource_dir().path_join("Assets.car")) && !OS::get_singleton()->get_bundle_icon_name().is_empty()) || (!OS::get_singleton()->get_bundle_icon_path().is_empty())) {
4644
has_icon = true; // Bundle has embedded icon, do not override with project icon.
4645
}
4646
#endif
4647
String mac_icon_path = GLOBAL_GET("application/config/macos_native_icon");
4648
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_ICON) && !mac_icon_path.is_empty() && !has_icon) {
4649
DisplayServer::get_singleton()->set_native_icon(mac_icon_path);
4650
has_icon = true;
4651
}
4652
#endif
4653
4654
#ifdef WINDOWS_ENABLED
4655
String win_icon_path = GLOBAL_GET("application/config/windows_native_icon");
4656
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_ICON) && !win_icon_path.is_empty()) {
4657
DisplayServer::get_singleton()->set_native_icon(win_icon_path);
4658
has_icon = true;
4659
}
4660
#endif
4661
4662
String icon_path = GLOBAL_GET("application/config/icon");
4663
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_ICON) && !icon_path.is_empty() && !has_icon) {
4664
Ref<Image> icon;
4665
icon.instantiate();
4666
if (ImageLoader::load_image(icon_path, icon) == OK) {
4667
DisplayServer::get_singleton()->set_icon(icon);
4668
has_icon = true;
4669
}
4670
}
4671
}
4672
4673
OS::get_singleton()->benchmark_end_measure("Startup", "Load Game");
4674
}
4675
4676
#ifdef TOOLS_ENABLED
4677
if (project_manager) {
4678
OS::get_singleton()->benchmark_begin_measure("Startup", "Project Manager");
4679
Engine::get_singleton()->set_editor_hint(true);
4680
4681
sml->get_root()->set_translation_domain("godot.editor");
4682
if (editor_pseudolocalization) {
4683
translation_server->get_editor_domain()->set_pseudolocalization_enabled(true);
4684
}
4685
4686
ProjectManager *pmanager = memnew(ProjectManager);
4687
ProgressDialog *progress_dialog = memnew(ProgressDialog);
4688
pmanager->add_child(progress_dialog);
4689
4690
sml->get_root()->add_child(pmanager);
4691
OS::get_singleton()->benchmark_end_measure("Startup", "Project Manager");
4692
}
4693
4694
if (project_manager || editor) {
4695
// Load SSL Certificates from Editor Settings (or builtin)
4696
Crypto::load_default_certificates(
4697
EditorSettings::get_singleton()->get_setting("network/tls/editor_tls_certificates").operator String());
4698
}
4699
4700
if (recovery_mode) {
4701
Engine::get_singleton()->set_recovery_mode_hint(true);
4702
}
4703
#endif
4704
}
4705
4706
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_ICON) && !has_icon && OS::get_singleton()->get_bundle_icon_path().is_empty()) {
4707
Ref<Image> icon = memnew(Image(app_icon_png));
4708
DisplayServer::get_singleton()->set_icon(icon);
4709
}
4710
4711
if (movie_writer) {
4712
Size2i movie_size = Size2i(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
4713
String stretch_mode = GLOBAL_GET("display/window/stretch/mode");
4714
if (stretch_mode != "viewport") {
4715
// `canvas_items` and `disabled` modes use the window size override instead,
4716
// which allows for higher resolution recording with 2D elements designed for a lower resolution.
4717
const int window_width_override = GLOBAL_GET("display/window/size/window_width_override");
4718
if (window_width_override > 0) {
4719
movie_size.width = window_width_override;
4720
}
4721
const int window_height_override = GLOBAL_GET("display/window/size/window_height_override");
4722
if (window_height_override > 0) {
4723
movie_size.height = window_height_override;
4724
}
4725
}
4726
movie_writer->begin(movie_size, fixed_fps, Engine::get_singleton()->get_write_movie_path());
4727
}
4728
4729
GDExtensionManager::get_singleton()->startup();
4730
4731
#ifdef MACOS_ENABLED
4732
// TODO: Used to fix full-screen splash drawing on macOS, processing events before main loop is fully initialized cause issues on Wayland, and has no effect on other platforms.
4733
if (minimum_time_msec) {
4734
int64_t minimum_time = 1000 * minimum_time_msec;
4735
uint64_t prev_time = OS::get_singleton()->get_ticks_usec();
4736
while (minimum_time > 0) {
4737
DisplayServer::get_singleton()->process_events();
4738
OS::get_singleton()->delay_usec(100);
4739
4740
uint64_t next_time = OS::get_singleton()->get_ticks_usec();
4741
minimum_time -= (next_time - prev_time);
4742
prev_time = next_time;
4743
}
4744
} else {
4745
DisplayServer::get_singleton()->process_events();
4746
}
4747
#else
4748
if (minimum_time_msec) {
4749
uint64_t minimum_time = 1000 * minimum_time_msec;
4750
uint64_t elapsed_time = OS::get_singleton()->get_ticks_usec();
4751
if (elapsed_time < minimum_time) {
4752
OS::get_singleton()->delay_usec(minimum_time - elapsed_time);
4753
}
4754
}
4755
#endif
4756
4757
OS::get_singleton()->benchmark_end_measure("Startup", "Main::Start");
4758
OS::get_singleton()->benchmark_dump();
4759
4760
return EXIT_SUCCESS;
4761
}
4762
4763
/* Main iteration
4764
*
4765
* This is the iteration of the engine's game loop, advancing the state of physics,
4766
* rendering and audio.
4767
* It's called directly by the platform's OS::run method, where the loop is created
4768
* and monitored.
4769
*
4770
* The OS implementation can impact its draw step with the Main::force_redraw() method.
4771
*/
4772
4773
uint64_t Main::last_ticks = 0;
4774
uint32_t Main::frames = 0;
4775
uint32_t Main::hide_print_fps_attempts = 3;
4776
uint32_t Main::frame = 0;
4777
bool Main::force_redraw_requested = false;
4778
int Main::iterating = 0;
4779
4780
bool Main::is_iterating() {
4781
return iterating > 0;
4782
}
4783
4784
// For performance metrics.
4785
static uint64_t physics_process_max = 0;
4786
static uint64_t process_max = 0;
4787
static uint64_t navigation_process_max = 0;
4788
4789
// Return false means iterating further, returning true means `OS::run`
4790
// will terminate the program. In case of failure, the OS exit code needs
4791
// to be set explicitly here (defaults to EXIT_SUCCESS).
4792
bool Main::iteration() {
4793
GodotProfileZone("Main::iteration");
4794
GodotProfileZoneGroupedFirst(_profile_zone, "prepare");
4795
iterating++;
4796
4797
const uint64_t ticks = OS::get_singleton()->get_ticks_usec();
4798
Engine::get_singleton()->_frame_ticks = ticks;
4799
main_timer_sync.set_cpu_ticks_usec(ticks);
4800
main_timer_sync.set_fixed_fps(fixed_fps);
4801
4802
const uint64_t ticks_elapsed = ticks - last_ticks;
4803
4804
const int physics_ticks_per_second = Engine::get_singleton()->get_user_physics_ticks_per_second();
4805
const double physics_step = 1.0 / physics_ticks_per_second;
4806
4807
const double time_scale = Engine::get_singleton()->get_effective_time_scale();
4808
4809
MainFrameTime advance = main_timer_sync.advance(physics_step, physics_ticks_per_second);
4810
double process_step = advance.process_step;
4811
double scaled_step = process_step * time_scale;
4812
4813
Engine::get_singleton()->_process_step = process_step;
4814
Engine::get_singleton()->_physics_interpolation_fraction = advance.interpolation_fraction;
4815
4816
uint64_t physics_process_ticks = 0;
4817
uint64_t process_ticks = 0;
4818
#if !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
4819
uint64_t navigation_process_ticks = 0;
4820
#endif // !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
4821
4822
frame += ticks_elapsed;
4823
4824
last_ticks = ticks;
4825
4826
const int max_physics_steps = Engine::get_singleton()->get_user_max_physics_steps_per_frame();
4827
if (fixed_fps == -1 && advance.physics_steps > max_physics_steps) {
4828
process_step -= (advance.physics_steps - max_physics_steps) * physics_step;
4829
advance.physics_steps = max_physics_steps;
4830
}
4831
4832
bool exit = false;
4833
4834
// process all our active interfaces
4835
#ifndef XR_DISABLED
4836
GodotProfileZoneGrouped(_profile_zone, "xr_server->_process");
4837
XRServer::get_singleton()->_process();
4838
#endif // XR_DISABLED
4839
4840
GodotProfileZoneGrouped(_profile_zone, "physics");
4841
for (int iters = 0; iters < advance.physics_steps; ++iters) {
4842
GodotProfileZone("Physics Step");
4843
GodotProfileZoneGroupedFirst(_physics_zone, "setup");
4844
if (Input::get_singleton()->is_agile_input_event_flushing()) {
4845
Input::get_singleton()->flush_buffered_events();
4846
}
4847
4848
Engine::get_singleton()->_in_physics = true;
4849
Engine::get_singleton()->_physics_frames++;
4850
4851
uint64_t physics_begin = OS::get_singleton()->get_ticks_usec();
4852
4853
// Prepare the fixed timestep interpolated nodes BEFORE they are updated
4854
// by the physics server, otherwise the current and previous transforms
4855
// may be the same, and no interpolation takes place.
4856
GodotProfileZoneGrouped(_physics_zone, "main loop iteration prepare");
4857
OS::get_singleton()->get_main_loop()->iteration_prepare();
4858
4859
#ifndef PHYSICS_3D_DISABLED
4860
GodotProfileZoneGrouped(_physics_zone, "PhysicsServer3D::sync");
4861
PhysicsServer3D::get_singleton()->sync();
4862
PhysicsServer3D::get_singleton()->flush_queries();
4863
#endif // PHYSICS_3D_DISABLED
4864
4865
#ifndef PHYSICS_2D_DISABLED
4866
GodotProfileZoneGrouped(_physics_zone, "PhysicsServer2D::sync");
4867
PhysicsServer2D::get_singleton()->sync();
4868
PhysicsServer2D::get_singleton()->flush_queries();
4869
#endif // PHYSICS_2D_DISABLED
4870
4871
GodotProfileZoneGrouped(_physics_zone, "physics_process");
4872
if (OS::get_singleton()->get_main_loop()->physics_process(physics_step * time_scale)) {
4873
#ifndef PHYSICS_3D_DISABLED
4874
PhysicsServer3D::get_singleton()->end_sync();
4875
#endif // PHYSICS_3D_DISABLED
4876
#ifndef PHYSICS_2D_DISABLED
4877
PhysicsServer2D::get_singleton()->end_sync();
4878
#endif // PHYSICS_2D_DISABLED
4879
4880
Engine::get_singleton()->_in_physics = false;
4881
exit = true;
4882
break;
4883
}
4884
4885
#if !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
4886
uint64_t navigation_begin = OS::get_singleton()->get_ticks_usec();
4887
4888
#ifndef NAVIGATION_2D_DISABLED
4889
GodotProfileZoneGrouped(_profile_zone, "NavigationServer2D::physics_process");
4890
NavigationServer2D::get_singleton()->physics_process(physics_step * time_scale);
4891
#endif // NAVIGATION_2D_DISABLED
4892
#ifndef NAVIGATION_3D_DISABLED
4893
GodotProfileZoneGrouped(_profile_zone, "NavigationServer3D::physics_process");
4894
NavigationServer3D::get_singleton()->physics_process(physics_step * time_scale);
4895
#endif // NAVIGATION_3D_DISABLED
4896
4897
navigation_process_ticks = MAX(navigation_process_ticks, OS::get_singleton()->get_ticks_usec() - navigation_begin); // keep the largest one for reference
4898
navigation_process_max = MAX(OS::get_singleton()->get_ticks_usec() - navigation_begin, navigation_process_max);
4899
4900
message_queue->flush();
4901
#endif // !defined(NAVIGATION_2D_DISABLED) || !defined(NAVIGATION_3D_DISABLED)
4902
4903
#ifndef PHYSICS_3D_DISABLED
4904
GodotProfileZoneGrouped(_profile_zone, "3D physics");
4905
PhysicsServer3D::get_singleton()->end_sync();
4906
PhysicsServer3D::get_singleton()->step(physics_step * time_scale);
4907
#endif // PHYSICS_3D_DISABLED
4908
4909
#ifndef PHYSICS_2D_DISABLED
4910
GodotProfileZoneGrouped(_profile_zone, "2D physics");
4911
PhysicsServer2D::get_singleton()->end_sync();
4912
PhysicsServer2D::get_singleton()->step(physics_step * time_scale);
4913
#endif // PHYSICS_2D_DISABLED
4914
4915
message_queue->flush();
4916
4917
GodotProfileZoneGrouped(_profile_zone, "main loop iteration end");
4918
OS::get_singleton()->get_main_loop()->iteration_end();
4919
4920
physics_process_ticks = MAX(physics_process_ticks, OS::get_singleton()->get_ticks_usec() - physics_begin); // keep the largest one for reference
4921
physics_process_max = MAX(OS::get_singleton()->get_ticks_usec() - physics_begin, physics_process_max);
4922
4923
Engine::get_singleton()->_in_physics = false;
4924
}
4925
4926
if (Input::get_singleton()->is_agile_input_event_flushing()) {
4927
Input::get_singleton()->flush_buffered_events();
4928
}
4929
4930
uint64_t process_begin = OS::get_singleton()->get_ticks_usec();
4931
4932
GodotProfileZoneGrouped(_profile_zone, "process");
4933
if (OS::get_singleton()->get_main_loop()->process(process_step * time_scale)) {
4934
exit = true;
4935
}
4936
message_queue->flush();
4937
4938
#ifndef NAVIGATION_2D_DISABLED
4939
GodotProfileZoneGrouped(_profile_zone, "process 2D navigation");
4940
NavigationServer2D::get_singleton()->process(process_step * time_scale);
4941
#endif // NAVIGATION_2D_DISABLED
4942
#ifndef NAVIGATION_3D_DISABLED
4943
GodotProfileZoneGrouped(_profile_zone, "process 3D navigation");
4944
NavigationServer3D::get_singleton()->process(process_step * time_scale);
4945
#endif // NAVIGATION_3D_DISABLED
4946
4947
GodotProfileZoneGrouped(_profile_zone, "RenderingServer::sync");
4948
RenderingServer::get_singleton()->sync(); //sync if still drawing from previous frames.
4949
4950
GodotProfileZoneGrouped(_profile_zone, "RenderingServer::draw");
4951
const bool has_pending_resources_for_processing = RD::get_singleton() && RD::get_singleton()->has_pending_resources_for_processing();
4952
bool wants_present = (DisplayServer::get_singleton()->can_any_window_draw() ||
4953
DisplayServer::get_singleton()->has_additional_outputs()) &&
4954
RenderingServer::get_singleton()->is_render_loop_enabled();
4955
4956
if (wants_present || has_pending_resources_for_processing) {
4957
wants_present |= force_redraw_requested;
4958
if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) {
4959
if (RenderingServer::get_singleton()->has_changed()) {
4960
RenderingServer::get_singleton()->draw(wants_present, scaled_step); // flush visual commands
4961
Engine::get_singleton()->increment_frames_drawn();
4962
}
4963
} else {
4964
RenderingServer::get_singleton()->draw(wants_present, scaled_step); // flush visual commands
4965
Engine::get_singleton()->increment_frames_drawn();
4966
force_redraw_requested = false;
4967
}
4968
}
4969
4970
process_ticks = OS::get_singleton()->get_ticks_usec() - process_begin;
4971
process_max = MAX(process_ticks, process_max);
4972
uint64_t frame_time = OS::get_singleton()->get_ticks_usec() - ticks;
4973
4974
GodotProfileZoneGrouped(_profile_zone, "GDExtensionManager::frame");
4975
GDExtensionManager::get_singleton()->frame();
4976
4977
GodotProfileZoneGrouped(_profile_zone, "ScriptServer::frame");
4978
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
4979
ScriptServer::get_language(i)->frame();
4980
}
4981
4982
GodotProfileZoneGrouped(_profile_zone, "AudioServer::update");
4983
AudioServer::get_singleton()->update();
4984
4985
if (EngineDebugger::is_active()) {
4986
EngineDebugger::get_singleton()->iteration(frame_time, process_ticks, physics_process_ticks, physics_step);
4987
}
4988
4989
frames++;
4990
Engine::get_singleton()->_process_frames++;
4991
4992
if (frame > 1000000) {
4993
// Wait a few seconds before printing FPS, as FPS reporting just after the engine has started is inaccurate.
4994
if (hide_print_fps_attempts == 0) {
4995
if (editor || project_manager) {
4996
if (print_fps) {
4997
print_line(vformat("Editor FPS: %d (%s mspf)", frames, rtos(1000.0 / frames).pad_decimals(2)));
4998
}
4999
} else if (print_fps || GLOBAL_GET("debug/settings/stdout/print_fps")) {
5000
print_line(vformat("Project FPS: %d (%s mspf)", frames, rtos(1000.0 / frames).pad_decimals(2)));
5001
}
5002
} else {
5003
hide_print_fps_attempts--;
5004
}
5005
5006
Engine::get_singleton()->_fps = frames;
5007
performance->set_process_time(USEC_TO_SEC(process_max));
5008
performance->set_physics_process_time(USEC_TO_SEC(physics_process_max));
5009
performance->set_navigation_process_time(USEC_TO_SEC(navigation_process_max));
5010
process_max = 0;
5011
physics_process_max = 0;
5012
navigation_process_max = 0;
5013
5014
frame %= 1000000;
5015
frames = 0;
5016
}
5017
5018
iterating--;
5019
5020
if (movie_writer) {
5021
GodotProfileZoneGrouped(_profile_zone, "movie_writer->add_frame");
5022
movie_writer->add_frame();
5023
}
5024
5025
#ifdef TOOLS_ENABLED
5026
bool quit_after_timeout = false;
5027
#endif
5028
if ((quit_after > 0) && (Engine::get_singleton()->_process_frames >= quit_after)) {
5029
#ifdef TOOLS_ENABLED
5030
quit_after_timeout = true;
5031
#endif
5032
exit = true;
5033
}
5034
5035
#ifdef TOOLS_ENABLED
5036
if (wait_for_import && EditorFileSystem::get_singleton() && EditorFileSystem::get_singleton()->doing_first_scan()) {
5037
exit = false;
5038
}
5039
#endif
5040
5041
if (fixed_fps != -1) {
5042
return exit;
5043
}
5044
5045
SceneTree *scene_tree = SceneTree::get_singleton();
5046
bool wake_for_events = scene_tree && scene_tree->is_accessibility_enabled();
5047
5048
GodotProfileZoneGrouped(_profile_zone, "OS::add_frame_delay");
5049
OS::get_singleton()->add_frame_delay(DisplayServer::get_singleton()->window_can_draw(), wake_for_events);
5050
5051
#ifdef TOOLS_ENABLED
5052
if (auto_build_solutions) {
5053
auto_build_solutions = false;
5054
// Only relevant when running the editor.
5055
if (!editor) {
5056
OS::get_singleton()->set_exit_code(EXIT_FAILURE);
5057
ERR_FAIL_V_MSG(true,
5058
"Command line option --build-solutions was passed, but no project is being edited. Aborting.");
5059
}
5060
if (!EditorNode::get_singleton()->call_build()) {
5061
OS::get_singleton()->set_exit_code(EXIT_FAILURE);
5062
ERR_FAIL_V_MSG(true,
5063
"Command line option --build-solutions was passed, but the build callback failed. Aborting.");
5064
}
5065
}
5066
#endif
5067
5068
#ifdef TOOLS_ENABLED
5069
if (exit && quit_after_timeout && EditorNode::get_singleton()) {
5070
EditorNode::get_singleton()->unload_editor_addons();
5071
}
5072
#endif
5073
5074
return exit;
5075
}
5076
5077
void Main::force_redraw() {
5078
force_redraw_requested = true;
5079
}
5080
5081
/* Engine deinitialization
5082
*
5083
* Responsible for freeing all the memory allocated by previous setup steps,
5084
* so that the engine closes cleanly without leaking memory or crashing.
5085
* The order matters as some of those steps are linked with each other.
5086
*/
5087
void Main::cleanup(bool p_force) {
5088
GodotProfileZone("cleanup");
5089
OS::get_singleton()->benchmark_begin_measure("Shutdown", "Main::Cleanup");
5090
if (!p_force) {
5091
ERR_FAIL_COND(!_start_success);
5092
}
5093
5094
#ifdef DEBUG_ENABLED
5095
if (input) {
5096
input->flush_frame_parsed_events();
5097
}
5098
#endif
5099
5100
GDExtensionManager::get_singleton()->shutdown();
5101
5102
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
5103
TextServerManager::get_singleton()->get_interface(i)->cleanup();
5104
}
5105
5106
if (movie_writer) {
5107
movie_writer->end();
5108
}
5109
5110
ResourceLoader::clear_thread_load_tasks();
5111
5112
ResourceLoader::remove_custom_loaders();
5113
ResourceSaver::remove_custom_savers();
5114
PropertyListHelper::clear_base_helpers();
5115
5116
// Remove the lock file if the engine exits successfully. Some automated processes such as
5117
// --export/--import can bypass and/or finish faster than the existing check to remove the lock file.
5118
if (OS::get_singleton()->get_exit_code() == EXIT_SUCCESS) {
5119
OS::get_singleton()->remove_lock_file();
5120
}
5121
5122
// Flush before uninitializing the scene, but delete the MessageQueue as late as possible.
5123
message_queue->flush();
5124
5125
OS::get_singleton()->delete_main_loop();
5126
5127
OS::get_singleton()->_cmdline.clear();
5128
OS::get_singleton()->_user_args.clear();
5129
OS::get_singleton()->_execpath = "";
5130
OS::get_singleton()->_local_clipboard = "";
5131
5132
ResourceLoader::clear_translation_remaps();
5133
5134
WorkerThreadPool::get_singleton()->exit_languages_threads();
5135
5136
ScriptServer::finish_languages();
5137
5138
// Sync pending commands that may have been queued from a different thread during ScriptServer finalization
5139
RenderingServer::get_singleton()->sync();
5140
5141
//clear global shader variables before scene and other graphics stuff are deinitialized.
5142
rendering_server->global_shader_parameters_clear();
5143
5144
#ifndef XR_DISABLED
5145
if (xr_server) {
5146
// Now that we're unregistering properly in plugins we need to keep access to xr_server for a little longer
5147
// We do however unset our primary interface
5148
xr_server->set_primary_interface(Ref<XRInterface>());
5149
}
5150
#endif // XR_DISABLED
5151
5152
#ifdef TOOLS_ENABLED
5153
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR);
5154
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR);
5155
unregister_editor_types();
5156
5157
#endif
5158
5159
ImageLoader::cleanup();
5160
5161
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SCENE);
5162
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE);
5163
5164
unregister_platform_apis();
5165
unregister_driver_types();
5166
unregister_scene_types();
5167
5168
finalize_theme_db();
5169
5170
// Before deinitializing server extensions, finalize servers which may be loaded as extensions.
5171
#ifndef NAVIGATION_2D_DISABLED
5172
NavigationServer2DManager::finalize_server();
5173
NavigationServer2DManager::finalize_server_manager();
5174
#endif // NAVIGATION_2D_DISABLED
5175
#ifndef NAVIGATION_3D_DISABLED
5176
NavigationServer3DManager::finalize_server();
5177
NavigationServer3DManager::finalize_server_manager();
5178
#endif // NAVIGATION_3D_DISABLED
5179
finalize_physics();
5180
5181
GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
5182
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
5183
unregister_server_types();
5184
5185
EngineDebugger::deinitialize();
5186
5187
#ifndef XR_DISABLED
5188
if (xr_server) {
5189
memdelete(xr_server);
5190
}
5191
#endif // XR_DISABLED
5192
5193
if (audio_server) {
5194
audio_server->finish();
5195
memdelete(audio_server);
5196
}
5197
5198
if (camera_server) {
5199
memdelete(camera_server);
5200
}
5201
5202
OS::get_singleton()->finalize();
5203
5204
finalize_display();
5205
5206
if (input) {
5207
memdelete(input);
5208
}
5209
5210
if (packed_data) {
5211
memdelete(packed_data);
5212
}
5213
if (performance) {
5214
memdelete(performance);
5215
}
5216
if (input_map) {
5217
memdelete(input_map);
5218
}
5219
if (translation_server) {
5220
memdelete(translation_server);
5221
}
5222
if (tsman) {
5223
memdelete(tsman);
5224
}
5225
#ifndef PHYSICS_3D_DISABLED
5226
if (physics_server_3d_manager) {
5227
memdelete(physics_server_3d_manager);
5228
}
5229
#endif // PHYSICS_3D_DISABLED
5230
#ifndef PHYSICS_2D_DISABLED
5231
if (physics_server_2d_manager) {
5232
memdelete(physics_server_2d_manager);
5233
}
5234
#endif // PHYSICS_2D_DISABLED
5235
if (globals) {
5236
memdelete(globals);
5237
}
5238
5239
if (OS::get_singleton()->is_restart_on_exit_set()) {
5240
//attempt to restart with arguments
5241
List<String> args = OS::get_singleton()->get_restart_on_exit_arguments();
5242
OS::get_singleton()->create_instance(args);
5243
OS::get_singleton()->set_restart_on_exit(false, List<String>()); //clear list (uses memory)
5244
}
5245
5246
// Now should be safe to delete MessageQueue (famous last words).
5247
message_queue->flush();
5248
memdelete(message_queue);
5249
5250
#if defined(STEAMAPI_ENABLED)
5251
if (steam_tracker) {
5252
memdelete(steam_tracker);
5253
}
5254
#endif
5255
5256
unregister_core_driver_types();
5257
unregister_core_extensions();
5258
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
5259
5260
if (engine) {
5261
memdelete(engine);
5262
}
5263
5264
unregister_core_types();
5265
5266
OS::get_singleton()->benchmark_end_measure("Shutdown", "Main::Cleanup");
5267
OS::get_singleton()->benchmark_dump();
5268
5269
OS::get_singleton()->finalize_core();
5270
}
5271
5272