/*************************************************************************/ /* main.cpp */ /*************************************************************************/ /* This file is part of: */ /* PANDEMONIUM ENGINE */ /* https://github.com/Relintai/pandemonium_engine */ /*************************************************************************/ /* Copyright (c) 2022-present Péter Magyar. */ /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ /* Copyright (c) 2007-2022 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/crypto/crypto.h" #include "core/input/input_map.h" #include "core/io/file_access_network.h" #include "core/io/file_access_pack.h" #include "core/io/file_access_zip.h" #include "core/io/image_loader.h" #include "core/io/ip.h" #include "core/io/resource_loader.h" #include "core/object/message_queue.h" #include "core/object/script_debugger_local.h" #include "core/object/script_language.h" #include "core/os/dir_access.h" #include "core/os/os.h" #include "core/os/time.h" #include "core/register_core_types.h" #include "core/string/translation.h" #include "core/version.h" #include "drivers/register_driver_types.h" #include "main/app_icon.gen.h" #include "main/input_default.h" #include "main/main_timer_sync.h" #include "main/performance.h" #include "main/splash.gen.h" #include "main/tests/test_main.h" #include "modules/register_module_types.h" #include "platform/register_platform_apis.h" #include "scene/debugger/script_debugger_remote.h" #include "scene/main/scene_tree.h" #include "scene/main/viewport.h" #include "scene/register_scene_types.h" #include "scene/resources/packed_scene.h" #include "servers/audio_server.h" #include "servers/navigation/navigation_mesh_generator.h" #include "servers/navigation/navigation_mesh_generator_dummy.h" #include "servers/navigation_2d_server.h" #include "servers/navigation_server.h" #include "servers/physics_2d_server.h" #include "servers/physics_server.h" #include "servers/register_server_types.h" #include "servers/rendering_server_callbacks.h" #ifdef TOOLS_ENABLED #include "editor/doc/doc_data.h" #include "editor/doc/doc_data_class_path.gen.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/editor_translation.h" #include "editor/progress_dialog.h" #include "editor/project_manager.h" #include "editor/script_editor_debugger.h" #if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH) #include "main/splash_editor.gen.h" #endif #endif #include "modules/modules_enabled.gen.h" #ifdef MODULE_EDITOR_CODE_EDITOR_ENABLED #include "editor_code_editor/editor_script_editor.h" #endif #ifdef MODULE_GDSCRIPT_ENABLED #if defined(TOOLS_ENABLED) && !defined(GDSCRIPT_NO_LSP) #include "modules/gdscript/language_server/gdscript_language_server.h" #endif // TOOLS_ENABLED && !GDSCRIPT_NO_LSP #endif // MODULE_GDSCRIPT_ENABLED /* Static members */ // Singletons // Initialized in setup() static Engine *engine = nullptr; static ProjectSettings *globals = nullptr; static InputMap *input_map = nullptr; static TranslationServer *translation_server = nullptr; static Performance *performance = nullptr; static PackedData *packed_data = nullptr; static Time *time_singleton = nullptr; #ifdef MINIZIP_ENABLED static ZipArchive *zip_packed_data = nullptr; #endif static FileAccessNetworkClient *file_access_network_client = nullptr; static ScriptDebugger *script_debugger = nullptr; static MessageQueue *message_queue = nullptr; // Initialized in setup2() static AudioServer *audio_server = nullptr; static PhysicsServer *physics_server = nullptr; static Physics2DServer *physics_2d_server = nullptr; static RenderingServerCallbacks *rendering_server_callbacks = nullptr; static NavigationMeshGeneratorManager *navigation_mesh_generator_manager = nullptr; static NavigationMeshGenerator *navigation_mesh_generator = nullptr; static NavigationServer *navigation_server = nullptr; static Navigation2DServer *navigation_2d_server = nullptr; // We error out if setup2() doesn't turn this true static bool _start_success = false; // Drivers static int video_driver_idx = -1; static int audio_driver_idx = -1; // Engine config/tools static bool editor = false; static bool project_manager = false; static String locale; static bool show_help = false; static bool auto_quit = false; static OS::ProcessID allow_focus_steal_pid = 0; static bool delta_sync_after_draw = false; #ifdef TOOLS_ENABLED static String debug_server_uri; #endif // Display static OS::VideoMode video_mode; static int init_screen = -1; static bool init_fullscreen = false; static bool init_maximized = false; static bool init_windowed = false; static bool init_always_on_top = false; static bool init_use_custom_pos = false; static Vector2 init_custom_pos; static bool force_lowdpi = false; // Debug static bool use_debug_profiler = false; #ifdef DEBUG_ENABLED static bool debug_collisions = false; static bool debug_navigation = false; static bool debug_avoidance = false; static bool debug_paths = false; static bool debug_shader_fallbacks = false; #endif static int frame_delay = 0; static bool disable_render_loop = false; static int fixed_fps = -1; static bool print_fps = false; /* Helper methods */ // Used by Mono module, should likely be registered in Engine singleton instead // FIXME: This is also not 100% accurate, `project_manager` is only true when it was requested, // but not if e.g. we fail to load and project and fallback to the manager. bool Main::is_project_manager() { return project_manager; } static String unescape_cmdline(const String &p_str) { return p_str.replace("%20", " "); } static String get_full_version_string() { String hash = String(VERSION_HASH); if (!hash.empty()) { hash = "." + hash.left(9); } return String(VERSION_FULL_BUILD) + hash; } // FIXME: Could maybe be moved to PhysicsServerManager and Physics2DServerManager directly // to have less code in main.cpp. void initialize_physics() { // This must be defined BEFORE the 3d physics server is created, // otherwise it won't always show up in the project settings page. GLOBAL_DEF("physics/3d/pandemonium_physics/use_bvh", true); GLOBAL_DEF("physics/3d/pandemonium_physics/bvh_collision_margin", 0.1); ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/pandemonium_physics/bvh_collision_margin", PropertyInfo(Variant::REAL, "physics/3d/pandemonium_physics/bvh_collision_margin", PROPERTY_HINT_RANGE, "0.0,2.0,0.01")); /// 3D Physics Server physics_server = PhysicsServerManager::new_server(ProjectSettings::get_singleton()->get(PhysicsServerManager::setting_property_name)); if (!physics_server) { // Physics server not found, Use the default physics physics_server = PhysicsServerManager::new_default_server(); } ERR_FAIL_COND(!physics_server); physics_server->init(); /// 2D Physics server physics_2d_server = Physics2DServerManager::new_server(ProjectSettings::get_singleton()->get(Physics2DServerManager::setting_property_name)); if (!physics_2d_server) { // Physics server not found, Use the default physics physics_2d_server = Physics2DServerManager::new_default_server(); } ERR_FAIL_COND(!physics_2d_server); physics_2d_server->init(); } void finalize_physics() { physics_server->finish(); memdelete(physics_server); physics_2d_server->finish(); memdelete(physics_2d_server); } void initialize_navigation_mesh_generator() { ERR_FAIL_COND(navigation_mesh_generator != NULL); // Init chosen NavigationMeshGenerator const String &server_name = GLOBAL_GET(NavigationMeshGeneratorManager::setting_property_name); navigation_mesh_generator = NavigationMeshGeneratorManager::get_singleton()->new_server(server_name); // Fall back to default if not found if (!navigation_mesh_generator) { // Navigation server not found, so use the default. navigation_mesh_generator = NavigationMeshGeneratorManager::get_singleton()->new_default_server(); } // Fall back to dummy if no default server has been registered. if (!navigation_mesh_generator) { //ERR_PRINT("No NavigationMeshGenerator implementation has been registered! Falling back to a dummy implementation: navigation mesh baking features will be unavailable."); navigation_mesh_generator = memnew(NavigationMeshGeneratorDummy); } if (navigation_mesh_generator) { navigation_mesh_generator->init(); // need to register singleton earlier so modules / extensions / addons can use it on SCENE / SERVER init level Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", NavigationMeshGenerator::get_singleton())); } ERR_FAIL_NULL_MSG(navigation_mesh_generator, "Failed to initialize NavigationMeshGenerator."); } void finalize_navigation_mesh_generator() { ERR_FAIL_COND(!navigation_mesh_generator); navigation_mesh_generator->finish(); memdelete(navigation_mesh_generator); navigation_mesh_generator = nullptr; } void initialize_navigation_server() { ERR_FAIL_COND(navigation_server != nullptr); ERR_FAIL_COND(navigation_2d_server != nullptr); /// 3D Navigation Server navigation_server = NavigationServerManager::new_server(ProjectSettings::get_singleton()->get(NavigationServerManager::setting_property_name)); if (!navigation_server) { // Navigation server not found, Use the default physics navigation_server = NavigationServerManager::new_default_server(); } ERR_FAIL_COND(!navigation_server); navigation_server->init(); /// 2D Navigation server navigation_2d_server = Navigation2DServerManager::new_server(ProjectSettings::get_singleton()->get(Navigation2DServerManager::setting_property_name)); if (!navigation_2d_server) { // Navigation server not found, Use the default physics navigation_2d_server = Navigation2DServerManager::new_default_server(); } ERR_FAIL_COND(!navigation_2d_server); navigation_2d_server->init(); } void finalize_navigation_server() { navigation_2d_server->finish(); navigation_server->finish(); memdelete(navigation_2d_server); navigation_2d_server = nullptr; memdelete(navigation_server); navigation_server = nullptr; } //#define DEBUG_INIT #ifdef DEBUG_INIT #define MAIN_PRINT(m_txt) print_line(m_txt) #else #define MAIN_PRINT(m_txt) #endif void Main::print_help(const char *p_binary) { print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); OS::get_singleton()->print("Free and open source software under the terms of the MIT license.\n"); OS::get_singleton()->print("(c) 2007-2022 Juan Linietsky, Ariel Manzur.\n"); OS::get_singleton()->print("(c) 2014-2022 Pandemonium Engine contributors.\n"); OS::get_singleton()->print("\n"); OS::get_singleton()->print("Usage: %s [options] [path to scene or 'project.pandemonium' file]\n", p_binary); OS::get_singleton()->print("\n"); OS::get_singleton()->print("General options:\n"); OS::get_singleton()->print(" -h, --help Display this help message.\n"); OS::get_singleton()->print(" --version Display the version string.\n"); #ifdef TOOLS_ENABLED OS::get_singleton()->print(" --version-full-config Display the full config version string (used by the export templates manager).\n"); #endif OS::get_singleton()->print(" -v, --verbose Use verbose stdout mode.\n"); OS::get_singleton()->print(" --quiet Quiet mode, silences stdout messages. Errors are still displayed.\n"); OS::get_singleton()->print("\n"); OS::get_singleton()->print("Run options:\n"); #ifdef TOOLS_ENABLED OS::get_singleton()->print(" -e, --editor Start the editor instead of running the scene.\n"); OS::get_singleton()->print(" -p, --project-manager Start the project manager, even if a project is auto-detected.\n"); OS::get_singleton()->print(" --debug-server
Start the editor debug server (:, e.g. 127.0.0.1:6007)\n"); #if defined(MODULE_GDSCRIPT_ENABLED) && !defined(GDSCRIPT_NO_LSP) OS::get_singleton()->print(" --lsp-port Use the specified port for the language server protocol. The port must be between 0 to 65535.\n"); #endif // MODULE_GDSCRIPT_ENABLED && !GDSCRIPT_NO_LSP #endif OS::get_singleton()->print(" -q, --quit Quit after the first iteration.\n"); OS::get_singleton()->print(" -l, --language Use a specific locale ( being a two-letter code).\n"); OS::get_singleton()->print(" --path Path to a project ( must contain a 'project.pandemonium' file).\n"); OS::get_singleton()->print(" -u, --upwards Scan folders upwards for project.pandemonium file.\n"); OS::get_singleton()->print(" --main-pack Path to a pack (.pck) file to load.\n"); OS::get_singleton()->print(" --render-thread Render thread mode ('unsafe', 'safe', 'separate').\n"); OS::get_singleton()->print(" --remote-fs
Remote filesystem ([:] address).\n"); OS::get_singleton()->print(" --remote-fs-password Password for remote filesystem.\n"); OS::get_singleton()->print(" --audio-driver Audio driver ("); for (int i = 0; i < OS::get_singleton()->get_audio_driver_count(); i++) { if (i != 0) { OS::get_singleton()->print(", "); } OS::get_singleton()->print("'%s'", OS::get_singleton()->get_audio_driver_name(i)); } OS::get_singleton()->print(").\n"); OS::get_singleton()->print(" --video-driver Video driver ("); for (int i = 0; i < OS::get_singleton()->get_video_driver_count(); i++) { if (i != 0) { OS::get_singleton()->print(", "); } OS::get_singleton()->print("'%s'", OS::get_singleton()->get_video_driver_name(i)); } OS::get_singleton()->print(").\n"); OS::get_singleton()->print("\n"); #ifndef SERVER_ENABLED OS::get_singleton()->print("Display options:\n"); OS::get_singleton()->print(" -f, --fullscreen Request fullscreen mode.\n"); OS::get_singleton()->print(" -m, --maximized Request a maximized window.\n"); OS::get_singleton()->print(" -w, --windowed Request windowed mode.\n"); OS::get_singleton()->print(" -t, --always-on-top Request an always-on-top window.\n"); OS::get_singleton()->print(" --resolution x Request window resolution.\n"); OS::get_singleton()->print(" --position , Request window position.\n"); OS::get_singleton()->print(" --low-dpi Force low-DPI mode (macOS and Windows only).\n"); OS::get_singleton()->print(" --no-window Run with invisible window. Useful together with --script.\n"); OS::get_singleton()->print(" --enable-vsync-via-compositor When vsync is enabled, vsync via the OS' window compositor (Windows only).\n"); OS::get_singleton()->print(" --disable-vsync-via-compositor Disable vsync via the OS' window compositor (Windows only).\n"); OS::get_singleton()->print(" --enable-delta-smoothing When vsync is enabled, enabled frame delta smoothing.\n"); OS::get_singleton()->print(" --disable-delta-smoothing Disable frame delta smoothing.\n"); OS::get_singleton()->print(" --tablet-driver Tablet input driver ("); for (int i = 0; i < OS::get_singleton()->get_tablet_driver_count(); i++) { if (i != 0) { OS::get_singleton()->print(", "); } OS::get_singleton()->print("'%s'", OS::get_singleton()->get_tablet_driver_name(i).utf8().get_data()); } OS::get_singleton()->print(") (Windows only).\n"); OS::get_singleton()->print("\n"); #endif OS::get_singleton()->print("Debug options:\n"); OS::get_singleton()->print(" -d, --debug Debug (local stdout debugger).\n"); OS::get_singleton()->print(" -b, --breakpoints Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n"); OS::get_singleton()->print(" --profiling Enable profiling in the script debugger.\n"); OS::get_singleton()->print(" --remote-debug
Remote debug (: address).\n"); #if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED) OS::get_singleton()->print(" --debug-collisions Show collision shapes when running the scene.\n"); OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n"); OS::get_singleton()->print(" --debug-avoidance Show navigation avoidance debug visuals when running the scene.\n"); OS::get_singleton()->print(" --debug-paths Show path lines when running the scene.\n"); OS::get_singleton()->print(" --debug-shader-fallbacks Use the fallbacks of the shaders which have one when running the scene (GL ES 3 only).\n"); #endif OS::get_singleton()->print(" --frame-delay Simulate high CPU load (delay each frame by milliseconds).\n"); OS::get_singleton()->print(" --time-scale Force time scale (higher values are faster, 1.0 is normal speed).\n"); OS::get_singleton()->print(" --disable-render-loop Disable render loop so rendering only occurs when called explicitly from script.\n"); OS::get_singleton()->print(" --disable-crash-handler Disable crash handler when supported by the platform code.\n"); OS::get_singleton()->print(" --fixed-fps Force a fixed number of frames per second. This setting disables real-time synchronization.\n"); OS::get_singleton()->print(" --print-fps Print the frames per second to the stdout.\n"); OS::get_singleton()->print("\n"); OS::get_singleton()->print("Standalone tools:\n"); OS::get_singleton()->print(" -s, --script