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