godot/main/main.cpp

/**************************************************************************/
/*  main.cpp                                                              */
/**************************************************************************/
/*                         This file is part of:                          */
/*                             GODOT ENGINE                               */
/*                        https://godotengine.org                         */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
/*                                                                        */
/* Permission is hereby granted, free of charge, to any person obtaining  */
/* a copy of this software and associated documentation files (the        */
/* "Software"), to deal in the Software without restriction, including    */
/* without limitation the rights to use, copy, modify, merge, publish,    */
/* distribute, sublicense, and/or sell copies of the Software, and to     */
/* permit persons to whom the Software is furnished to do so, subject to  */
/* the following conditions:                                              */
/*                                                                        */
/* The above copyright notice and this permission notice shall be         */
/* included in all copies or substantial portions of the Software.        */
/*                                                                        */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
/**************************************************************************/

#include "main.h"

#include "core/config/project_settings.h"
#include "core/core_globals.h"
#include "core/crypto/crypto.h"
#include "core/debugger/engine_debugger.h"
#include "core/extension/extension_api_dump.h"
#include "core/extension/gdextension_interface_dump.gen.h"
#include "core/extension/gdextension_manager.h"
#include "core/input/input.h"
#include "core/input/input_map.h"
#include "core/io/dir_access.h"
#include "core/io/file_access_pack.h"
#include "core/io/file_access_zip.h"
#include "core/io/image.h"
#include "core/io/image_loader.h"
#include "core/io/ip.h"
#include "core/io/resource_loader.h"
#include "core/object/message_queue.h"
#include "core/os/os.h"
#include "core/os/time.h"
#include "core/register_core_types.h"
#include "core/string/translation_server.h"
#include "core/version.h"
#include "drivers/register_driver_types.h"
#include "main/app_icon.gen.h"
#include "main/main_timer_sync.h"
#include "main/performance.h"
#include "main/splash.gen.h"
#include "modules/register_module_types.h"
#include "platform/register_platform_apis.h"
#include "scene/main/scene_tree.h"
#include "scene/main/window.h"
#include "scene/property_list_helper.h"
#include "scene/register_scene_types.h"
#include "scene/resources/packed_scene.h"
#include "scene/theme/theme_db.h"
#include "servers/audio_server.h"
#include "servers/camera_server.h"
#include "servers/display_server.h"
#include "servers/movie_writer/movie_writer.h"
#include "servers/movie_writer/movie_writer_mjpeg.h"
#include "servers/navigation_server_3d.h"
#include "servers/navigation_server_3d_dummy.h"
#include "servers/register_server_types.h"
#include "servers/rendering/rendering_server_default.h"
#include "servers/text/text_server_dummy.h"
#include "servers/text_server.h"

// 2D
#include "servers/navigation_server_2d.h"
#include "servers/navigation_server_2d_dummy.h"
#include "servers/physics_server_2d.h"
#include "servers/physics_server_2d_dummy.h"

#ifndef _3D_DISABLED
#include "servers/physics_server_3d.h"
#include "servers/physics_server_3d_dummy.h"
#include "servers/xr_server.h"
#endif // _3D_DISABLED

#ifdef TESTS_ENABLED
#include "tests/test_main.h"
#endif

#ifdef TOOLS_ENABLED
#include "editor/debugger/debug_adapter/debug_adapter_server.h"
#include "editor/debugger/editor_debugger_node.h"
#include "editor/doc_data_class_path.gen.h"
#include "editor/doc_tools.h"
#include "editor/editor_file_system.h"
#include "editor/editor_help.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/editor_settings.h"
#include "editor/editor_translation.h"
#include "editor/progress_dialog.h"
#include "editor/project_manager.h"
#include "editor/register_editor_types.h"

#if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
#include "main/splash_editor.gen.h"
#endif

#ifndef DISABLE_DEPRECATED
#include "editor/project_converter_3_to_4.h"
#endif // DISABLE_DEPRECATED
#endif // TOOLS_ENABLED

#if defined(STEAMAPI_ENABLED)
#include "main/steam_tracker.h"
#endif

#include "modules/modules_enabled.gen.h" // For mono.

#if defined(MODULE_MONO_ENABLED) && defined(TOOLS_ENABLED)
#include "modules/mono/editor/bindings_generator.h"
#endif

#ifdef MODULE_GDSCRIPT_ENABLED
#include "modules/gdscript/gdscript.h"
#if defined(TOOLS_ENABLED) && !defined(GDSCRIPT_NO_LSP)
#include "modules/gdscript/language_server/gdscript_language_server.h"
#endif // TOOLS_ENABLED && !GDSCRIPT_NO_LSP
#endif // MODULE_GDSCRIPT_ENABLED

/* Static members */

// Singletons

// Initialized in setup()
static Engine *engine =;
static ProjectSettings *globals =;
static Input *input =;
static InputMap *input_map =;
static TranslationServer *translation_server =;
static Performance *performance =;
static PackedData *packed_data =;
#ifdef MINIZIP_ENABLED
static ZipArchive *zip_packed_data =;
#endif
static MessageQueue *message_queue =;

#if defined(STEAMAPI_ENABLED)
static SteamTracker *steam_tracker = nullptr;
#endif

// Initialized in setup2()
static AudioServer *audio_server =;
static CameraServer *camera_server =;
static DisplayServer *display_server =;
static RenderingServer *rendering_server =;
static TextServerManager *tsman =;
static ThemeDB *theme_db =;
static NavigationServer2D *navigation_server_2d =;
static PhysicsServer2DManager *physics_server_2d_manager =;
static PhysicsServer2D *physics_server_2d =;
static NavigationServer3D *navigation_server_3d =;
#ifndef _3D_DISABLED
static PhysicsServer3DManager *physics_server_3d_manager =;
static PhysicsServer3D *physics_server_3d =;
static XRServer *xr_server =;
#endif // _3D_DISABLED
// We error out if setup2() doesn't turn this true
static bool _start_success =;

// Drivers

String display_driver =;
String tablet_driver =;
String text_driver =;
String rendering_driver =;
String rendering_method =;
static int text_driver_idx =;
static int audio_driver_idx =;

// Engine config/tools

static bool single_window =;
static bool editor =;
static bool project_manager =;
static bool cmdline_tool =;
static String locale;
static String log_file;
static bool show_help =;
static uint64_t quit_after =;
static OS::ProcessID editor_pid =;
#ifdef TOOLS_ENABLED
static bool found_project =;
static bool auto_build_solutions =;
static String debug_server_uri;
static bool wait_for_import =;
static bool restore_editor_window_layout =;
#ifndef DISABLE_DEPRECATED
static int converter_max_kb_file =; // 4MB
static int converter_max_line_length =;
#endif // DISABLE_DEPRECATED

HashMap<Main::CLIScope, Vector<String>> forwardable_cli_arguments;
#endif
static bool single_threaded_scene =;

// Display

static DisplayServer::WindowMode window_mode =;
static DisplayServer::ScreenOrientation window_orientation =;
static DisplayServer::VSyncMode window_vsync_mode =;
static uint32_t window_flags =;
static Size2i window_size =;

static int init_screen =;
static bool init_fullscreen =;
static bool init_maximized =;
static bool init_windowed =;
static bool init_always_on_top =;
static bool init_use_custom_pos =;
static bool init_use_custom_screen =;
static Vector2 init_custom_pos;

// Debug

static bool use_debug_profiler =;
#ifdef DEBUG_ENABLED
static bool debug_collisions =;
static bool debug_paths =;
static bool debug_navigation =;
static bool debug_avoidance =;
static bool debug_canvas_item_redraw =;
#endif
static int max_fps =;
static int frame_delay =;
static int audio_output_latency =;
static bool disable_render_loop =;
static int fixed_fps =;
static MovieWriter *movie_writer =;
static bool disable_vsync =;
static bool print_fps =;
#ifdef TOOLS_ENABLED
static bool editor_pseudolocalization =;
static bool dump_gdextension_interface =;
static bool dump_extension_api =;
static bool include_docs_in_extension_api_dump =;
static bool validate_extension_api =;
static String validate_extension_api_file;
#endif
bool profile_gpu =;

// Constants.

static const String NULL_DISPLAY_DRIVER("headless");
static const String NULL_AUDIO_DRIVER("Dummy");

// The length of the longest column in the command-line help we should align to
// (excluding the 2-space left and right margins).
// Currently, this is `--export-release <preset> <path>`.
static const int OPTION_COLUMN_LENGTH =;

/* Helper methods */

bool Main::is_cmdline_tool() {}

#ifdef TOOLS_ENABLED
const Vector<String> &Main::get_forwardable_cli_arguments(Main::CLIScope p_scope) {}
#endif

static String unescape_cmdline(const String &p_str) {}

static String get_full_version_string() {}

#if defined(TOOLS_ENABLED) && defined(MODULE_GDSCRIPT_ENABLED)
static Vector<String> get_files_with_extension(const String &p_root, const String &p_extension) {}
#endif

// FIXME: Could maybe be moved to have less code in main.cpp.
void initialize_physics() {}

void finalize_physics() {}

void finalize_display() {}

void initialize_navigation_server() {}

void finalize_navigation_server() {}

void initialize_theme_db() {}

void finalize_theme_db() {}

//#define DEBUG_INIT
#ifdef DEBUG_INIT
#define MAIN_PRINT
#else
#define MAIN_PRINT(m_txt)
#endif

void Main::print_header(bool p_rich) {}

/**
 * Prints a copyright notice in the command-line help with colored text. A newline is
 * automatically added at the end.
 */
void Main::print_help_copyright(const char *p_notice) {}

/**
 * Prints a title in the command-line help with colored text. A newline is
 * automatically added at beginning and at the end.
 */
void Main::print_help_title(const char *p_title) {}

/**
 * Returns the option string with required and optional arguments colored separately from the rest of the option.
 * This color replacement must be done *after* calling `rpad()` for the length padding to be done correctly.
 */
String Main::format_help_option(const char *p_option) {}

/**
 * Prints an option in the command-line help with colored text. No newline is
 * added at the end. `p_availability` denotes which build types the argument is
 * available in. Support in release export templates implies support in debug
 * export templates and editor. Support in debug export templates implies
 * support in editor.
 */
void Main::print_help_option(const char *p_option, const char *p_description, CLIOptionAvailability p_availability) {}

void Main::print_help(const char *p_binary) {}

#ifdef TESTS_ENABLED
// The order is the same as in `Main::setup()`, only core and some editor types
// are initialized here. This also combines `Main::setup2()` initialization.
Error Main::test_setup() {
	Thread::make_main_thread();
	set_current_thread_safe_for_nodes(true);

	OS::get_singleton()->initialize();

	engine = memnew(Engine);

	register_core_types();
	register_core_driver_types();

	packed_data = memnew(PackedData);

	globals = memnew(ProjectSettings);

	register_core_settings(); // Here globals are present.

	translation_server = memnew(TranslationServer);
	tsman = memnew(TextServerManager);

	if (tsman) {
		Ref<TextServerDummy> ts;
		ts.instantiate();
		tsman->add_interface(ts);
	}

#ifndef _3D_DISABLED
	physics_server_3d_manager = memnew(PhysicsServer3DManager);
#endif // _3D_DISABLED
	physics_server_2d_manager = memnew(PhysicsServer2DManager);

	// From `Main::setup2()`.
	register_early_core_singletons();
	initialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);
	register_core_extensions();

	register_core_singletons();

	/** INITIALIZE SERVERS **/
	register_server_types();
#ifndef _3D_DISABLED
	XRServer::set_xr_mode(XRServer::XRMODE_OFF); // Skip in tests.
#endif // _3D_DISABLED
	initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
	GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);

	translation_server->setup(); //register translations, load them, etc.
	if (!locale.is_empty()) {
		translation_server->set_locale(locale);
	}
	translation_server->load_translations();
	ResourceLoader::load_translation_remaps(); //load remaps for resources

	ResourceLoader::load_path_remaps();

	// Initialize ThemeDB early so that scene types can register their theme items.
	// Default theme will be initialized later, after modules and ScriptServer are ready.
	initialize_theme_db();

	register_scene_types();
	register_driver_types();

	register_scene_singletons();

	initialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE);
	GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_SCENE);

#ifdef TOOLS_ENABLED
	ClassDB::set_current_api(ClassDB::API_EDITOR);
	register_editor_types();

	initialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR);
	GDExtensionManager::get_singleton()->initialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR);

	ClassDB::set_current_api(ClassDB::API_CORE);
#endif
	register_platform_apis();

	// Theme needs modules to be initialized so that sub-resources can be loaded.
	theme_db->initialize_theme_noproject();

	initialize_navigation_server();

	ERR_FAIL_COND_V(TextServerManager::get_singleton()->get_interface_count() == 0, ERR_CANT_CREATE);

	/* Use one with the most features available. */
	int max_features = 0;
	for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
		uint32_t features = TextServerManager::get_singleton()->get_interface(i)->get_features();
		int feature_number = 0;
		while (features) {
			feature_number += features & 1;
			features >>= 1;
		}
		if (feature_number >= max_features) {
			max_features = feature_number;
			text_driver_idx = i;
		}
	}
	if (text_driver_idx >= 0) {
		Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(text_driver_idx);
		TextServerManager::get_singleton()->set_primary_interface(ts);
		if (ts->has_feature(TextServer::FEATURE_USE_SUPPORT_DATA)) {
			ts->load_support_data("res://" + ts->get_support_data_filename());
		}
	} else {
		ERR_FAIL_V_MSG(ERR_CANT_CREATE, "TextServer: Unable to create TextServer interface.");
	}

	ClassDB::set_current_api(ClassDB::API_NONE);

	_start_success = true;

	return OK;
}

// The order is the same as in `Main::cleanup()`.
void Main::test_cleanup() {
	ERR_FAIL_COND(!_start_success);

	for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
		TextServerManager::get_singleton()->get_interface(i)->cleanup();
	}

	ResourceLoader::remove_custom_loaders();
	ResourceSaver::remove_custom_savers();
	PropertyListHelper::clear_base_helpers();

#ifdef TOOLS_ENABLED
	GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_EDITOR);
	uninitialize_modules(MODULE_INITIALIZATION_LEVEL_EDITOR);
	unregister_editor_types();
#endif

	GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SCENE);
	uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SCENE);

	unregister_platform_apis();
	unregister_driver_types();
	unregister_scene_types();

	finalize_theme_db();

	finalize_navigation_server();

	GDExtensionManager::get_singleton()->deinitialize_extensions(GDExtension::INITIALIZATION_LEVEL_SERVERS);
	uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
	unregister_server_types();

	EngineDebugger::deinitialize();
	OS::get_singleton()->finalize();

	if (packed_data) {
		memdelete(packed_data);
	}
	if (translation_server) {
		memdelete(translation_server);
	}
	if (tsman) {
		memdelete(tsman);
	}
#ifndef _3D_DISABLED
	if (physics_server_3d_manager) {
		memdelete(physics_server_3d_manager);
	}
#endif // _3D_DISABLED
	if (physics_server_2d_manager) {
		memdelete(physics_server_2d_manager);
	}
	if (globals) {
		memdelete(globals);
	}

	unregister_core_driver_types();
	unregister_core_extensions();
	uninitialize_modules(MODULE_INITIALIZATION_LEVEL_CORE);

	if (engine) {
		memdelete(engine);
	}

	unregister_core_types();

	OS::get_singleton()->finalize_core();
}
#endif

int Main::test_entrypoint(int argc, char *argv[], bool &tests_need_run) {}

/* Engine initialization
 *
 * Consists of several methods that are called by each platform's specific main(argc, argv).
 * To fully understand engine init, one should therefore start from the platform's main and
 * see how it calls into the Main class' methods.
 *
 * The initialization is typically done in 3 steps (with the setup2 step triggered either
 * automatically by setup, or manually in the platform's main).
 *
 * - setup(execpath, argc, argv, p_second_phase) is the main entry point for all platforms,
 *   responsible for the initialization of all low level singletons and core types, and parsing
 *   command line arguments to configure things accordingly.
 *   If p_second_phase is true, it will chain into setup2() (default behavior). This is
 *   disabled on some platforms (Android, iOS) which trigger the second step in their own time.
 *
 * - setup2(p_main_tid_override) registers high level servers and singletons, displays the
 *   boot splash, then registers higher level types (scene, editor, etc.).
 *
 * - start() is the last step and that's where command line tools can run, or the main loop
 *   can be created eventually and the project settings put into action. That's also where
 *   the editor node is created, if relevant.
 *   start() does it own argument parsing for a subset of the command line arguments described
 *   in help, it's a bit messy and should be globalized with the setup() parsing somehow.
 */

Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_phase) {}

Error _parse_resource_dummy(void *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {}

Error Main::setup2(bool p_show_boot_logo) {}

void Main::setup_boot_logo() {}

String Main::get_rendering_driver_name() {}

// everything the main loop needs to know about frame timings
static MainTimerSync main_timer_sync;

// Return value should be EXIT_SUCCESS if we start successfully
// and should move on to `OS::run`, and EXIT_FAILURE otherwise for
// an early exit with that error code.
int Main::start() {}

/* Main iteration
 *
 * This is the iteration of the engine's game loop, advancing the state of physics,
 * rendering and audio.
 * It's called directly by the platform's OS::run method, where the loop is created
 * and monitored.
 *
 * The OS implementation can impact its draw step with the Main::force_redraw() method.
 */

uint64_t Main::last_ticks =;
uint32_t Main::frames =;
uint32_t Main::hide_print_fps_attempts =;
uint32_t Main::frame =;
bool Main::force_redraw_requested =;
int Main::iterating =;

bool Main::is_iterating() {}

// For performance metrics.
static uint64_t physics_process_max =;
static uint64_t process_max =;
static uint64_t navigation_process_max =;

// Return false means iterating further, returning true means `OS::run`
// will terminate the program. In case of failure, the OS exit code needs
// to be set explicitly here (defaults to EXIT_SUCCESS).
bool Main::iteration() {}

void Main::force_redraw() {}

/* Engine deinitialization
 *
 * Responsible for freeing all the memory allocated by previous setup steps,
 * so that the engine closes cleanly without leaking memory or crashing.
 * The order matters as some of those steps are linked with each other.
 */
void Main::cleanup(bool p_force) {}