2014-02-10 02:10:30 +01:00
/*************************************************************************/
2017-12-20 01:04:30 +01:00
/* main.cpp */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2021-01-01 20:13:46 +01:00
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
2014-02-10 02:10:30 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "main.h"
2017-08-19 16:45:03 +02:00
2019-07-19 15:29:57 +02:00
# include "core/crypto/crypto.h"
2018-09-11 18:13:45 +02:00
# include "core/input_map.h"
# include "core/io/file_access_network.h"
# include "core/io/file_access_pack.h"
# include "core/io/file_access_zip.h"
2018-09-30 17:21:07 +02:00
# include "core/io/image_loader.h"
2018-09-11 18:13:45 +02:00
# include "core/io/ip.h"
# include "core/io/resource_loader.h"
# include "core/message_queue.h"
# include "core/os/dir_access.h"
# include "core/os/os.h"
# include "core/project_settings.h"
2014-02-10 02:10:30 +01:00
# include "core/register_core_types.h"
2018-09-11 18:13:45 +02:00
# include "core/script_debugger_local.h"
# include "core/script_language.h"
# include "core/translation.h"
# include "core/version.h"
# include "core/version_hash.gen.h"
2014-02-10 02:10:30 +01:00
# include "drivers/register_driver_types.h"
2018-09-11 18:13:45 +02:00
# include "main/app_icon.gen.h"
# include "main/input_default.h"
2019-02-12 14:23:35 +01:00
# include "main/main_timer_sync.h"
2018-09-11 18:13:45 +02:00
# include "main/performance.h"
# include "main/splash.gen.h"
# include "main/splash_editor.gen.h"
# include "main/tests/test_main.h"
2014-02-10 02:10:30 +01:00
# include "modules/register_module_types.h"
2017-11-16 01:33:48 +01:00
# include "platform/register_platform_apis.h"
2019-04-06 22:55:01 +02:00
# include "scene/debugger/script_debugger_remote.h"
2017-06-27 03:58:03 +02:00
# include "scene/main/scene_tree.h"
2018-09-11 18:13:45 +02:00
# include "scene/main/viewport.h"
# include "scene/register_scene_types.h"
# include "scene/resources/packed_scene.h"
2017-10-07 15:51:17 +02:00
# include "servers/arvr_server.h"
2017-01-15 20:06:14 +01:00
# include "servers/audio_server.h"
2019-11-29 07:54:39 +01:00
# include "servers/camera_server.h"
2017-10-21 13:02:06 +02:00
# include "servers/physics_2d_server.h"
# include "servers/physics_server.h"
2018-09-11 18:13:45 +02:00
# include "servers/register_server_types.h"
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
2017-03-05 14:21:25 +01:00
# include "editor/doc/doc_data.h"
2017-09-13 09:13:23 +02:00
# include "editor/doc/doc_data_class_path.gen.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_node.h"
2018-09-15 14:45:54 +02:00
# include "editor/editor_settings.h"
2019-12-24 08:17:23 +01:00
# include "editor/progress_dialog.h"
2017-03-05 14:21:25 +01:00
# include "editor/project_manager.h"
2014-02-10 02:10:30 +01:00
# endif
2018-09-20 11:45:05 +02:00
/* Static members */
// Singletons
// Initialized in setup()
2017-03-05 16:44:50 +01:00
static Engine * engine = NULL ;
2018-09-20 11:45:05 +02:00
static ProjectSettings * globals = NULL ;
2017-03-05 16:44:50 +01:00
static InputMap * input_map = NULL ;
2018-09-20 11:45:05 +02:00
static TranslationServer * translation_server = NULL ;
2014-02-10 02:10:30 +01:00
static Performance * performance = NULL ;
2017-03-05 16:44:50 +01:00
static PackedData * packed_data = NULL ;
2015-04-21 00:38:02 +02:00
# ifdef MINIZIP_ENABLED
2017-03-05 16:44:50 +01:00
static ZipArchive * zip_packed_data = NULL ;
2015-04-21 00:38:02 +02:00
# endif
2017-03-05 16:44:50 +01:00
static FileAccessNetworkClient * file_access_network_client = NULL ;
2018-09-20 11:45:05 +02:00
static ScriptDebugger * script_debugger = NULL ;
static MessageQueue * message_queue = NULL ;
// Initialized in setup2()
static AudioServer * audio_server = NULL ;
2019-11-29 07:54:39 +01:00
static CameraServer * camera_server = NULL ;
2018-09-20 11:45:05 +02:00
static ARVRServer * arvr_server = NULL ;
static PhysicsServer * physics_server = NULL ;
static Physics2DServer * physics_2d_server = NULL ;
// 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 ;
2018-10-03 14:05:17 +02:00
# ifdef TOOLS_ENABLED
static bool auto_build_solutions = false ;
# endif
2018-09-20 11:45:05 +02:00
// Display
2014-02-10 02:10:30 +01:00
static OS : : VideoMode video_mode ;
2018-09-20 11:45:05 +02:00
static int init_screen = - 1 ;
static bool init_fullscreen = false ;
2017-03-05 16:44:50 +01:00
static bool init_maximized = false ;
static bool init_windowed = false ;
2017-12-27 20:51:19 +01:00
static bool init_always_on_top = false ;
2017-03-05 16:44:50 +01:00
static bool init_use_custom_pos = false ;
2018-09-20 11:45:05 +02:00
static Vector2 init_custom_pos ;
static bool force_lowdpi = false ;
// Debug
static bool use_debug_profiler = false ;
2017-04-07 16:17:16 +02:00
# ifdef DEBUG_ENABLED
2017-03-05 16:44:50 +01:00
static bool debug_collisions = false ;
static bool debug_navigation = false ;
2017-04-07 16:17:16 +02:00
# endif
2017-03-05 16:44:50 +01:00
static int frame_delay = 0 ;
2017-08-30 12:40:35 +02:00
static bool disable_render_loop = false ;
static int fixed_fps = - 1 ;
2018-03-21 08:46:05 +01:00
static bool print_fps = false ;
2015-06-14 03:12:53 +02:00
2018-09-20 11:45:05 +02:00
/* Helper methods */
2018-02-16 16:00:54 +01:00
2018-09-20 11:45:05 +02:00
// 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.
2018-02-16 16:00:54 +01:00
bool Main : : is_project_manager ( ) {
return project_manager ;
}
2018-09-20 11:45:05 +02:00
static String unescape_cmdline ( const String & p_str ) {
return p_str . replace ( " %20 " , " " ) ;
}
2017-10-21 13:02:06 +02:00
2018-09-20 11:45:05 +02:00
static String get_full_version_string ( ) {
String hash = String ( VERSION_HASH ) ;
if ( hash . length ( ) ! = 0 )
2019-06-01 13:51:10 +02:00
hash = " . " + hash . left ( 9 ) ;
2018-09-20 11:45:05 +02:00
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 ( ) {
2021-01-13 10:22:17 +01:00
// This must be defined BEFORE the 3d physics server is created
GLOBAL_DEF ( " physics/3d/godot_physics/use_bvh " , true ) ;
2017-10-21 13:02:06 +02:00
/// 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 ) ;
}
2014-02-10 02:10:30 +01:00
//#define DEBUG_INIT
# ifdef DEBUG_INIT
# define MAIN_PRINT(m_txt) print_line(m_txt)
# else
# define MAIN_PRINT(m_txt)
# endif
2017-03-05 16:44:50 +01:00
void Main : : print_help ( const char * p_binary ) {
2014-02-10 02:10:30 +01:00
2019-05-28 11:19:21 +02:00
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 " ) ;
2021-01-01 20:13:46 +01:00
OS : : get_singleton ( ) - > print ( " (c) 2007-2021 Juan Linietsky, Ariel Manzur. \n " ) ;
OS : : get_singleton ( ) - > print ( " (c) 2014-2021 Godot Engine contributors. \n " ) ;
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " \n " ) ;
2017-06-21 11:09:30 +02:00
OS : : get_singleton ( ) - > print ( " Usage: %s [options] [path to scene or 'project.godot' file] \n " , p_binary ) ;
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " \n " ) ;
OS : : get_singleton ( ) - > print ( " General options: \n " ) ;
2017-06-21 11:09:30 +02:00
OS : : get_singleton ( ) - > print ( " -h, --help Display this help message. \n " ) ;
2017-09-24 11:32:05 +02:00
OS : : get_singleton ( ) - > print ( " --version Display the version string. \n " ) ;
2017-08-19 16:45:03 +02:00
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 " ) ;
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
2017-08-19 16:45:03 +02:00
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 " ) ;
2014-02-10 02:10:30 +01:00
# endif
2018-02-24 18:22:29 +01:00
OS : : get_singleton ( ) - > print ( " -q, --quit Quit after the first iteration. \n " ) ;
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " -l, --language <locale> Use a specific locale (<locale> being a two-letter code). \n " ) ;
OS : : get_singleton ( ) - > print ( " --path <directory> Path to a project (<directory> must contain a 'project.godot' file). \n " ) ;
2017-10-10 14:45:54 +02:00
OS : : get_singleton ( ) - > print ( " -u, --upwards Scan folders upwards for project.godot file. \n " ) ;
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " --main-pack <file> Path to a pack (.pck) file to load. \n " ) ;
OS : : get_singleton ( ) - > print ( " --render-thread <mode> Render thread mode ('unsafe', 'safe', 'separate'). \n " ) ;
OS : : get_singleton ( ) - > print ( " --remote-fs <address> Remote filesystem (<host/IP>[:<port>] address). \n " ) ;
OS : : get_singleton ( ) - > print ( " --remote-fs-password <password> Password for remote filesystem. \n " ) ;
OS : : get_singleton ( ) - > print ( " --audio-driver <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 ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-06-21 11:09:30 +02:00
OS : : get_singleton ( ) - > print ( " ). \n " ) ;
OS : : get_singleton ( ) - > print ( " --video-driver <driver> Video driver ( " ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < OS : : get_singleton ( ) - > get_video_driver_count ( ) ; i + + ) {
if ( i ! = 0 )
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > print ( " , " ) ;
2017-06-21 11:09:30 +02:00
OS : : get_singleton ( ) - > print ( " '%s' " , OS : : get_singleton ( ) - > get_video_driver_name ( i ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-06-21 11:09:30 +02:00
OS : : get_singleton ( ) - > print ( " ). \n " ) ;
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " \n " ) ;
2017-08-19 16:45:03 +02:00
2019-05-19 01:33:13 +02:00
# ifndef SERVER_ENABLED
2017-08-19 16:45:03 +02:00
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 " ) ;
2017-12-27 20:51:19 +01:00
OS : : get_singleton ( ) - > print ( " -t, --always-on-top Request an always-on-top window. \n " ) ;
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " --resolution <W>x<H> Request window resolution. \n " ) ;
OS : : get_singleton ( ) - > print ( " --position <X>,<Y> Request window position. \n " ) ;
2017-09-12 16:40:18 +02:00
OS : : get_singleton ( ) - > print ( " --low-dpi Force low-DPI mode (macOS and Windows only). \n " ) ;
2020-09-23 13:43:51 +02:00
OS : : get_singleton ( ) - > print ( " --no-window Run with invisible window. Useful together with --script. \n " ) ;
2019-11-07 03:18:55 +01:00
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 " ) ;
2020-05-19 22:28:57 +02:00
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 ( " , " ) ;
2020-05-22 09:44:23 +02:00
OS : : get_singleton ( ) - > print ( " '%s' " , OS : : get_singleton ( ) - > get_tablet_driver_name ( i ) . utf8 ( ) . get_data ( ) ) ;
2020-05-19 22:28:57 +02:00
}
OS : : get_singleton ( ) - > print ( " ) (Windows only). \n " ) ;
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " \n " ) ;
2019-05-19 01:33:13 +02:00
# endif
2017-08-19 22:47:27 +02:00
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Debug options: \n " ) ;
2017-06-21 11:09:30 +02:00
OS : : get_singleton ( ) - > print ( " -d, --debug Debug (local stdout debugger). \n " ) ;
2017-08-19 16:45:03 +02:00
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 <address> Remote debug (<host/IP>:<port> address). \n " ) ;
2019-05-19 01:33:13 +02:00
# if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED)
OS : : get_singleton ( ) - > print ( " --debug-collisions Show collision shapes when running the scene. \n " ) ;
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " --debug-navigation Show navigation polygons when running the scene. \n " ) ;
# endif
2017-06-21 11:09:30 +02:00
OS : : get_singleton ( ) - > print ( " --frame-delay <ms> Simulate high CPU load (delay each frame by <ms> milliseconds). \n " ) ;
OS : : get_singleton ( ) - > print ( " --time-scale <scale> Force time scale (higher values are faster, 1.0 is normal speed). \n " ) ;
2017-08-30 12:40:35 +02:00
OS : : get_singleton ( ) - > print ( " --disable-render-loop Disable render loop so rendering only occurs when called explicitly from script. \n " ) ;
2017-09-08 03:01:49 +02:00
OS : : get_singleton ( ) - > print ( " --disable-crash-handler Disable crash handler when supported by the platform code. \n " ) ;
2017-09-24 20:24:41 +02:00
OS : : get_singleton ( ) - > print ( " --fixed-fps <fps> Force a fixed number of frames per second. This setting disables real-time synchronization. \n " ) ;
2018-03-21 08:46:05 +01:00
OS : : get_singleton ( ) - > print ( " --print-fps Print the frames per second to the stdout. \n " ) ;
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " \n " ) ;
OS : : get_singleton ( ) - > print ( " Standalone tools: \n " ) ;
OS : : get_singleton ( ) - > print ( " -s, --script <script> Run a script. \n " ) ;
2018-05-31 00:23:23 +02:00
OS : : get_singleton ( ) - > print ( " --check-only Only parse for errors and quit (use with --script). \n " ) ;
2017-08-19 22:47:27 +02:00
# ifdef TOOLS_ENABLED
2020-01-07 13:29:02 +01:00
OS : : get_singleton ( ) - > print ( " --export <preset> <path> Export the project using the given preset and matching release template. The preset name should match one defined in export_presets.cfg. \n " ) ;
2020-01-08 14:22:50 +01:00
OS : : get_singleton ( ) - > print ( " <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe'). The target directory should exist. \n " ) ;
2020-01-07 13:29:02 +01:00
OS : : get_singleton ( ) - > print ( " --export-debug <preset> <path> Same as --export, but using the debug template. \n " ) ;
2020-01-08 14:22:50 +01:00
OS : : get_singleton ( ) - > print ( " --export-pack <preset> <path> Same as --export, but only export the game pack for the given preset. The <path> extension determines whether it will be in PCK or ZIP format. \n " ) ;
2017-09-24 11:32:05 +02:00
OS : : get_singleton ( ) - > print ( " --doctool <path> Dump the engine API reference to the given <path> in XML format, merging if existing files are found. \n " ) ;
2017-06-21 11:09:30 +02:00
OS : : get_singleton ( ) - > print ( " --no-docbase Disallow dumping the base types (used with --doctool). \n " ) ;
2020-01-13 13:55:54 +01:00
OS : : get_singleton ( ) - > print ( " --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit. \n " ) ;
2017-08-19 16:45:03 +02:00
# ifdef DEBUG_METHODS_ENABLED
OS : : get_singleton ( ) - > print ( " --gdnative-generate-json-api Generate JSON dump of the Godot API for GDNative bindings. \n " ) ;
# endif
OS : : get_singleton ( ) - > print ( " --test <test> Run a unit test ( " ) ;
const char * * test_names = tests_get_names ( ) ;
const char * comma = " " ;
while ( * test_names ) {
OS : : get_singleton ( ) - > print ( " %s'%s' " , comma , * test_names ) ;
test_names + + ;
comma = " , " ;
}
OS : : get_singleton ( ) - > print ( " ). \n " ) ;
2014-02-10 02:10:30 +01:00
# endif
}
2018-09-20 11:45:05 +02:00
/* Engine initialization
*
* Consists of several methods that are called by each platform ' s specific main ( argc , argv ) .
* To fully understand engine init , one should therefore start from the platform ' s main and
* see how it calls into the Main class ' methods .
*
* The initialization is typically done in 3 steps ( with the setup2 step triggered either
* automatically by setup , or manually in the platform ' s main ) .
*
* - setup ( execpath , argc , argv , p_second_phase ) is the main entry point for all platforms ,
* responsible for the initialization of all low level singletons and core types , and parsing
* command line arguments to configure things accordingly .
* If p_second_phase is true , it will chain into setup2 ( ) ( default behaviour ) . This is
* disabled on some platforms ( Android , iOS , UWP ) 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 .
*/
2017-03-05 16:44:50 +01:00
Error Main : : setup ( const char * execpath , int argc , char * argv [ ] , bool p_second_phase ) {
2014-02-10 02:10:30 +01:00
RID_OwnerBase : : init_rid ( ) ;
OS : : get_singleton ( ) - > initialize_core ( ) ;
2017-01-13 16:51:14 +01:00
2017-03-05 16:44:50 +01:00
engine = memnew ( Engine ) ;
2017-01-13 16:51:14 +01:00
2017-01-03 03:03:46 +01:00
ClassDB : : init ( ) ;
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: Initialize CORE " ) ;
register_core_types ( ) ;
register_core_driver_types ( ) ;
MAIN_PRINT ( " Main: Initialize Globals " ) ;
2017-08-07 12:17:31 +02:00
Thread : : _main_thread_id = Thread : : get_caller_id ( ) ;
2014-02-10 02:10:30 +01:00
2017-07-19 22:00:46 +02:00
globals = memnew ( ProjectSettings ) ;
2017-03-05 16:44:50 +01:00
input_map = memnew ( InputMap ) ;
2014-02-10 02:10:30 +01:00
2017-01-05 13:16:00 +01:00
register_core_settings ( ) ; //here globals is present
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
translation_server = memnew ( TranslationServer ) ;
performance = memnew ( Performance ) ;
2017-10-09 23:49:17 +02:00
ClassDB : : register_class < Performance > ( ) ;
2017-11-13 21:46:57 +01:00
engine - > add_singleton ( Engine : : Singleton ( " Performance " , performance ) ) ;
2014-02-10 02:10:30 +01:00
2019-07-01 13:58:57 +02:00
GLOBAL_DEF ( " debug/settings/crash_handler/message " , String ( " Please include this when reporting the bug on https://github.com/godotengine/godot/issues " ) ) ;
2017-09-08 03:01:49 +02:00
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: Parse CMDLine " ) ;
/* argument parsing and main creation */
List < String > args ;
List < String > main_args ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < argc ; i + + ) {
2014-02-10 02:10:30 +01:00
2014-02-18 14:37:22 +01:00
args . push_back ( String : : utf8 ( argv [ i ] ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
List < String > : : Element * I = args . front ( ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
I = args . front ( ) ;
2014-02-10 02:10:30 +01:00
while ( I ) {
2019-05-31 15:27:53 +02:00
I - > get ( ) = unescape_cmdline ( I - > get ( ) . strip_edges ( ) ) ;
2017-03-05 16:44:50 +01:00
I = I - > next ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
I = args . front ( ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
String video_driver = " " ;
String audio_driver = " " ;
2020-05-19 22:28:57 +02:00
String tablet_driver = " " ;
2018-05-12 13:21:26 +02:00
String project_path = " . " ;
2017-10-10 14:45:54 +02:00
bool upwards = false ;
2014-02-10 02:10:30 +01:00
String debug_mode ;
String debug_host ;
2019-07-29 20:09:22 +02:00
bool skip_breakpoints = false ;
2014-06-28 04:21:45 +02:00
String main_pack ;
2017-03-05 16:44:50 +01:00
bool quiet_stdout = false ;
int rtm = - 1 ;
2014-02-10 02:10:30 +01:00
String remotefs ;
String remotefs_pass ;
Vector < String > breakpoints ;
2017-03-05 16:44:50 +01:00
bool use_custom_res = true ;
bool force_res = false ;
2019-11-07 03:18:55 +01:00
bool saw_vsync_via_compositor_override = false ;
2019-02-18 20:28:40 +01:00
# ifdef TOOLS_ENABLED
2018-02-26 17:16:29 +01:00
bool found_project = false ;
2019-02-18 20:28:40 +01:00
# endif
2014-02-10 02:10:30 +01:00
2014-06-28 04:21:45 +02:00
packed_data = PackedData : : get_singleton ( ) ;
if ( ! packed_data )
packed_data = memnew ( PackedData ) ;
2014-02-10 02:10:30 +01:00
# ifdef MINIZIP_ENABLED
2016-03-09 00:00:52 +01:00
2015-05-07 01:37:25 +02:00
//XXX: always get_singleton() == 0x0
2015-04-21 00:38:02 +02:00
zip_packed_data = ZipArchive : : get_singleton ( ) ;
2015-05-07 01:37:25 +02:00
//TODO: remove this temporary fix
if ( ! zip_packed_data ) {
zip_packed_data = memnew ( ZipArchive ) ;
}
2015-04-21 00:38:02 +02:00
packed_data - > add_pack_source ( zip_packed_data ) ;
2014-02-10 02:10:30 +01:00
# endif
2017-08-19 16:45:03 +02:00
I = args . front ( ) ;
2017-03-05 16:44:50 +01:00
while ( I ) {
2020-04-09 19:06:43 +02:00
# ifdef OSX_ENABLED
// Ignore the process serial number argument passed by macOS Gatekeeper.
// Otherwise, Godot would try to open a non-existent project on the first start and abort.
if ( I - > get ( ) . begins_with ( " -psn_ " ) ) {
I = I - > next ( ) ;
continue ;
}
# endif
2016-06-18 21:03:00 +02:00
2017-03-05 16:44:50 +01:00
List < String > : : Element * N = I - > next ( ) ;
2014-02-10 02:10:30 +01:00
2017-08-19 16:45:03 +02:00
if ( I - > get ( ) = = " -h " | | I - > get ( ) = = " --help " | | I - > get ( ) = = " /? " ) { // display help
2016-03-09 00:00:52 +01:00
2017-08-19 16:45:03 +02:00
show_help = true ;
2014-02-10 02:10:30 +01:00
goto error ;
2016-03-09 00:00:52 +01:00
2017-09-24 11:32:05 +02:00
} else if ( I - > get ( ) = = " --version " ) {
print_line ( get_full_version_string ( ) ) ;
goto error ;
2019-05-19 01:33:13 +02:00
} else if ( I - > get ( ) = = " -v " | | I - > get ( ) = = " --verbose " ) { // verbose output
OS : : get_singleton ( ) - > _verbose_stdout = true ;
} else if ( I - > get ( ) = = " --quiet " ) { // quieter output
quiet_stdout = true ;
} else if ( I - > get ( ) = = " --audio-driver " ) { // audio driver
if ( I - > next ( ) ) {
audio_driver = I - > next ( ) - > get ( ) ;
2019-09-27 15:06:15 +02:00
bool found = false ;
for ( int i = 0 ; i < OS : : get_singleton ( ) - > get_audio_driver_count ( ) ; i + + ) {
if ( audio_driver = = OS : : get_singleton ( ) - > get_audio_driver_name ( i ) ) {
found = true ;
}
}
if ( ! found ) {
OS : : get_singleton ( ) - > print ( " Unknown audio driver '%s', aborting. \n Valid options are " , audio_driver . utf8 ( ) . get_data ( ) ) ;
for ( int i = 0 ; i < OS : : get_singleton ( ) - > get_audio_driver_count ( ) ; i + + ) {
if ( i = = OS : : get_singleton ( ) - > get_audio_driver_count ( ) - 1 ) {
OS : : get_singleton ( ) - > print ( " and " ) ;
} else 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 " ) ;
goto error ;
}
2019-05-19 01:33:13 +02:00
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing audio driver argument, aborting. \n " ) ;
goto error ;
}
} else if ( I - > get ( ) = = " --video-driver " ) { // force video driver
if ( I - > next ( ) ) {
video_driver = I - > next ( ) - > get ( ) ;
2019-09-27 15:06:15 +02:00
bool found = false ;
for ( int i = 0 ; i < OS : : get_singleton ( ) - > get_video_driver_count ( ) ; i + + ) {
if ( video_driver = = OS : : get_singleton ( ) - > get_video_driver_name ( i ) ) {
found = true ;
}
}
if ( ! found ) {
OS : : get_singleton ( ) - > print ( " Unknown video driver '%s', aborting. \n Valid options are " , video_driver . utf8 ( ) . get_data ( ) ) ;
for ( int i = 0 ; i < OS : : get_singleton ( ) - > get_video_driver_count ( ) ; i + + ) {
if ( i = = OS : : get_singleton ( ) - > get_video_driver_count ( ) - 1 ) {
OS : : get_singleton ( ) - > print ( " and " ) ;
} else 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 " ) ;
goto error ;
}
2019-05-19 01:33:13 +02:00
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing video driver argument, aborting. \n " ) ;
goto error ;
}
# ifndef SERVER_ENABLED
} else if ( I - > get ( ) = = " -f " | | I - > get ( ) = = " --fullscreen " ) { // force fullscreen
init_fullscreen = true ;
} else if ( I - > get ( ) = = " -m " | | I - > get ( ) = = " --maximized " ) { // force maximized window
init_maximized = true ;
video_mode . maximized = true ;
} else if ( I - > get ( ) = = " -w " | | I - > get ( ) = = " --windowed " ) { // force windowed window
init_windowed = true ;
} else if ( I - > get ( ) = = " -t " | | I - > get ( ) = = " --always-on-top " ) { // force always-on-top window
init_always_on_top = true ;
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --resolution " ) { // force resolution
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
String vm = I - > next ( ) - > get ( ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( vm . find ( " x " ) = = - 1 ) { // invalid parameter format
2016-03-09 00:00:52 +01:00
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Invalid resolution '%s', it should be e.g. '1280x720'. \n " , vm . utf8 ( ) . get_data ( ) ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
int w = vm . get_slice ( " x " , 0 ) . to_int ( ) ;
int h = vm . get_slice ( " x " , 1 ) . to_int ( ) ;
2016-03-09 00:00:52 +01:00
2017-08-19 16:45:03 +02:00
if ( w < = 0 | | h < = 0 ) {
2016-03-09 00:00:52 +01:00
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Invalid resolution '%s', width and height must be above 0. \n " , vm . utf8 ( ) . get_data ( ) ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
video_mode . width = w ;
video_mode . height = h ;
force_res = true ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing resolution argument, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2019-05-19 01:33:13 +02:00
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --position " ) { // set window position
2015-08-31 04:36:46 +02:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
String vm = I - > next ( ) - > get ( ) ;
2015-08-31 04:36:46 +02:00
2017-06-21 11:09:30 +02:00
if ( vm . find ( " , " ) = = - 1 ) { // invalid parameter format
2015-08-31 04:36:46 +02:00
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Invalid position '%s', it should be e.g. '80,128'. \n " , vm . utf8 ( ) . get_data ( ) ) ;
2015-08-31 04:36:46 +02:00
goto error ;
}
2017-06-21 11:09:30 +02:00
int x = vm . get_slice ( " , " , 0 ) . to_int ( ) ;
int y = vm . get_slice ( " , " , 1 ) . to_int ( ) ;
2015-08-31 04:36:46 +02:00
2017-03-05 16:44:50 +01:00
init_custom_pos = Point2 ( x , y ) ;
init_use_custom_pos = true ;
2015-08-31 04:36:46 +02:00
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2015-08-31 04:36:46 +02:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing position argument, aborting. \n " ) ;
2015-08-31 04:36:46 +02:00
goto error ;
}
2019-05-19 01:33:13 +02:00
} else if ( I - > get ( ) = = " --low-dpi " ) { // force low DPI (macOS only)
2015-08-31 04:36:46 +02:00
2019-05-19 01:33:13 +02:00
force_lowdpi = true ;
2020-09-23 13:43:51 +02:00
} else if ( I - > get ( ) = = " --no-window " ) { // run with an invisible window
2017-12-27 20:51:19 +01:00
2019-05-19 01:33:13 +02:00
OS : : get_singleton ( ) - > set_no_window_mode ( true ) ;
2020-05-19 22:28:57 +02:00
} else if ( I - > get ( ) = = " --tablet-driver " ) {
if ( I - > next ( ) ) {
tablet_driver = I - > next ( ) - > get ( ) ;
bool found = false ;
for ( int i = 0 ; i < OS : : get_singleton ( ) - > get_tablet_driver_count ( ) ; i + + ) {
if ( tablet_driver = = OS : : get_singleton ( ) - > get_tablet_driver_name ( i ) ) {
found = true ;
}
}
2020-05-05 13:53:30 +02:00
2020-05-19 22:28:57 +02:00
if ( ! found ) {
OS : : get_singleton ( ) - > print ( " Unknown tablet driver '%s', aborting. \n " , tablet_driver . utf8 ( ) . get_data ( ) ) ;
goto error ;
}
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing tablet driver argument, aborting. \n " ) ;
goto error ;
}
2019-11-07 03:18:55 +01:00
} else if ( I - > get ( ) = = " --enable-vsync-via-compositor " ) {
video_mode . vsync_via_compositor = true ;
saw_vsync_via_compositor_override = true ;
} else if ( I - > get ( ) = = " --disable-vsync-via-compositor " ) {
video_mode . vsync_via_compositor = false ;
saw_vsync_via_compositor_override = true ;
2019-05-19 01:33:13 +02:00
# endif
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --profiling " ) { // enable profiling
2015-12-12 16:06:53 +01:00
2017-03-05 16:44:50 +01:00
use_debug_profiler = true ;
2016-03-09 00:00:52 +01:00
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " -l " | | I - > get ( ) = = " --language " ) { // language
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
locale = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing language argument, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2016-05-30 05:28:29 +02:00
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --remote-fs " ) { // remote filesystem
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
remotefs = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing remote filesystem address, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --remote-fs-password " ) { // remote filesystem password
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
remotefs_pass = I - > next ( ) - > get ( ) ;
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing remote filesystem password, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --render-thread " ) { // render thread mode
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
if ( I - > next ( ) - > get ( ) = = " safe " )
rtm = OS : : RENDER_THREAD_SAFE ;
else if ( I - > next ( ) - > get ( ) = = " unsafe " )
rtm = OS : : RENDER_THREAD_UNSAFE ;
else if ( I - > next ( ) - > get ( ) = = " separate " )
rtm = OS : : RENDER_SEPARATE_THREAD ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing render thread mode argument, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2018-02-16 19:40:22 +01:00
# ifdef TOOLS_ENABLED
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " -e " | | I - > get ( ) = = " --editor " ) { // starts editor
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
editor = true ;
2018-02-13 18:56:38 +01:00
} else if ( I - > get ( ) = = " -p " | | I - > get ( ) = = " --project-manager " ) { // starts project manager
project_manager = true ;
2018-02-14 16:23:04 +01:00
} else if ( I - > get ( ) = = " --build-solutions " ) { // Build the scripting solution such C#
auto_build_solutions = true ;
2018-06-16 00:08:59 +02:00
editor = true ;
2019-08-19 16:14:58 +02:00
# ifdef DEBUG_METHODS_ENABLED
} else if ( I - > get ( ) = = " --gdnative-generate-json-api " ) {
// Register as an editor instance to use the GLES2 fallback automatically on hardware that doesn't support the GLES3 backend
editor = true ;
// We still pass it to the main arguments since the argument handling itself is not done in this function
main_args . push_back ( I - > get ( ) ) ;
# endif
2020-01-08 14:22:50 +01:00
} else if ( I - > get ( ) = = " --export " | | I - > get ( ) = = " --export-debug " | | I - > get ( ) = = " --export-pack " ) { // Export project
2019-06-28 14:34:09 +02:00
editor = true ;
main_args . push_back ( I - > get ( ) ) ;
2018-02-16 19:40:22 +01:00
# endif
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --path " ) { // set path of project to start or edit
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
String p = I - > next ( ) - > get ( ) ;
2017-03-05 16:44:50 +01:00
if ( OS : : get_singleton ( ) - > set_cwd ( p ) = = OK ) {
2014-02-10 02:10:30 +01:00
//nothing
} else {
2018-05-12 13:21:26 +02:00
project_path = I - > next ( ) - > get ( ) ; //use project_path instead
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing relative or absolute path, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2017-10-10 14:45:54 +02:00
} else if ( I - > get ( ) = = " -u " | | I - > get ( ) = = " --upwards " ) { // scan folders upwards
upwards = true ;
2018-02-24 18:22:29 +01:00
} else if ( I - > get ( ) = = " -q " | | I - > get ( ) = = " --quit " ) { // Auto quit at the end of the first main loop iteration
2018-02-14 16:23:04 +01:00
auto_quit = true ;
2017-05-01 17:44:52 +02:00
} else if ( I - > get ( ) . ends_with ( " project.godot " ) ) {
String path ;
String file = I - > get ( ) ;
int sep = MAX ( file . find_last ( " / " ) , file . find_last ( " \\ " ) ) ;
if ( sep = = - 1 )
path = " . " ;
else {
path = file . substr ( 0 , sep ) ;
}
if ( OS : : get_singleton ( ) - > set_cwd ( path ) = = OK ) {
// path already specified, don't override
} else {
2018-05-12 13:21:26 +02:00
project_path = path ;
2017-05-01 17:44:52 +02:00
}
# ifdef TOOLS_ENABLED
editor = true ;
# endif
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " -b " | | I - > get ( ) = = " --breakpoints " ) { // add breakpoints
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
String bplist = I - > next ( ) - > get ( ) ;
2017-03-05 16:44:50 +01:00
breakpoints = bplist . split ( " , " ) ;
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing list of breakpoints, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --frame-delay " ) { // force frame delay
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
frame_delay = I - > next ( ) - > get ( ) . to_int ( ) ;
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing frame delay argument, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
}
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --time-scale " ) { // force time scale
2014-09-21 06:43:42 +02:00
if ( I - > next ( ) ) {
2017-01-13 16:51:14 +01:00
Engine : : get_singleton ( ) - > set_time_scale ( I - > next ( ) - > get ( ) . to_double ( ) ) ;
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2014-09-21 06:43:42 +02:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing time scale argument, aborting. \n " ) ;
2014-09-21 06:43:42 +02:00
goto error ;
}
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --main-pack " ) {
2014-06-28 04:21:45 +02:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
main_pack = I - > next ( ) - > get ( ) ;
2014-06-28 04:21:45 +02:00
N = I - > next ( ) - > next ( ) ;
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing path to main pack file, aborting. \n " ) ;
2014-06-28 04:21:45 +02:00
goto error ;
} ;
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " -d " | | I - > get ( ) = = " --debug " ) {
2017-03-05 16:44:50 +01:00
debug_mode = " local " ;
2020-07-09 09:32:42 +02:00
OS : : get_singleton ( ) - > _debug_stdout = true ;
2019-05-19 01:33:13 +02:00
# if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED)
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --debug-collisions " ) {
2017-03-05 16:44:50 +01:00
debug_collisions = true ;
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --debug-navigation " ) {
2017-03-05 16:44:50 +01:00
debug_navigation = true ;
2017-04-07 16:17:16 +02:00
# endif
2017-06-21 11:09:30 +02:00
} else if ( I - > get ( ) = = " --remote-debug " ) {
2014-02-10 02:10:30 +01:00
if ( I - > next ( ) ) {
2017-03-05 16:44:50 +01:00
debug_mode = " remote " ;
debug_host = I - > next ( ) - > get ( ) ;
2017-08-19 16:45:03 +02:00
if ( debug_host . find ( " : " ) = = - 1 ) { // wrong address
OS : : get_singleton ( ) - > print ( " Invalid debug host address, it should be of the form <host/IP>:<port>. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
2015-09-10 05:10:54 +02:00
}
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2014-02-10 02:10:30 +01:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing remote debug host address, aborting. \n " ) ;
2014-02-10 02:10:30 +01:00
goto error ;
2016-09-14 04:02:18 +02:00
}
2017-08-19 16:45:03 +02:00
} else if ( I - > get ( ) = = " --allow_focus_steal_pid " ) { // not exposed to user
2016-09-14 04:02:18 +02:00
if ( I - > next ( ) ) {
2017-08-21 04:42:54 +02:00
allow_focus_steal_pid = I - > next ( ) - > get ( ) . to_int64 ( ) ;
2017-03-05 16:44:50 +01:00
N = I - > next ( ) - > next ( ) ;
2016-09-14 04:02:18 +02:00
} else {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > print ( " Missing editor PID argument, aborting. \n " ) ;
2016-09-14 04:02:18 +02:00
goto error ;
2014-02-10 02:10:30 +01:00
}
2017-08-30 12:40:35 +02:00
} else if ( I - > get ( ) = = " --disable-render-loop " ) {
disable_render_loop = true ;
} else if ( I - > get ( ) = = " --fixed-fps " ) {
if ( I - > next ( ) ) {
fixed_fps = I - > next ( ) - > get ( ) . to_int ( ) ;
N = I - > next ( ) - > next ( ) ;
} else {
OS : : get_singleton ( ) - > print ( " Missing fixed-fps argument, aborting. \n " ) ;
goto error ;
}
2018-03-21 08:46:05 +01:00
} else if ( I - > get ( ) = = " --print-fps " ) {
print_fps = true ;
2017-09-08 03:01:49 +02:00
} else if ( I - > get ( ) = = " --disable-crash-handler " ) {
OS : : get_singleton ( ) - > disable_crash_handler ( ) ;
2019-07-29 20:09:22 +02:00
} else if ( I - > get ( ) = = " --skip-breakpoints " ) {
skip_breakpoints = true ;
2014-02-10 02:10:30 +01:00
} else {
2018-05-12 12:51:41 +02:00
main_args . push_back ( I - > get ( ) ) ;
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
I = N ;
2014-02-10 02:10:30 +01:00
}
2020-01-10 09:48:03 +01:00
# ifdef TOOLS_ENABLED
if ( editor & & project_manager ) {
OS : : get_singleton ( ) - > print ( " Error: Command line arguments implied opening both editor and project manager, which is not possible. Aborting. \n " ) ;
goto error ;
}
# endif
2018-11-08 18:42:41 +01:00
// Network file system needs to be configured before globals, since globals are based on the
// 'project.godot' file which will only be available through the network if this is enabled
FileAccessNetwork : : configure ( ) ;
if ( remotefs ! = " " ) {
file_access_network_client = memnew ( FileAccessNetworkClient ) ;
int port ;
if ( remotefs . find ( " : " ) ! = - 1 ) {
port = remotefs . get_slicec ( ' : ' , 1 ) . to_int ( ) ;
remotefs = remotefs . get_slicec ( ' : ' , 0 ) ;
} else {
port = 6010 ;
}
Error err = file_access_network_client - > connect ( remotefs , port , remotefs_pass ) ;
if ( err ) {
OS : : get_singleton ( ) - > printerr ( " Could not connect to remotefs: %s:%i. \n " , remotefs . utf8 ( ) . get_data ( ) , port ) ;
goto error ;
}
FileAccess : : make_default < FileAccessNetwork > ( FileAccess : : ACCESS_RESOURCES ) ;
}
2018-05-12 13:21:26 +02:00
if ( globals - > setup ( project_path , main_pack , upwards ) = = OK ) {
2019-02-18 20:28:40 +01:00
# ifdef TOOLS_ENABLED
2018-03-15 12:22:10 +01:00
found_project = true ;
2019-02-18 20:28:40 +01:00
# endif
2018-03-15 12:22:10 +01:00
} else {
# ifdef TOOLS_ENABLED
editor = false ;
# else
2020-01-28 00:10:31 +01:00
const String error_msg = " Error: Couldn't load project data at path \" " + project_path + " \" . Is the .pck file missing? \n If you've renamed the executable, the associated .pck file should also be renamed to match the executable's name (without the extension). \n " ;
2019-02-22 15:38:49 +01:00
OS : : get_singleton ( ) - > print ( " %s " , error_msg . ascii ( ) . get_data ( ) ) ;
2018-10-15 17:50:29 +02:00
OS : : get_singleton ( ) - > alert ( error_msg ) ;
2018-03-15 12:22:10 +01:00
goto error ;
# endif
}
2021-01-08 10:24:41 +01:00
// Initialize user data dir.
OS : : get_singleton ( ) - > ensure_user_data_dir ( ) ;
2017-07-18 02:05:38 +02:00
GLOBAL_DEF ( " memory/limits/multithreaded_server/rid_pool_prealloc " , 60 ) ;
2018-10-05 18:43:53 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " memory/limits/multithreaded_server/rid_pool_prealloc " , PropertyInfo ( Variant : : INT , " memory/limits/multithreaded_server/rid_pool_prealloc " , PROPERTY_HINT_RANGE , " 0,500,1 " ) ) ; // No negative and limit to 500 due to crashes
2017-07-18 02:05:38 +02:00
GLOBAL_DEF ( " network/limits/debugger_stdout/max_chars_per_second " , 2048 ) ;
2018-10-05 18:43:53 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " network/limits/debugger_stdout/max_chars_per_second " , PropertyInfo ( Variant : : INT , " network/limits/debugger_stdout/max_chars_per_second " , PROPERTY_HINT_RANGE , " 0, 4096, 1, or_greater " ) ) ;
2018-01-03 17:04:10 +01:00
GLOBAL_DEF ( " network/limits/debugger_stdout/max_messages_per_frame " , 10 ) ;
2018-10-05 18:43:53 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " network/limits/debugger_stdout/max_messages_per_frame " , PropertyInfo ( Variant : : INT , " network/limits/debugger_stdout/max_messages_per_frame " , PROPERTY_HINT_RANGE , " 0, 20, 1, or_greater " ) ) ;
2019-07-31 17:24:53 +02:00
GLOBAL_DEF ( " network/limits/debugger_stdout/max_errors_per_second " , 100 ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " network/limits/debugger_stdout/max_errors_per_second " , PropertyInfo ( Variant : : INT , " network/limits/debugger_stdout/max_errors_per_second " , PROPERTY_HINT_RANGE , " 0, 200, 1, or_greater " ) ) ;
GLOBAL_DEF ( " network/limits/debugger_stdout/max_warnings_per_second " , 100 ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " network/limits/debugger_stdout/max_warnings_per_second " , PropertyInfo ( Variant : : INT , " network/limits/debugger_stdout/max_warnings_per_second " , PROPERTY_HINT_RANGE , " 0, 200, 1, or_greater " ) ) ;
2017-01-05 13:16:00 +01:00
2014-02-10 02:10:30 +01:00
if ( debug_mode = = " remote " ) {
2017-03-05 16:44:50 +01:00
ScriptDebuggerRemote * sdr = memnew ( ScriptDebuggerRemote ) ;
2017-06-10 16:28:18 +02:00
uint16_t debug_port = 6007 ;
2017-03-05 16:44:50 +01:00
if ( debug_host . find ( " : " ) ! = - 1 ) {
2017-05-08 22:22:28 +02:00
int sep_pos = debug_host . find_last ( " : " ) ;
debug_port = debug_host . substr ( sep_pos + 1 , debug_host . length ( ) ) . to_int ( ) ;
debug_host = debug_host . substr ( 0 , sep_pos ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
Error derr = sdr - > connect_to_host ( debug_host , debug_port ) ;
2014-02-10 02:10:30 +01:00
2019-07-29 20:09:22 +02:00
sdr - > set_skip_breakpoints ( skip_breakpoints ) ;
2017-03-05 16:44:50 +01:00
if ( derr ! = OK ) {
2014-02-10 02:10:30 +01:00
memdelete ( sdr ) ;
} else {
2017-03-05 16:44:50 +01:00
script_debugger = sdr ;
2020-07-21 01:09:17 +02:00
sdr - > set_allow_focus_steal_pid ( allow_focus_steal_pid ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
} else if ( debug_mode = = " local " ) {
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
script_debugger = memnew ( ScriptDebuggerLocal ) ;
2018-02-11 12:08:37 +01:00
OS : : get_singleton ( ) - > initialize_debugging ( ) ;
2014-02-10 02:10:30 +01:00
}
if ( script_debugger ) {
//there is a debugger, parse breakpoints
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < breakpoints . size ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
String bp = breakpoints [ i ] ;
2017-03-05 16:44:50 +01:00
int sp = bp . find_last ( " : " ) ;
2019-08-08 22:08:27 +02:00
ERR_CONTINUE_MSG ( sp = = - 1 , " Invalid breakpoint: ' " + bp + " ', expected file:line format. " ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
script_debugger - > insert_breakpoint ( bp . substr ( sp + 1 , bp . length ( ) ) . to_int ( ) , bp . substr ( 0 , sp ) ) ;
2014-02-10 02:10:30 +01:00
}
}
# ifdef TOOLS_ENABLED
if ( editor ) {
packed_data - > set_disabled ( true ) ;
2017-07-19 22:00:46 +02:00
globals - > set_disable_feature_overrides ( true ) ;
2014-02-10 02:10:30 +01:00
}
# endif
2018-02-19 13:31:06 +01:00
# ifdef TOOLS_ENABLED
2014-02-10 02:10:30 +01:00
if ( editor ) {
2017-08-13 16:21:45 +02:00
Engine : : get_singleton ( ) - > set_editor_hint ( true ) ;
2017-06-21 11:09:30 +02:00
main_args . push_back ( " --editor " ) ;
2017-12-29 20:10:15 +01:00
if ( ! init_windowed ) {
init_maximized = true ;
video_mode . maximized = true ;
}
2014-02-10 02:10:30 +01:00
}
2020-01-10 09:48:03 +01:00
if ( ! project_manager & & ! editor ) {
2018-02-13 18:56:38 +01:00
// Determine if the project manager should be requested
2018-02-26 17:16:29 +01:00
project_manager = main_args . size ( ) = = 0 & & ! found_project ;
2018-02-13 18:56:38 +01:00
}
2014-02-10 02:10:30 +01:00
# endif
2020-07-12 14:22:06 +02:00
GLOBAL_DEF ( " logging/file_logging/enable_file_logging " , false ) ;
// Only file logging by default on desktop platforms as logs can't be
// accessed easily on mobile/Web platforms (if at all).
// This also prevents logs from being created for the editor instance, as feature tags
// are disabled while in the editor (even if they should logically apply).
GLOBAL_DEF ( " logging/file_logging/enable_file_logging.pc " , true ) ;
GLOBAL_DEF ( " logging/file_logging/log_path " , " user://logs/godot.log " ) ;
GLOBAL_DEF ( " logging/file_logging/max_log_files " , 5 ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " logging/file_logging/max_log_files " , PropertyInfo ( Variant : : INT , " logging/file_logging/max_log_files " , PROPERTY_HINT_RANGE , " 0,20,1,or_greater " ) ) ; //no negative numbers
if ( ! project_manager & & ! editor & & FileAccess : : get_create_func ( FileAccess : : ACCESS_USERDATA ) & & GLOBAL_GET ( " logging/file_logging/enable_file_logging " ) ) {
// Don't create logs for the project manager as they would be written to
// the current working directory, which is inconvenient.
String base_path = GLOBAL_GET ( " logging/file_logging/log_path " ) ;
int max_files = GLOBAL_GET ( " logging/file_logging/max_log_files " ) ;
OS : : get_singleton ( ) - > add_logger ( memnew ( RotatedFileLogger ( base_path , max_files ) ) ) ;
}
2018-02-26 17:16:29 +01:00
if ( main_args . size ( ) = = 0 & & String ( GLOBAL_DEF ( " application/run/main_scene " , " " ) ) = = " " ) {
# ifdef TOOLS_ENABLED
if ( ! editor & & ! project_manager ) {
# endif
OS : : get_singleton ( ) - > print ( " Error: Can't run project: no main scene defined. \n " ) ;
goto error ;
# ifdef TOOLS_ENABLED
}
# endif
}
2018-02-19 13:31:06 +01:00
if ( editor | | project_manager ) {
2019-03-09 01:04:53 +01:00
Engine : : get_singleton ( ) - > set_editor_hint ( true ) ;
2018-02-19 13:31:06 +01:00
use_custom_res = false ;
2016-06-05 06:19:42 +02:00
input_map - > load_default ( ) ; //keys for editor
2018-02-19 13:31:06 +01:00
} else {
2016-06-05 06:19:42 +02:00
input_map - > load_from_globals ( ) ; //keys for game
2018-02-19 13:31:06 +01:00
}
if ( bool ( ProjectSettings : : get_singleton ( ) - > get ( " application/run/disable_stdout " ) ) ) {
quiet_stdout = true ;
}
if ( bool ( ProjectSettings : : get_singleton ( ) - > get ( " application/run/disable_stderr " ) ) ) {
_print_error_enabled = false ;
} ;
if ( quiet_stdout )
_print_line_enabled = false ;
OS : : get_singleton ( ) - > set_cmdline ( execpath , main_args ) ;
2014-02-10 02:10:30 +01:00
2018-03-01 22:17:34 +01:00
GLOBAL_DEF ( " rendering/quality/driver/driver_name " , " GLES3 " ) ;
2018-07-19 23:58:15 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " rendering/quality/driver/driver_name " , PropertyInfo ( Variant : : STRING , " rendering/quality/driver/driver_name " , PROPERTY_HINT_ENUM , " GLES2,GLES3 " ) ) ;
2018-03-01 22:17:34 +01:00
if ( video_driver = = " " ) {
2020-12-11 17:35:29 +01:00
video_driver = GLOBAL_GET ( " rendering/quality/driver/driver_name " ) ;
2018-03-01 22:17:34 +01:00
}
2014-02-10 02:10:30 +01:00
2019-03-05 13:46:51 +01:00
GLOBAL_DEF ( " rendering/quality/driver/fallback_to_gles2 " , false ) ;
2018-08-25 00:04:25 +02:00
2020-05-05 17:25:45 +02:00
// Assigning here, to be sure that it appears in docs
GLOBAL_DEF ( " rendering/quality/2d/use_nvidia_rect_flicker_workaround " , false ) ;
2019-01-14 18:26:41 +01:00
2017-11-09 17:55:51 +01:00
GLOBAL_DEF ( " display/window/size/width " , 1024 ) ;
2018-10-02 14:51:24 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " display/window/size/width " , PropertyInfo ( Variant : : INT , " display/window/size/width " , PROPERTY_HINT_RANGE , " 0,7680,or_greater " ) ) ; // 8K resolution
2017-11-09 17:55:51 +01:00
GLOBAL_DEF ( " display/window/size/height " , 600 ) ;
2018-10-02 14:51:24 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " display/window/size/height " , PropertyInfo ( Variant : : INT , " display/window/size/height " , PROPERTY_HINT_RANGE , " 0,4320,or_greater " ) ) ; // 8K resolution
2017-11-09 17:55:51 +01:00
GLOBAL_DEF ( " display/window/size/resizable " , true ) ;
GLOBAL_DEF ( " display/window/size/borderless " , false ) ;
GLOBAL_DEF ( " display/window/size/fullscreen " , false ) ;
2017-12-27 20:51:19 +01:00
GLOBAL_DEF ( " display/window/size/always_on_top " , false ) ;
2017-11-09 17:55:51 +01:00
GLOBAL_DEF ( " display/window/size/test_width " , 0 ) ;
2018-10-02 14:51:24 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " display/window/size/test_width " , PropertyInfo ( Variant : : INT , " display/window/size/test_width " , PROPERTY_HINT_RANGE , " 0,7680,or_greater " ) ) ; // 8K resolution
2017-11-09 17:55:51 +01:00
GLOBAL_DEF ( " display/window/size/test_height " , 0 ) ;
2018-10-02 14:51:24 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " display/window/size/test_height " , PropertyInfo ( Variant : : INT , " display/window/size/test_height " , PROPERTY_HINT_RANGE , " 0,4320,or_greater " ) ) ; // 8K resolution
2017-11-09 17:55:51 +01:00
2017-11-09 17:01:29 +01:00
if ( use_custom_res ) {
if ( ! force_res ) {
2017-11-09 17:55:51 +01:00
video_mode . width = GLOBAL_GET ( " display/window/size/width " ) ;
video_mode . height = GLOBAL_GET ( " display/window/size/height " ) ;
2017-11-09 17:01:29 +01:00
if ( globals - > has_setting ( " display/window/size/test_width " ) & & globals - > has_setting ( " display/window/size/test_height " ) ) {
2019-10-04 15:26:02 +02:00
2017-11-09 17:01:29 +01:00
int tw = globals - > get ( " display/window/size/test_width " ) ;
2019-10-04 15:26:02 +02:00
if ( tw > 0 ) {
2017-11-09 17:01:29 +01:00
video_mode . width = tw ;
2019-10-04 15:26:02 +02:00
}
int th = globals - > get ( " display/window/size/test_height " ) ;
if ( th > 0 ) {
2017-11-09 17:01:29 +01:00
video_mode . height = th ;
}
}
2014-09-15 16:33:30 +02:00
}
2017-11-09 17:01:29 +01:00
2017-11-09 17:55:51 +01:00
video_mode . resizable = GLOBAL_GET ( " display/window/size/resizable " ) ;
video_mode . borderless_window = GLOBAL_GET ( " display/window/size/borderless " ) ;
video_mode . fullscreen = GLOBAL_GET ( " display/window/size/fullscreen " ) ;
2017-12-27 20:51:19 +01:00
video_mode . always_on_top = GLOBAL_GET ( " display/window/size/always_on_top " ) ;
2014-09-15 16:33:30 +02:00
}
2014-02-10 02:10:30 +01:00
2017-11-09 17:01:29 +01:00
if ( ! force_lowdpi ) {
OS : : get_singleton ( ) - > _allow_hidpi = GLOBAL_DEF ( " display/window/dpi/allow_hidpi " , false ) ;
}
2019-08-27 23:16:55 +02:00
video_mode . use_vsync = GLOBAL_DEF_RST ( " display/window/vsync/use_vsync " , true ) ;
2018-06-25 17:17:19 +02:00
OS : : get_singleton ( ) - > _use_vsync = video_mode . use_vsync ;
2019-11-07 03:18:55 +01:00
if ( ! saw_vsync_via_compositor_override ) {
// If one of the command line options to enable/disable vsync via the
// window compositor ("--enable-vsync-via-compositor" or
// "--disable-vsync-via-compositor") was present then it overrides the
// project setting.
2020-01-13 09:27:06 +01:00
video_mode . vsync_via_compositor = GLOBAL_DEF ( " display/window/vsync/vsync_via_compositor " , false ) ;
2019-11-07 03:18:55 +01:00
}
OS : : get_singleton ( ) - > _vsync_via_compositor = video_mode . vsync_via_compositor ;
2020-05-19 22:28:57 +02:00
if ( tablet_driver = = " " ) { // specified in project.godot
tablet_driver = GLOBAL_DEF_RST ( " display/window/tablet_driver " , OS : : get_singleton ( ) - > get_tablet_driver_name ( 0 ) ) ;
2020-05-05 13:53:30 +02:00
}
2020-05-19 22:28:57 +02:00
for ( int i = 0 ; i < OS : : get_singleton ( ) - > get_tablet_driver_count ( ) ; i + + ) {
if ( tablet_driver = = OS : : get_singleton ( ) - > get_tablet_driver_name ( i ) ) {
OS : : get_singleton ( ) - > set_current_tablet_driver ( OS : : get_singleton ( ) - > get_tablet_driver_name ( i ) ) ;
break ;
}
}
if ( tablet_driver = = " " ) {
OS : : get_singleton ( ) - > set_current_tablet_driver ( OS : : get_singleton ( ) - > get_tablet_driver_name ( 0 ) ) ;
}
2020-05-05 13:53:30 +02:00
2019-02-20 14:37:25 +01:00
OS : : get_singleton ( ) - > _allow_layered = GLOBAL_DEF ( " display/window/per_pixel_transparency/allowed " , false ) ;
video_mode . layered = GLOBAL_DEF ( " display/window/per_pixel_transparency/enabled " , false ) ;
2017-11-09 17:01:29 +01:00
2017-07-19 22:00:46 +02:00
GLOBAL_DEF ( " rendering/quality/intended_usage/framebuffer_allocation " , 2 ) ;
GLOBAL_DEF ( " rendering/quality/intended_usage/framebuffer_allocation.mobile " , 3 ) ;
2018-02-13 18:56:38 +01:00
if ( editor | | project_manager ) {
// The editor and project manager always detect and use hiDPI if needed
OS : : get_singleton ( ) - > _allow_hidpi = true ;
2017-12-10 19:38:26 +01:00
OS : : get_singleton ( ) - > _allow_layered = false ;
2017-10-05 21:41:42 +02:00
}
2018-02-13 18:56:38 +01:00
2017-07-18 02:05:38 +02:00
Engine : : get_singleton ( ) - > _pixel_snap = GLOBAL_DEF ( " rendering/quality/2d/use_pixel_snap " , false ) ;
2020-11-15 10:40:07 +01:00
Engine : : get_singleton ( ) - > _snap_2d_transforms = GLOBAL_DEF ( " rendering/quality/2d/use_transform_snap " , false ) ;
2020-12-25 19:53:00 +01:00
Engine : : get_singleton ( ) - > _snap_2d_viewports = GLOBAL_DEF ( " rendering/quality/2d/use_camera_snap " , false ) ;
2017-07-18 02:05:38 +02:00
OS : : get_singleton ( ) - > _keep_screen_on = GLOBAL_DEF ( " display/window/energy_saving/keep_screen_on " , true ) ;
2017-03-05 16:44:50 +01:00
if ( rtm = = - 1 ) {
rtm = GLOBAL_DEF ( " rendering/threads/thread_model " , OS : : RENDER_THREAD_SAFE ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
if ( rtm > = 0 & & rtm < 3 ) {
2020-09-23 11:24:01 +02:00
# ifdef NO_THREADS
rtm = OS : : RENDER_THREAD_UNSAFE ; // No threads available on this platform.
# else
2015-12-31 20:24:27 +01:00
if ( editor ) {
2017-03-05 16:44:50 +01:00
rtm = OS : : RENDER_THREAD_SAFE ;
2015-12-31 20:24:27 +01:00
}
2020-09-23 11:24:01 +02:00
# endif
2017-03-05 16:44:50 +01:00
OS : : get_singleton ( ) - > _render_thread_mode = OS : : RenderThreadMode ( rtm ) ;
2015-12-31 20:24:27 +01:00
}
2014-02-10 02:10:30 +01:00
2017-08-19 16:45:03 +02:00
/* Determine audio and video drivers */
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < OS : : get_singleton ( ) - > get_video_driver_count ( ) ; i + + ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( video_driver = = OS : : get_singleton ( ) - > get_video_driver_name ( i ) ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
video_driver_idx = i ;
2014-02-10 02:10:30 +01:00
break ;
}
}
2017-03-05 16:44:50 +01:00
if ( video_driver_idx < 0 ) {
2014-02-10 02:10:30 +01:00
video_driver_idx = 0 ;
}
2017-08-19 16:45:03 +02:00
if ( audio_driver = = " " ) { // specified in project.godot
2018-07-19 23:58:15 +02:00
audio_driver = GLOBAL_DEF_RST ( " audio/driver " , OS : : get_singleton ( ) - > get_audio_driver_name ( 0 ) ) ;
2017-08-19 16:45:03 +02:00
}
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < OS : : get_singleton ( ) - > get_audio_driver_count ( ) ; i + + ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( audio_driver = = OS : : get_singleton ( ) - > get_audio_driver_name ( i ) ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
audio_driver_idx = i ;
2014-02-10 02:10:30 +01:00
break ;
}
}
2017-03-05 16:44:50 +01:00
if ( audio_driver_idx < 0 ) {
2016-01-31 22:47:13 +01:00
audio_driver_idx = 0 ;
2014-02-10 02:10:30 +01:00
}
{
2017-07-18 02:05:38 +02:00
String orientation = GLOBAL_DEF ( " display/window/handheld/orientation " , " landscape " ) ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( orientation = = " portrait " )
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_screen_orientation ( OS : : SCREEN_PORTRAIT ) ;
2017-03-05 16:44:50 +01:00
else if ( orientation = = " reverse_landscape " )
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_screen_orientation ( OS : : SCREEN_REVERSE_LANDSCAPE ) ;
2017-03-05 16:44:50 +01:00
else if ( orientation = = " reverse_portrait " )
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_screen_orientation ( OS : : SCREEN_REVERSE_PORTRAIT ) ;
2017-03-05 16:44:50 +01:00
else if ( orientation = = " sensor_landscape " )
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_screen_orientation ( OS : : SCREEN_SENSOR_LANDSCAPE ) ;
2017-03-05 16:44:50 +01:00
else if ( orientation = = " sensor_portrait " )
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_screen_orientation ( OS : : SCREEN_SENSOR_PORTRAIT ) ;
2017-03-05 16:44:50 +01:00
else if ( orientation = = " sensor " )
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_screen_orientation ( OS : : SCREEN_SENSOR ) ;
else
OS : : get_singleton ( ) - > set_screen_orientation ( OS : : SCREEN_LANDSCAPE ) ;
}
2018-01-22 22:01:31 +01:00
Engine : : get_singleton ( ) - > set_iterations_per_second ( GLOBAL_DEF ( " physics/common/physics_fps " , 60 ) ) ;
2019-06-13 05:37:51 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " physics/common/physics_fps " , PropertyInfo ( Variant : : INT , " physics/common/physics_fps " , PROPERTY_HINT_RANGE , " 1,120,1,or_greater " ) ) ;
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
Engine : : get_singleton ( ) - > set_physics_jitter_fix ( GLOBAL_DEF ( " physics/common/physics_jitter_fix " , 0.5 ) ) ;
2017-07-18 02:05:38 +02:00
Engine : : get_singleton ( ) - > set_target_fps ( GLOBAL_DEF ( " debug/settings/fps/force_fps " , 0 ) ) ;
2018-10-05 18:43:53 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " debug/settings/fps/force_fps " , PropertyInfo ( Variant : : INT , " debug/settings/fps/force_fps " , PROPERTY_HINT_RANGE , " 0,120,1,or_greater " ) ) ;
2017-01-05 13:16:00 +01:00
2018-03-21 08:46:05 +01:00
GLOBAL_DEF ( " debug/settings/stdout/print_fps " , false ) ;
2020-04-20 12:29:34 +02:00
GLOBAL_DEF ( " debug/settings/stdout/verbose_stdout " , false ) ;
2014-02-10 02:10:30 +01:00
2020-04-20 12:29:34 +02:00
if ( ! OS : : get_singleton ( ) - > _verbose_stdout ) { // Not manually overridden.
OS : : get_singleton ( ) - > _verbose_stdout = GLOBAL_GET ( " debug/settings/stdout/verbose_stdout " ) ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( frame_delay = = 0 ) {
2017-07-18 02:05:38 +02:00
frame_delay = GLOBAL_DEF ( " application/run/frame_delay_msec " , 0 ) ;
2018-10-05 18:43:53 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " application/run/frame_delay_msec " , PropertyInfo ( Variant : : INT , " application/run/frame_delay_msec " , PROPERTY_HINT_RANGE , " 0,100,1,or_greater " ) ) ; // No negative numbers
2016-07-09 17:34:30 +02:00
}
2017-11-22 18:40:43 +01:00
OS : : get_singleton ( ) - > set_low_processor_usage_mode ( GLOBAL_DEF ( " application/run/low_processor_mode " , false ) ) ;
2019-05-09 22:40:20 +02:00
OS : : get_singleton ( ) - > set_low_processor_usage_mode_sleep_usec ( GLOBAL_DEF ( " application/run/low_processor_mode_sleep_usec " , 6900 ) ) ; // Roughly 144 FPS
2018-10-05 18:43:53 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " application/run/low_processor_mode_sleep_usec " , PropertyInfo ( Variant : : INT , " application/run/low_processor_mode_sleep_usec " , PROPERTY_HINT_RANGE , " 0,33200,1,or_greater " ) ) ; // No negative numbers
2017-11-22 18:40:43 +01:00
2019-12-09 20:38:22 +01:00
GLOBAL_DEF ( " display/window/ios/hide_home_indicator " , true ) ;
2020-09-27 19:31:02 +02:00
GLOBAL_DEF ( " input_devices/pointing/ios/touch_delay " , 0.150 ) ;
2019-12-09 20:38:22 +01:00
2017-01-13 16:51:14 +01:00
Engine : : get_singleton ( ) - > set_frame_delay ( frame_delay ) ;
2016-07-09 17:34:30 +02:00
2017-03-05 16:44:50 +01:00
message_queue = memnew ( MessageQueue ) ;
2014-02-10 02:10:30 +01:00
if ( p_second_phase )
return setup2 ( ) ;
return OK ;
2017-03-05 16:44:50 +01:00
error :
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
video_driver = " " ;
audio_driver = " " ;
2020-05-19 22:28:57 +02:00
tablet_driver = " " ;
2018-05-12 13:21:26 +02:00
project_path = " " ;
2016-03-09 00:00:52 +01:00
args . clear ( ) ;
2014-02-10 02:10:30 +01:00
main_args . clear ( ) ;
2016-03-09 00:00:52 +01:00
2017-08-19 16:45:03 +02:00
if ( show_help )
print_help ( execpath ) ;
2014-02-10 02:10:30 +01:00
if ( performance )
memdelete ( performance ) ;
if ( input_map )
memdelete ( input_map ) ;
if ( translation_server )
2017-03-05 16:44:50 +01:00
memdelete ( translation_server ) ;
2014-02-10 02:10:30 +01:00
if ( globals )
memdelete ( globals ) ;
2017-01-13 16:51:14 +01:00
if ( engine )
memdelete ( engine ) ;
2014-02-10 02:10:30 +01:00
if ( script_debugger )
memdelete ( script_debugger ) ;
if ( packed_data )
memdelete ( packed_data ) ;
if ( file_access_network_client )
memdelete ( file_access_network_client ) ;
2015-04-21 00:38:02 +02:00
2015-10-30 12:56:07 +01:00
unregister_core_driver_types ( ) ;
2014-02-10 02:10:30 +01:00
unregister_core_types ( ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > _cmdline . clear ( ) ;
if ( message_queue )
2017-03-05 16:44:50 +01:00
memdelete ( message_queue ) ;
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > finalize_core ( ) ;
2017-03-05 16:44:50 +01:00
locale = String ( ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return ERR_INVALID_PARAMETER ;
}
2017-08-22 17:21:41 +02:00
Error Main : : setup2 ( Thread : : ID p_main_tid_override ) {
2019-05-28 11:19:21 +02:00
// Print engine name and version
print_line ( String ( VERSION_NAME ) + " v " + get_full_version_string ( ) + " - " + String ( VERSION_WEBSITE ) ) ;
2017-08-22 17:21:41 +02:00
if ( p_main_tid_override ) {
Thread : : _main_thread_id = p_main_tid_override ;
}
2014-02-10 02:10:30 +01:00
2018-01-03 18:26:44 +01:00
Error err = OS : : get_singleton ( ) - > initialize ( video_mode , video_driver_idx , audio_driver_idx ) ;
if ( err ! = OK ) {
return err ;
}
2018-08-25 00:04:25 +02:00
2019-06-04 15:20:37 +02:00
print_line ( " " ) ; //add a blank line for readability
2015-08-31 04:36:46 +02:00
if ( init_use_custom_pos ) {
OS : : get_singleton ( ) - > set_window_position ( init_custom_pos ) ;
}
2015-12-12 16:06:53 +01:00
2017-10-07 15:51:17 +02:00
// right moment to create and initialize the audio server
2017-01-15 20:06:14 +01:00
2017-03-05 16:44:50 +01:00
audio_server = memnew ( AudioServer ) ;
2017-01-15 20:06:14 +01:00
audio_server - > init ( ) ;
2017-10-07 15:51:17 +02:00
// also init our arvr_server from here
arvr_server = memnew ( ARVRServer ) ;
2020-06-18 12:49:24 +02:00
// and finally setup this property under visual_server
VisualServer : : get_singleton ( ) - > set_render_loop_enabled ( ! disable_render_loop ) ;
2014-02-10 02:10:30 +01:00
register_core_singletons ( ) ;
MAIN_PRINT ( " Main: Setup Logo " ) ;
# ifdef JAVASCRIPT_ENABLED
2017-08-21 21:15:36 +02:00
bool show_logo = false ;
# else
bool show_logo = true ;
2014-02-10 02:10:30 +01:00
# endif
2017-03-05 16:44:50 +01:00
if ( init_screen ! = - 1 ) {
2015-06-14 03:12:53 +02:00
OS : : get_singleton ( ) - > set_current_screen ( init_screen ) ;
}
2015-12-12 16:06:53 +01:00
if ( init_windowed ) {
//do none..
} else if ( init_maximized ) {
2015-06-14 03:12:53 +02:00
OS : : get_singleton ( ) - > set_window_maximized ( true ) ;
2015-12-12 16:06:53 +01:00
} else if ( init_fullscreen ) {
OS : : get_singleton ( ) - > set_window_fullscreen ( true ) ;
2015-06-14 03:12:53 +02:00
}
2017-12-27 20:51:19 +01:00
if ( init_always_on_top ) {
OS : : get_singleton ( ) - > set_window_always_on_top ( true ) ;
}
2017-04-10 01:02:04 +02:00
register_server_types ( ) ;
2015-09-04 04:24:55 +02:00
MAIN_PRINT ( " Main: Load Remaps " ) ;
2017-07-18 02:05:38 +02:00
Color clear = GLOBAL_DEF ( " rendering/environment/default_clear_color " , Color ( 0.3 , 0.3 , 0.3 ) ) ;
2017-01-05 13:16:00 +01:00
VisualServer : : get_singleton ( ) - > set_default_clear_color ( clear ) ;
2014-02-10 02:10:30 +01:00
if ( show_logo ) { //boot logo!
2017-07-18 02:05:38 +02:00
String boot_logo_path = GLOBAL_DEF ( " application/boot_splash/image " , String ( ) ) ;
bool boot_logo_scale = GLOBAL_DEF ( " application/boot_splash/fullsize " , true ) ;
2019-06-13 22:37:19 +02:00
bool boot_logo_filter = GLOBAL_DEF ( " application/boot_splash/use_filter " , true ) ;
2017-07-19 22:00:46 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " application/boot_splash/image " , PropertyInfo ( Variant : : STRING , " application/boot_splash/image " , PROPERTY_HINT_FILE , " *.png " ) ) ;
2015-04-12 22:55:01 +02:00
2017-05-17 12:36:47 +02:00
Ref < Image > boot_logo ;
2015-04-12 22:55:01 +02:00
2015-09-04 04:24:55 +02:00
boot_logo_path = boot_logo_path . strip_edges ( ) ;
2018-08-24 09:35:07 +02:00
if ( boot_logo_path ! = String ( ) ) {
2017-05-17 12:36:47 +02:00
boot_logo . instance ( ) ;
2019-02-12 21:10:08 +01:00
Error load_err = ImageLoader : : load_image ( boot_logo_path , boot_logo ) ;
if ( load_err )
2019-09-25 10:28:50 +02:00
ERR_PRINTS ( " Non-existing or invalid boot splash at ' " + boot_logo_path + " '. Loading default splash. " ) ;
2015-04-12 22:55:01 +02:00
}
2014-02-10 02:10:30 +01:00
2018-09-14 21:00:24 +02:00
Color boot_bg_color = GLOBAL_DEF ( " application/boot_splash/bg_color " , boot_splash_bg_color ) ;
2017-05-17 12:36:47 +02:00
if ( boot_logo . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
OS : : get_singleton ( ) - > _msec_splash = OS : : get_singleton ( ) - > get_ticks_msec ( ) ;
2019-06-13 22:37:19 +02:00
VisualServer : : get_singleton ( ) - > set_boot_image ( boot_logo , boot_bg_color , boot_logo_scale , boot_logo_filter ) ;
2014-02-10 02:10:30 +01:00
} else {
# ifndef NO_DEFAULT_BOOT_LOGO
2015-11-23 00:38:12 +01:00
MAIN_PRINT ( " Main: Create bootsplash " ) ;
2017-12-16 20:11:13 +01:00
# if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
2018-02-19 13:31:06 +01:00
Ref < Image > splash = ( editor | | project_manager ) ? memnew ( Image ( boot_splash_editor_png ) ) : memnew ( Image ( boot_splash_png ) ) ;
2017-12-16 20:11:13 +01:00
# else
2017-05-17 12:36:47 +02:00
Ref < Image > splash = memnew ( Image ( boot_splash_png ) ) ;
2017-12-16 20:11:13 +01:00
# endif
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: ClearColor " ) ;
2018-09-14 21:00:24 +02:00
VisualServer : : get_singleton ( ) - > set_default_clear_color ( boot_bg_color ) ;
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: Image " ) ;
2018-09-14 21:00:24 +02:00
VisualServer : : get_singleton ( ) - > set_boot_image ( splash , boot_bg_color , false ) ;
2014-02-10 02:10:30 +01:00
# endif
}
2017-09-15 18:41:11 +02:00
# ifdef TOOLS_ENABLED
2017-05-17 12:36:47 +02:00
Ref < Image > icon = memnew ( Image ( app_icon_png ) ) ;
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_icon ( icon ) ;
2017-09-15 18:41:11 +02:00
# endif
2014-02-10 02:10:30 +01:00
}
2016-04-08 01:30:00 +02:00
MAIN_PRINT ( " Main: DCC " ) ;
2017-07-18 02:05:38 +02:00
VisualServer : : get_singleton ( ) - > set_default_clear_color ( GLOBAL_DEF ( " rendering/environment/default_clear_color " , Color ( 0.3 , 0.3 , 0.3 ) ) ) ;
2016-04-08 01:30:00 +02:00
MAIN_PRINT ( " Main: END " ) ;
2017-07-18 02:05:38 +02:00
GLOBAL_DEF ( " application/config/icon " , String ( ) ) ;
2020-11-06 23:05:29 +01:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " application/config/icon " ,
PropertyInfo ( Variant : : STRING , " application/config/icon " ,
PROPERTY_HINT_FILE , " *.png,*.webp,*.svg,*.svgz " ) ) ;
2014-02-10 02:10:30 +01:00
2019-05-17 15:43:56 +02:00
GLOBAL_DEF ( " application/config/macos_native_icon " , String ( ) ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " application/config/macos_native_icon " , PropertyInfo ( Variant : : STRING , " application/config/macos_native_icon " , PROPERTY_HINT_FILE , " *.icns " ) ) ;
GLOBAL_DEF ( " application/config/windows_native_icon " , String ( ) ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " application/config/windows_native_icon " , PropertyInfo ( Variant : : STRING , " application/config/windows_native_icon " , PROPERTY_HINT_FILE , " *.ico " ) ) ;
2018-02-24 03:04:30 +01:00
InputDefault * id = Object : : cast_to < InputDefault > ( Input : : get_singleton ( ) ) ;
if ( id ) {
2018-05-10 07:26:28 +02:00
if ( bool ( GLOBAL_DEF ( " input_devices/pointing/emulate_touch_from_mouse " , false ) ) & & ! ( editor | | project_manager ) ) {
2018-02-24 03:04:30 +01:00
if ( ! OS : : get_singleton ( ) - > has_touchscreen_ui_hint ( ) ) {
//only if no touchscreen ui hint, set emulation
id - > set_emulate_touch_from_mouse ( true ) ;
}
2015-08-29 22:16:11 +02:00
}
2018-02-24 03:04:30 +01:00
2018-05-10 07:26:28 +02:00
id - > set_emulate_mouse_from_touch ( bool ( GLOBAL_DEF ( " input_devices/pointing/emulate_mouse_from_touch " , true ) ) ) ;
2015-08-29 22:16:11 +02:00
}
2015-09-24 23:06:15 +02:00
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: Load Remaps " ) ;
MAIN_PRINT ( " Main: Load Scene Types " ) ;
register_scene_types ( ) ;
2017-03-05 16:44:50 +01:00
GLOBAL_DEF ( " display/mouse_cursor/custom_image " , String ( ) ) ;
GLOBAL_DEF ( " display/mouse_cursor/custom_image_hotspot " , Vector2 ( ) ) ;
2019-03-02 12:11:42 +01:00
GLOBAL_DEF ( " display/mouse_cursor/tooltip_position_offset " , Point2 ( 10 , 10 ) ) ;
2017-07-19 22:00:46 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " display/mouse_cursor/custom_image " , PropertyInfo ( Variant : : STRING , " display/mouse_cursor/custom_image " , PROPERTY_HINT_FILE , " *.png,*.webp " ) ) ;
2015-09-24 23:06:15 +02:00
2017-07-19 22:00:46 +02:00
if ( String ( ProjectSettings : : get_singleton ( ) - > get ( " display/mouse_cursor/custom_image " ) ) ! = String ( ) ) {
2015-09-24 23:06:15 +02:00
2017-07-19 22:00:46 +02:00
Ref < Texture > cursor = ResourceLoader : : load ( ProjectSettings : : get_singleton ( ) - > get ( " display/mouse_cursor/custom_image " ) ) ;
2015-09-24 23:06:15 +02:00
if ( cursor . is_valid ( ) ) {
2017-07-19 22:00:46 +02:00
Vector2 hotspot = ProjectSettings : : get_singleton ( ) - > get ( " display/mouse_cursor/custom_image_hotspot " ) ;
2017-11-10 11:50:11 +01:00
Input : : get_singleton ( ) - > set_custom_mouse_cursor ( cursor , Input : : CURSOR_ARROW , hotspot ) ;
2015-09-24 23:06:15 +02:00
}
}
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
2017-01-03 03:03:46 +01:00
ClassDB : : set_current_api ( ClassDB : : API_EDITOR ) ;
2014-02-10 02:10:30 +01:00
EditorNode : : register_editor_types ( ) ;
2016-10-01 22:04:10 +02:00
2017-01-03 03:03:46 +01:00
ClassDB : : set_current_api ( ClassDB : : API_CORE ) ;
2016-09-15 00:37:37 +02:00
2014-02-10 02:10:30 +01:00
# endif
2017-10-21 13:02:06 +02:00
MAIN_PRINT ( " Main: Load Modules, Physics, Drivers, Scripts " ) ;
2014-02-10 02:10:30 +01:00
2017-11-16 01:33:48 +01:00
register_platform_apis ( ) ;
2014-02-10 02:10:30 +01:00
register_module_types ( ) ;
2017-10-21 13:02:06 +02:00
2019-11-29 07:54:39 +01:00
camera_server = CameraServer : : create ( ) ;
2017-10-21 13:02:06 +02:00
initialize_physics ( ) ;
register_server_singletons ( ) ;
2014-02-10 02:10:30 +01:00
register_driver_types ( ) ;
2018-06-11 02:59:53 +02:00
// This loads global classes, so it must happen before custom loaders and savers are registered
2014-11-13 04:53:12 +01:00
ScriptServer : : init_languages ( ) ;
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: Load Translations " ) ;
translation_server - > setup ( ) ; //register translations, load them, etc.
2017-03-05 16:44:50 +01:00
if ( locale ! = " " ) {
2014-02-10 02:10:30 +01:00
translation_server - > set_locale ( locale ) ;
}
translation_server - > load_translations ( ) ;
2017-06-28 22:00:18 +02:00
ResourceLoader : : load_translation_remaps ( ) ; //load remaps for resources
2014-02-10 02:10:30 +01:00
2017-12-14 19:33:54 +01:00
ResourceLoader : : load_path_remaps ( ) ;
2017-01-25 18:30:40 +01:00
audio_server - > load_default_bus_layout ( ) ;
2014-02-10 02:10:30 +01:00
2016-05-22 02:18:16 +02:00
if ( use_debug_profiler & & script_debugger ) {
script_debugger - > profiling_start ( ) ;
}
2017-03-05 16:44:50 +01:00
_start_success = true ;
locale = String ( ) ;
2014-02-10 02:10:30 +01:00
2017-01-03 03:03:46 +01:00
ClassDB : : set_current_api ( ClassDB : : API_NONE ) ; //no more api is registered at this point
2016-09-15 00:37:37 +02:00
2019-11-01 16:16:31 +01:00
print_verbose ( " CORE API HASH: " + uitos ( ClassDB : : get_api_hash ( ClassDB : : API_CORE ) ) ) ;
print_verbose ( " EDITOR API HASH: " + uitos ( ClassDB : : get_api_hash ( ClassDB : : API_EDITOR ) ) ) ;
2014-02-10 02:10:30 +01:00
MAIN_PRINT ( " Main: Done " ) ;
return OK ;
}
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
// everything the main loop needs to know about frame timings
2018-05-15 22:12:35 +02:00
static MainTimerSync main_timer_sync ;
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
2014-02-10 02:10:30 +01:00
bool Main : : start ( ) {
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND_V ( ! _start_success , false ) ;
2014-02-10 02:10:30 +01:00
2017-09-15 18:41:11 +02:00
bool hasicon = false ;
2014-02-10 02:10:30 +01:00
String doc_tool ;
2016-12-16 12:12:22 +01:00
List < String > removal_docs ;
2019-10-29 01:42:57 +01:00
String positional_arg ;
2014-02-10 02:10:30 +01:00
String game_path ;
String script ;
String test ;
2020-01-08 14:22:50 +01:00
bool check_only = false ;
# ifdef TOOLS_ENABLED
bool doc_base = true ;
2017-08-14 15:15:06 +02:00
String _export_preset ;
2017-03-05 16:44:50 +01:00
bool export_debug = false ;
2020-01-08 14:22:50 +01:00
bool export_pack_only = false ;
# endif
2017-08-19 16:45:03 +02:00
2018-05-15 22:12:35 +02:00
main_timer_sync . init ( OS : : get_singleton ( ) - > get_ticks_usec ( ) ) ;
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
2014-02-10 02:10:30 +01:00
List < String > args = OS : : get_singleton ( ) - > get_cmdline_args ( ) ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < args . size ( ) ; i + + ) {
2015-11-01 17:50:44 +01:00
//parameters that do not have an argument to the right
2019-02-18 20:28:40 +01:00
if ( args [ i ] = = " --check-only " ) {
check_only = true ;
2018-02-16 19:40:22 +01:00
# ifdef TOOLS_ENABLED
2019-02-18 20:28:40 +01:00
} else if ( args [ i ] = = " --no-docbase " ) {
doc_base = false ;
2017-08-19 16:45:03 +02:00
} else if ( args [ i ] = = " -e " | | args [ i ] = = " --editor " ) {
2017-03-05 16:44:50 +01:00
editor = true ;
2017-08-19 16:45:03 +02:00
} else if ( args [ i ] = = " -p " | | args [ i ] = = " --project-manager " ) {
2018-02-13 18:56:38 +01:00
project_manager = true ;
2018-02-16 19:40:22 +01:00
# endif
2019-10-29 01:42:57 +01:00
} else if ( args [ i ] . length ( ) & & args [ i ] [ 0 ] ! = ' - ' & & positional_arg = = " " ) {
positional_arg = args [ i ] ;
2020-05-06 19:59:29 +02:00
if ( args [ i ] . ends_with ( " .scn " ) | |
args [ i ] . ends_with ( " .tscn " ) | |
args [ i ] . ends_with ( " .escn " ) | |
args [ i ] . ends_with ( " .res " ) | |
args [ i ] . ends_with ( " .tres " ) ) {
2019-10-29 01:42:57 +01:00
// Only consider the positional argument to be a scene path if it ends with
// a file extension associated with Godot scenes. This makes it possible
// for projects to parse command-line arguments for custom CLI arguments
// or other file extensions without trouble. This can be used to implement
// "drag-and-drop onto executable" logic, which can prove helpful
// for non-game applications.
game_path = args [ i ] ;
}
2015-11-01 17:50:44 +01:00
}
2015-09-16 22:51:19 +02:00
//parameters that have an argument to the right
2017-03-05 16:44:50 +01:00
else if ( i < ( args . size ( ) - 1 ) ) {
bool parsed_pair = true ;
2018-02-16 19:40:22 +01:00
if ( args [ i ] = = " -s " | | args [ i ] = = " --script " ) {
2017-03-05 16:44:50 +01:00
script = args [ i + 1 ] ;
2017-06-21 11:09:30 +02:00
} else if ( args [ i ] = = " --test " ) {
2017-03-05 16:44:50 +01:00
test = args [ i + 1 ] ;
2018-02-16 19:40:22 +01:00
# ifdef TOOLS_ENABLED
} else if ( args [ i ] = = " --doctool " ) {
doc_tool = args [ i + 1 ] ;
for ( int j = i + 2 ; j < args . size ( ) ; j + + )
removal_docs . push_back ( args [ j ] ) ;
2017-06-21 11:09:30 +02:00
} else if ( args [ i ] = = " --export " ) {
2017-03-05 16:44:50 +01:00
editor = true ; //needs editor
2019-06-28 14:34:09 +02:00
_export_preset = args [ i + 1 ] ;
2017-06-21 11:09:30 +02:00
} else if ( args [ i ] = = " --export-debug " ) {
2017-03-05 16:44:50 +01:00
editor = true ; //needs editor
2019-06-28 14:34:09 +02:00
_export_preset = args [ i + 1 ] ;
2017-03-05 16:44:50 +01:00
export_debug = true ;
2020-01-08 14:22:50 +01:00
} else if ( args [ i ] = = " --export-pack " ) {
editor = true ;
_export_preset = args [ i + 1 ] ;
export_pack_only = true ;
2018-02-16 19:40:22 +01:00
# endif
2015-11-01 17:50:44 +01:00
} else {
// The parameter does not match anything known, don't skip the next argument
2017-03-05 16:44:50 +01:00
parsed_pair = false ;
2015-11-01 17:50:44 +01:00
}
if ( parsed_pair ) {
i + + ;
2015-09-16 22:51:19 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
String main_loop_type ;
# ifdef TOOLS_ENABLED
2017-03-05 16:44:50 +01:00
if ( doc_tool ! = " " ) {
2014-02-10 02:10:30 +01:00
2019-06-01 15:42:22 +02:00
Engine : : get_singleton ( ) - > set_editor_hint ( true ) ; // Needed to instance editor-only classes for their default values
2017-09-12 22:42:36 +02:00
{
DirAccessRef da = DirAccess : : open ( doc_tool ) ;
2020-03-07 15:40:59 +01:00
ERR_FAIL_COND_V_MSG ( ! da , false , " Argument supplied to --doctool must be a valid directory path. " ) ;
2017-09-12 22:42:36 +02:00
}
2014-02-10 02:10:30 +01:00
DocData doc ;
doc . generate ( doc_base ) ;
DocData docsrc ;
2017-09-13 09:13:23 +02:00
Map < String , String > doc_data_classes ;
2017-09-12 22:42:36 +02:00
Set < String > checked_paths ;
2018-04-22 19:36:01 +02:00
print_line ( " Loading docs... " ) ;
2017-09-12 22:42:36 +02:00
2017-09-13 09:13:23 +02:00
for ( int i = 0 ; i < _doc_data_class_path_count ; i + + ) {
2020-04-04 13:46:15 +02:00
// Custom modules are always located by absolute path.
String path = _doc_data_class_paths [ i ] . path ;
if ( path . is_rel_path ( ) ) {
path = doc_tool . plus_file ( path ) ;
}
2017-09-12 22:42:36 +02:00
String name = _doc_data_class_paths [ i ] . name ;
2017-09-13 09:13:23 +02:00
doc_data_classes [ name ] = path ;
2017-09-12 22:42:36 +02:00
if ( ! checked_paths . has ( path ) ) {
checked_paths . insert ( path ) ;
2019-06-08 21:13:16 +02:00
// Create the module documentation directory if it doesn't exist
DirAccess * da = DirAccess : : create_for_path ( path ) ;
da - > make_dir_recursive ( path ) ;
memdelete ( da ) ;
2017-09-12 22:42:36 +02:00
docsrc . load_classes ( path ) ;
2017-09-13 09:13:23 +02:00
print_line ( " Loading docs from: " + path ) ;
2017-09-12 22:42:36 +02:00
}
2014-02-10 02:10:30 +01:00
}
2017-09-12 22:42:36 +02:00
String index_path = doc_tool . plus_file ( " doc/classes " ) ;
2019-06-08 21:13:16 +02:00
// Create the main documentation directory if it doesn't exist
DirAccess * da = DirAccess : : create_for_path ( index_path ) ;
da - > make_dir_recursive ( index_path ) ;
memdelete ( da ) ;
2017-09-12 22:42:36 +02:00
docsrc . load_classes ( index_path ) ;
checked_paths . insert ( index_path ) ;
2017-09-13 09:13:23 +02:00
print_line ( " Loading docs from: " + index_path ) ;
2017-09-12 22:42:36 +02:00
2018-04-22 19:36:01 +02:00
print_line ( " Merging docs... " ) ;
2017-09-12 22:42:36 +02:00
doc . merge_from ( docsrc ) ;
2017-09-13 09:13:23 +02:00
for ( Set < String > : : Element * E = checked_paths . front ( ) ; E ; E = E - > next ( ) ) {
print_line ( " Erasing old docs at: " + E - > get ( ) ) ;
2017-09-12 22:42:36 +02:00
DocData : : erase_classes ( E - > get ( ) ) ;
2016-12-16 12:12:22 +01:00
}
2018-04-22 19:36:01 +02:00
print_line ( " Generating new docs... " ) ;
2017-09-13 09:13:23 +02:00
doc . save_classes ( index_path , doc_data_classes ) ;
2014-02-10 02:10:30 +01:00
return false ;
}
2020-01-08 14:22:50 +01:00
# endif
2015-11-26 21:59:25 +01:00
2017-07-18 02:05:38 +02:00
if ( script = = " " & & game_path = = " " & & String ( GLOBAL_DEF ( " application/run/main_scene " , " " ) ) ! = " " ) {
game_path = GLOBAL_DEF ( " application/run/main_scene " , " " ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
MainLoop * main_loop = NULL ;
2014-02-10 02:10:30 +01:00
if ( editor ) {
2014-11-06 01:20:42 +01:00
main_loop = memnew ( SceneTree ) ;
2014-02-10 02:10:30 +01:00
} ;
2017-03-05 16:44:50 +01:00
if ( test ! = " " ) {
2019-09-26 13:56:27 +02:00
# ifdef TOOLS_ENABLED
2017-03-05 16:44:50 +01:00
main_loop = test_main ( test , args ) ;
2014-02-10 02:10:30 +01:00
if ( ! main_loop )
return false ;
# endif
2017-03-05 16:44:50 +01:00
} else if ( script ! = " " ) {
2014-02-10 02:10:30 +01:00
Ref < Script > script_res = ResourceLoader : : load ( script ) ;
2019-08-08 22:08:27 +02:00
ERR_FAIL_COND_V_MSG ( script_res . is_null ( ) , false , " Can't load script: " + script ) ;
2016-03-09 00:00:52 +01:00
2018-05-31 00:23:23 +02:00
if ( check_only ) {
2019-11-25 22:39:51 +01:00
if ( ! script_res - > is_valid ( ) ) {
OS : : get_singleton ( ) - > set_exit_code ( 1 ) ;
}
2018-05-31 00:23:23 +02:00
return false ;
}
2020-03-06 22:57:02 +01:00
if ( script_res - > can_instance ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
StringName instance_type = script_res - > get_instance_base_type ( ) ;
2017-01-03 03:03:46 +01:00
Object * obj = ClassDB : : instance ( instance_type ) ;
2017-08-24 22:58:51 +02:00
MainLoop * script_loop = Object : : cast_to < MainLoop > ( obj ) ;
2014-02-10 02:10:30 +01:00
if ( ! script_loop ) {
if ( obj )
memdelete ( obj ) ;
2020-03-06 22:57:02 +01:00
ERR_FAIL_V_MSG ( false , vformat ( " Can't load the script \" %s \" as it doesn't inherit from SceneTree or MainLoop. " , script ) ) ;
2014-02-10 02:10:30 +01:00
}
script_loop - > set_init_script ( script_res ) ;
2017-03-05 16:44:50 +01:00
main_loop = script_loop ;
2014-02-10 02:10:30 +01:00
} else {
return false ;
}
} else {
2017-07-18 02:05:38 +02:00
main_loop_type = GLOBAL_DEF ( " application/run/main_loop_type " , " " ) ;
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( ! main_loop & & main_loop_type = = " " )
main_loop_type = " SceneTree " ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( ! main_loop ) {
2017-01-03 03:03:46 +01:00
if ( ! ClassDB : : class_exists ( main_loop_type ) ) {
2017-08-19 16:45:03 +02:00
OS : : get_singleton ( ) - > alert ( " Error: MainLoop type doesn't exist: " + main_loop_type ) ;
2014-02-10 02:10:30 +01:00
return false ;
} else {
2017-01-03 03:03:46 +01:00
Object * ml = ClassDB : : instance ( main_loop_type ) ;
2019-08-08 22:08:27 +02:00
ERR_FAIL_COND_V_MSG ( ! ml , false , " Can't instance MainLoop type. " ) ;
2014-02-10 02:10:30 +01:00
2017-08-24 22:58:51 +02:00
main_loop = Object : : cast_to < MainLoop > ( ml ) ;
2014-02-10 02:10:30 +01:00
if ( ! main_loop ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
memdelete ( ml ) ;
2019-08-08 22:08:27 +02:00
ERR_FAIL_V_MSG ( false , " Invalid MainLoop type. " ) ;
2014-02-10 02:10:30 +01:00
}
}
}
2017-01-03 03:03:46 +01:00
if ( main_loop - > is_class ( " SceneTree " ) ) {
2016-03-09 00:00:52 +01:00
2017-08-24 22:58:51 +02:00
SceneTree * sml = Object : : cast_to < SceneTree > ( main_loop ) ;
2014-02-10 02:10:30 +01:00
2017-04-07 16:17:16 +02:00
# ifdef DEBUG_ENABLED
2015-09-19 04:10:58 +02:00
if ( debug_collisions ) {
sml - > set_debug_collisions_hint ( true ) ;
}
2015-09-20 18:03:46 +02:00
if ( debug_navigation ) {
sml - > set_debug_navigation_hint ( true ) ;
}
2017-04-07 16:17:16 +02:00
# endif
2018-06-11 02:59:53 +02:00
ResourceLoader : : add_custom_loaders ( ) ;
ResourceSaver : : add_custom_savers ( ) ;
2018-05-22 18:26:13 +02:00
if ( ! project_manager & & ! editor ) { // game
2018-05-01 16:06:23 +02:00
if ( game_path ! = " " | | script ! = " " ) {
2019-04-06 22:55:01 +02:00
if ( script_debugger & & script_debugger - > is_remote ( ) ) {
ScriptDebuggerRemote * remote_debugger = static_cast < ScriptDebuggerRemote * > ( script_debugger ) ;
remote_debugger - > set_scene_tree ( sml ) ;
}
2018-05-01 16:06:23 +02:00
//autoload
List < PropertyInfo > props ;
ProjectSettings : : get_singleton ( ) - > get_property_list ( & props ) ;
//first pass, add the constants so they exist before any script is loaded
for ( List < PropertyInfo > : : Element * E = props . front ( ) ; E ; E = E - > next ( ) ) {
String s = E - > get ( ) . name ;
if ( ! s . begins_with ( " autoload/ " ) )
continue ;
String name = s . get_slicec ( ' / ' , 1 ) ;
String path = ProjectSettings : : get_singleton ( ) - > get ( s ) ;
bool global_var = false ;
if ( path . begins_with ( " * " ) ) {
global_var = true ;
}
if ( global_var ) {
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
ScriptServer : : get_language ( i ) - > add_global_constant ( name , Variant ( ) ) ;
}
}
}
//second pass, load into global constants
List < Node * > to_add ;
for ( List < PropertyInfo > : : Element * E = props . front ( ) ; E ; E = E - > next ( ) ) {
String s = E - > get ( ) . name ;
if ( ! s . begins_with ( " autoload/ " ) )
continue ;
String name = s . get_slicec ( ' / ' , 1 ) ;
String path = ProjectSettings : : get_singleton ( ) - > get ( s ) ;
bool global_var = false ;
if ( path . begins_with ( " * " ) ) {
global_var = true ;
path = path . substr ( 1 , path . length ( ) - 1 ) ;
}
RES res = ResourceLoader : : load ( path ) ;
2019-08-08 22:08:27 +02:00
ERR_CONTINUE_MSG ( res . is_null ( ) , " Can't autoload: " + path ) ;
2018-05-01 16:06:23 +02:00
Node * n = NULL ;
if ( res - > is_class ( " PackedScene " ) ) {
Ref < PackedScene > ps = res ;
n = ps - > instance ( ) ;
} else if ( res - > is_class ( " Script " ) ) {
2019-02-12 21:10:08 +01:00
Ref < Script > script_res = res ;
StringName ibt = script_res - > get_instance_base_type ( ) ;
2018-05-01 16:06:23 +02:00
bool valid_type = ClassDB : : is_parent_class ( ibt , " Node " ) ;
2019-08-08 22:08:27 +02:00
ERR_CONTINUE_MSG ( ! valid_type , " Script does not inherit a Node: " + path ) ;
2018-05-01 16:06:23 +02:00
Object * obj = ClassDB : : instance ( ibt ) ;
2019-08-08 22:08:27 +02:00
ERR_CONTINUE_MSG ( obj = = NULL , " Cannot instance script for autoload, expected 'Node' inheritance, got: " + String ( ibt ) ) ;
2018-05-01 16:06:23 +02:00
n = Object : : cast_to < Node > ( obj ) ;
2019-02-12 21:10:08 +01:00
n - > set_script ( script_res . get_ref_ptr ( ) ) ;
2018-05-01 16:06:23 +02:00
}
2019-08-08 22:08:27 +02:00
ERR_CONTINUE_MSG ( ! n , " Path in autoload not a node or script: " + path ) ;
2018-05-01 16:06:23 +02:00
n - > set_name ( name ) ;
//defer so references are all valid on _ready()
to_add . push_back ( n ) ;
if ( global_var ) {
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
ScriptServer : : get_language ( i ) - > add_global_constant ( name , n ) ;
}
}
}
for ( List < Node * > : : Element * E = to_add . front ( ) ; E ; E = E - > next ( ) ) {
sml - > get_root ( ) - > add_child ( E - > get ( ) ) ;
}
}
}
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
2017-03-05 16:44:50 +01:00
EditorNode * editor_node = NULL ;
2014-02-10 02:10:30 +01:00
if ( editor ) {
2017-03-05 16:44:50 +01:00
editor_node = memnew ( EditorNode ) ;
2014-02-10 02:10:30 +01:00
sml - > get_root ( ) - > add_child ( editor_node ) ;
2017-08-14 15:15:06 +02:00
if ( _export_preset ! = " " ) {
2019-10-29 01:42:57 +01:00
editor_node - > export_preset ( _export_preset , positional_arg , export_debug , export_pack_only ) ;
2020-01-07 13:29:02 +01:00
game_path = " " ; // Do not load anything.
2014-02-10 02:10:30 +01:00
}
}
# endif
2018-02-19 13:31:06 +01:00
if ( ! editor & & ! project_manager ) {
2014-02-10 02:10:30 +01:00
//standard helpers that can be changed from main config
2017-07-18 02:05:38 +02:00
String stretch_mode = GLOBAL_DEF ( " display/window/stretch/mode " , " disabled " ) ;
String stretch_aspect = GLOBAL_DEF ( " display/window/stretch/aspect " , " ignore " ) ;
Size2i stretch_size = Size2 ( GLOBAL_DEF ( " display/window/size/width " , 0 ) , GLOBAL_DEF ( " display/window/size/height " , 0 ) ) ;
2019-02-25 16:53:33 +01:00
real_t stretch_shrink = GLOBAL_DEF ( " display/window/stretch/shrink " , 1.0 ) ;
2014-04-15 03:43:44 +02:00
2017-03-05 16:44:50 +01:00
SceneTree : : StretchMode sml_sm = SceneTree : : STRETCH_MODE_DISABLED ;
if ( stretch_mode = = " 2d " )
sml_sm = SceneTree : : STRETCH_MODE_2D ;
else if ( stretch_mode = = " viewport " )
sml_sm = SceneTree : : STRETCH_MODE_VIEWPORT ;
2014-04-15 03:43:44 +02:00
2017-03-05 16:44:50 +01:00
SceneTree : : StretchAspect sml_aspect = SceneTree : : STRETCH_ASPECT_IGNORE ;
if ( stretch_aspect = = " keep " )
sml_aspect = SceneTree : : STRETCH_ASPECT_KEEP ;
else if ( stretch_aspect = = " keep_width " )
sml_aspect = SceneTree : : STRETCH_ASPECT_KEEP_WIDTH ;
else if ( stretch_aspect = = " keep_height " )
sml_aspect = SceneTree : : STRETCH_ASPECT_KEEP_HEIGHT ;
2017-08-09 09:53:38 +02:00
else if ( stretch_aspect = = " expand " )
sml_aspect = SceneTree : : STRETCH_ASPECT_EXPAND ;
2014-04-15 03:43:44 +02:00
2017-07-22 19:07:38 +02:00
sml - > set_screen_stretch ( sml_sm , sml_aspect , stretch_size , stretch_shrink ) ;
2014-02-10 02:10:30 +01:00
2017-07-18 02:05:38 +02:00
sml - > set_auto_accept_quit ( GLOBAL_DEF ( " application/config/auto_accept_quit " , true ) ) ;
sml - > set_quit_on_go_back ( GLOBAL_DEF ( " application/config/quit_on_go_back " , true ) ) ;
2017-07-19 22:00:46 +02:00
String appname = ProjectSettings : : get_singleton ( ) - > get ( " application/config/name " ) ;
2014-02-10 02:10:30 +01:00
appname = TranslationServer : : get_singleton ( ) - > translate ( appname ) ;
2020-06-16 11:27:46 +02:00
# ifdef DEBUG_ENABLED
// Append a suffix to the window title to denote that the project is running
// from a debug build (including the editor). Since this results in lower performance,
// this should be clearly presented to the user.
OS : : get_singleton ( ) - > set_window_title ( vformat ( " %s (DEBUG) " , appname ) ) ;
# else
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_window_title ( appname ) ;
2020-06-16 11:27:46 +02:00
# endif
2014-02-10 02:10:30 +01:00
2017-07-18 02:05:38 +02:00
int shadow_atlas_size = GLOBAL_GET ( " rendering/quality/shadow_atlas/size " ) ;
int shadow_atlas_q0_subdiv = GLOBAL_GET ( " rendering/quality/shadow_atlas/quadrant_0_subdiv " ) ;
int shadow_atlas_q1_subdiv = GLOBAL_GET ( " rendering/quality/shadow_atlas/quadrant_1_subdiv " ) ;
int shadow_atlas_q2_subdiv = GLOBAL_GET ( " rendering/quality/shadow_atlas/quadrant_2_subdiv " ) ;
int shadow_atlas_q3_subdiv = GLOBAL_GET ( " rendering/quality/shadow_atlas/quadrant_3_subdiv " ) ;
2016-11-10 03:55:06 +01:00
sml - > get_root ( ) - > set_shadow_atlas_size ( shadow_atlas_size ) ;
2017-03-05 16:44:50 +01:00
sml - > get_root ( ) - > set_shadow_atlas_quadrant_subdiv ( 0 , Viewport : : ShadowAtlasQuadrantSubdiv ( shadow_atlas_q0_subdiv ) ) ;
sml - > get_root ( ) - > set_shadow_atlas_quadrant_subdiv ( 1 , Viewport : : ShadowAtlasQuadrantSubdiv ( shadow_atlas_q1_subdiv ) ) ;
sml - > get_root ( ) - > set_shadow_atlas_quadrant_subdiv ( 2 , Viewport : : ShadowAtlasQuadrantSubdiv ( shadow_atlas_q2_subdiv ) ) ;
sml - > get_root ( ) - > set_shadow_atlas_quadrant_subdiv ( 3 , Viewport : : ShadowAtlasQuadrantSubdiv ( shadow_atlas_q3_subdiv ) ) ;
2017-07-19 22:00:46 +02:00
Viewport : : Usage usage = Viewport : : Usage ( int ( GLOBAL_GET ( " rendering/quality/intended_usage/framebuffer_allocation " ) ) ) ;
sml - > get_root ( ) - > set_usage ( usage ) ;
2014-02-10 02:10:30 +01:00
2017-09-07 16:22:07 +02:00
bool snap_controls = GLOBAL_DEF ( " gui/common/snap_controls_to_pixels " , true ) ;
sml - > get_root ( ) - > set_snap_controls_to_pixels ( snap_controls ) ;
2018-04-19 01:25:25 +02:00
bool font_oversampling = GLOBAL_DEF ( " rendering/quality/dynamic_fonts/use_oversampling " , true ) ;
2017-12-19 22:48:30 +01:00
sml - > set_use_font_oversampling ( font_oversampling ) ;
2014-02-10 02:10:30 +01:00
} else {
2018-09-15 14:45:54 +02:00
2017-07-18 02:05:38 +02:00
GLOBAL_DEF ( " display/window/stretch/mode " , " disabled " ) ;
2017-07-19 22:00:46 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " display/window/stretch/mode " , PropertyInfo ( Variant : : STRING , " display/window/stretch/mode " , PROPERTY_HINT_ENUM , " disabled,2d,viewport " ) ) ;
2017-07-18 02:05:38 +02:00
GLOBAL_DEF ( " display/window/stretch/aspect " , " ignore " ) ;
2017-08-09 09:53:38 +02:00
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " display/window/stretch/aspect " , PropertyInfo ( Variant : : STRING , " display/window/stretch/aspect " , PROPERTY_HINT_ENUM , " ignore,keep,keep_width,keep_height,expand " ) ) ;
2019-02-25 16:53:33 +01:00
GLOBAL_DEF ( " display/window/stretch/shrink " , 1.0 ) ;
ProjectSettings : : get_singleton ( ) - > set_custom_property_info ( " display/window/stretch/shrink " , PropertyInfo ( Variant : : REAL , " display/window/stretch/shrink " , PROPERTY_HINT_RANGE , " 1.0,8.0,0.1 " ) ) ;
2017-07-18 02:05:38 +02:00
sml - > set_auto_accept_quit ( GLOBAL_DEF ( " application/config/auto_accept_quit " , true ) ) ;
sml - > set_quit_on_go_back ( GLOBAL_DEF ( " application/config/quit_on_go_back " , true ) ) ;
2017-09-07 16:22:07 +02:00
GLOBAL_DEF ( " gui/common/snap_controls_to_pixels " , true ) ;
2018-04-19 01:25:25 +02:00
GLOBAL_DEF ( " rendering/quality/dynamic_fonts/use_oversampling " , true ) ;
2014-02-10 02:10:30 +01:00
}
2016-09-06 18:45:35 +02:00
String local_game_path ;
2018-02-13 18:56:38 +01:00
if ( game_path ! = " " & & ! project_manager ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
local_game_path = game_path . replace ( " \\ " , " / " ) ;
2014-02-10 02:10:30 +01:00
if ( ! local_game_path . begins_with ( " res:// " ) ) {
2017-03-05 16:44:50 +01:00
bool absolute = ( local_game_path . size ( ) > 1 ) & & ( local_game_path [ 0 ] = = ' / ' | | local_game_path [ 1 ] = = ' : ' ) ;
2014-02-10 02:10:30 +01:00
if ( ! absolute ) {
2017-07-19 22:00:46 +02:00
if ( ProjectSettings : : get_singleton ( ) - > is_using_datapack ( ) ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
local_game_path = " res:// " + local_game_path ;
2014-02-10 02:10:30 +01:00
2014-02-19 15:57:14 +01:00
} else {
2017-03-05 16:44:50 +01:00
int sep = local_game_path . find_last ( " / " ) ;
2014-02-19 15:57:14 +01:00
2017-03-05 16:44:50 +01:00
if ( sep = = - 1 ) {
2014-02-19 15:57:14 +01:00
DirAccess * da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2019-06-16 14:31:57 +02:00
local_game_path = da - > get_current_dir ( ) . plus_file ( local_game_path ) ;
2017-03-05 16:44:50 +01:00
memdelete ( da ) ;
2014-02-19 15:57:14 +01:00
} else {
2017-03-05 16:44:50 +01:00
DirAccess * da = DirAccess : : open ( local_game_path . substr ( 0 , sep ) ) ;
2014-02-19 15:57:14 +01:00
if ( da ) {
2019-06-16 14:31:57 +02:00
local_game_path = da - > get_current_dir ( ) . plus_file ( local_game_path . substr ( sep + 1 , local_game_path . length ( ) ) ) ;
2014-02-19 15:57:14 +01:00
memdelete ( da ) ;
}
2014-02-10 02:10:30 +01:00
}
}
}
}
2017-07-19 22:00:46 +02:00
local_game_path = ProjectSettings : : get_singleton ( ) - > localize_path ( local_game_path ) ;
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
if ( editor ) {
2018-09-21 05:14:04 +02:00
if ( game_path ! = GLOBAL_GET ( " application/run/main_scene " ) | | ! editor_node - > has_scenes_in_session ( ) ) {
Error serr = editor_node - > load_scene ( local_game_path ) ;
if ( serr ! = OK )
ERR_PRINT ( " Failed to load scene " ) ;
}
2016-01-27 21:53:37 +01:00
OS : : get_singleton ( ) - > set_context ( OS : : CONTEXT_EDITOR ) ;
2016-09-06 18:45:35 +02:00
}
2014-02-10 02:10:30 +01:00
# endif
2018-10-05 22:18:10 +02:00
if ( ! editor ) {
OS : : get_singleton ( ) - > set_context ( OS : : CONTEXT_ENGINE ) ;
}
2016-09-06 18:45:35 +02:00
}
2014-02-10 02:10:30 +01:00
2018-02-19 13:31:06 +01:00
if ( ! project_manager & & ! editor ) { // game
2018-09-15 14:45:54 +02:00
2019-08-08 22:08:27 +02:00
// Load SSL Certificates from Project Settings (or builtin).
2019-07-19 15:29:57 +02:00
Crypto : : load_default_certificates ( GLOBAL_DEF ( " network/ssl/certificates " , " " ) ) ;
2018-09-15 14:45:54 +02:00
2017-03-05 16:44:50 +01:00
if ( game_path ! = " " ) {
Node * scene = NULL ;
2014-02-10 02:10:30 +01:00
Ref < PackedScene > scenedata = ResourceLoader : : load ( local_game_path ) ;
if ( scenedata . is_valid ( ) )
2017-03-05 16:44:50 +01:00
scene = scenedata - > instance ( ) ;
2014-02-10 02:10:30 +01:00
2019-08-08 22:08:27 +02:00
ERR_FAIL_COND_V_MSG ( ! scene , false , " Failed loading scene: " + local_game_path ) ;
2015-05-17 21:33:35 +02:00
sml - > add_current_scene ( scene ) ;
2014-02-10 02:10:30 +01:00
2019-05-17 15:43:56 +02:00
# ifdef OSX_ENABLED
String mac_iconpath = GLOBAL_DEF ( " application/config/macos_native_icon " , " Variant() " ) ;
if ( mac_iconpath ! = " " ) {
OS : : get_singleton ( ) - > set_native_icon ( mac_iconpath ) ;
hasicon = true ;
}
# endif
# ifdef WINDOWS_ENABLED
String win_iconpath = GLOBAL_DEF ( " application/config/windows_native_icon " , " Variant() " ) ;
if ( win_iconpath ! = " " ) {
OS : : get_singleton ( ) - > set_native_icon ( win_iconpath ) ;
hasicon = true ;
}
# endif
2017-07-18 02:05:38 +02:00
String iconpath = GLOBAL_DEF ( " application/config/icon " , " Variant() " ) ;
2019-05-17 15:43:56 +02:00
if ( ( iconpath ! = " " ) & & ( ! hasicon ) ) {
2017-05-17 12:36:47 +02:00
Ref < Image > icon ;
2017-08-11 19:13:17 +02:00
icon . instance ( ) ;
2018-09-30 17:21:07 +02:00
if ( ImageLoader : : load_image ( iconpath , icon ) = = OK ) {
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_icon ( icon ) ;
2017-09-15 18:41:11 +02:00
hasicon = true ;
}
2014-02-10 02:10:30 +01:00
}
}
}
# ifdef TOOLS_ENABLED
2018-02-13 18:56:38 +01:00
if ( project_manager | | ( script = = " " & & test = = " " & & game_path = = " " & & ! editor ) ) {
2014-02-10 02:10:30 +01:00
2018-09-10 14:53:31 +02:00
Engine : : get_singleton ( ) - > set_editor_hint ( true ) ;
2017-03-05 16:44:50 +01:00
ProjectManager * pmanager = memnew ( ProjectManager ) ;
ProgressDialog * progress_dialog = memnew ( ProgressDialog ) ;
2016-07-10 22:19:19 +02:00
pmanager - > add_child ( progress_dialog ) ;
2014-02-10 02:10:30 +01:00
sml - > get_root ( ) - > add_child ( pmanager ) ;
2016-01-27 21:53:37 +01:00
OS : : get_singleton ( ) - > set_context ( OS : : CONTEXT_PROJECTMAN ) ;
2018-12-18 14:17:43 +01:00
project_manager = true ;
2014-02-10 02:10:30 +01:00
}
2018-09-15 14:45:54 +02:00
if ( project_manager | | editor ) {
2019-08-08 22:08:27 +02:00
// Hide console window if requested (Windows-only).
2018-12-18 14:17:43 +01:00
bool hide_console = EditorSettings : : get_singleton ( ) - > get_setting ( " interface/editor/hide_console_window " ) ;
OS : : get_singleton ( ) - > set_console_visible ( ! hide_console ) ;
2019-07-19 15:29:57 +02:00
// Load SSL Certificates from Editor Settings (or builtin)
Crypto : : load_default_certificates ( EditorSettings : : get_singleton ( ) - > get_setting ( " network/ssl/editor_ssl_certificates " ) . operator String ( ) ) ;
}
2014-02-10 02:10:30 +01:00
# endif
}
2017-09-15 18:41:11 +02:00
if ( ! hasicon ) {
Ref < Image > icon = memnew ( Image ( app_icon_png ) ) ;
OS : : get_singleton ( ) - > set_icon ( icon ) ;
}
2017-03-05 16:44:50 +01:00
OS : : get_singleton ( ) - > set_main_loop ( main_loop ) ;
2014-02-10 02:10:30 +01:00
return true ;
}
2018-09-20 11:45:05 +02:00
/* Main iteration
*
* This is the iteration of the engine ' s game loop , advancing the state of physics ,
* rendering and audio .
* It ' s called directly by the platform ' s OS : : run method , where the loop is created
* and monitored .
*
* The OS implementation can impact its draw step with the Main : : force_redraw ( ) method .
*/
2017-03-05 16:44:50 +01:00
uint64_t Main : : last_ticks = 0 ;
2018-05-28 13:47:09 +02:00
uint32_t Main : : frames = 0 ;
2017-03-05 16:44:50 +01:00
uint32_t Main : : frame = 0 ;
2014-02-10 02:10:30 +01:00
bool Main : : force_redraw_requested = false ;
2019-01-24 17:09:05 +01:00
int Main : : iterating = 0 ;
2019-01-22 17:17:39 +01:00
bool Main : : is_iterating ( ) {
2019-01-24 17:09:05 +01:00
return iterating > 0 ;
2019-01-22 17:17:39 +01:00
}
2014-02-10 02:10:30 +01:00
2019-08-08 22:08:27 +02:00
// For performance metrics.
2017-09-30 16:19:07 +02:00
static uint64_t physics_process_max = 0 ;
2017-03-05 16:44:50 +01:00
static uint64_t idle_process_max = 0 ;
2014-02-10 02:10:30 +01:00
bool Main : : iteration ( ) {
2019-01-24 16:42:05 +01:00
//for now do not error on this
//ERR_FAIL_COND_V(iterating, false);
2019-01-22 17:17:39 +01:00
2019-01-24 17:09:05 +01:00
iterating + + ;
2019-01-22 17:17:39 +01:00
2017-03-05 16:44:50 +01:00
uint64_t ticks = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2017-07-15 06:23:10 +02:00
Engine : : get_singleton ( ) - > _frame_ticks = ticks ;
2018-05-15 22:12:35 +02:00
main_timer_sync . set_cpu_ticks_usec ( ticks ) ;
main_timer_sync . set_fixed_fps ( fixed_fps ) ;
2017-07-15 06:23:10 +02:00
2017-03-05 16:44:50 +01:00
uint64_t ticks_elapsed = ticks - last_ticks ;
2014-02-10 02:10:30 +01:00
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
int physics_fps = Engine : : get_singleton ( ) - > get_iterations_per_second ( ) ;
float frame_slice = 1.0 / physics_fps ;
2017-08-30 12:40:35 +02:00
2018-05-09 08:11:43 +02:00
float time_scale = Engine : : get_singleton ( ) - > get_time_scale ( ) ;
2018-05-15 22:12:35 +02:00
MainFrameTime advance = main_timer_sync . advance ( frame_slice , physics_fps ) ;
double step = advance . idle_step ;
2018-05-09 08:11:43 +02:00
double scaled_step = step * time_scale ;
2015-04-15 03:05:14 +02:00
2017-07-15 06:23:10 +02:00
Engine : : get_singleton ( ) - > _frame_step = step ;
2019-07-01 18:42:02 +02:00
Engine : : get_singleton ( ) - > _physics_interpolation_fraction = advance . interpolation_fraction ;
2017-07-15 06:23:10 +02:00
2017-09-30 16:19:07 +02:00
uint64_t physics_process_ticks = 0 ;
2017-03-05 16:44:50 +01:00
uint64_t idle_process_ticks = 0 ;
2016-05-22 02:18:16 +02:00
2017-03-05 16:44:50 +01:00
frame + = ticks_elapsed ;
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
last_ticks = ticks ;
2014-02-10 02:10:30 +01:00
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
static const int max_physics_steps = 8 ;
if ( fixed_fps = = - 1 & & advance . physics_steps > max_physics_steps ) {
step - = ( advance . physics_steps - max_physics_steps ) * frame_slice ;
advance . physics_steps = max_physics_steps ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
bool exit = false ;
2014-02-10 02:10:30 +01:00
2017-09-30 16:19:07 +02:00
Engine : : get_singleton ( ) - > _in_physics = true ;
2016-09-01 23:58:52 +02:00
Add hysteresis to physics timestep count per frame
Add new class _TimerSync to manage timestep calculations.
The new class handles the decisions about simulation progression
previously handled by main::iteration(). It is fed the current timer
ticks and determines how many physics updates are to be run and what
the delta argument to the _process() functions should be.
The new class tries to keep the number of physics updates per frame as
constant as possible from frame to frame. Ideally, it would be N steps
every render frame, but even with perfectly regular rendering, the
general case is that N or N+1 steps are required per frame, for some
fixed N. The best guess for N is stored in typical_physics_steps.
When determining the number of steps to take, no restrictions are
imposed between the choice of typical_physics_steps and
typical_physics_steps+1 steps. Should more or less steps than that be
required, the accumulated remaining time (as before, stored in
time_accum) needs to surpass its boundaries by some minimal threshold.
Once surpassed, typical_physics_steps is updated to allow the new step
count for future updates.
Care is taken that the modified calculation of the number of physics
steps is not observable from game code that only checks the delta
parameters to the _process and _physics_process functions; in addition
to modifying the number of steps, the _process argument is modified as
well to stay in expected bounds. Extra care is taken that the accumulated
steps still sum up to roughly the real elapsed time, up to a maximum
tolerated difference.
To allow the hysteresis code to work correctly on higher refresh
monitors, the number of typical physics steps is not only recorded and
kept consistent for single render frames, but for groups of them.
Currently, up to 12 frames are grouped that way.
The engine parameter physics_jitter_fix controls both the maximum
tolerated difference between wall clock time and summed up _process
arguments and the threshold for changing typical_physics_steps. It is
given in units of the real physics frame slice 1/physics_fps. Set
physics_jitter_fix to 0 to disable the effects of the new code here.
It starts to be effective against the random physics jitter at around
0.02 to 0.05. at values greater than 1 it starts having ill effects on
the engine's ability to react sensibly to dropped frames and framerate
changes.
2018-02-11 00:03:31 +01:00
for ( int iters = 0 ; iters < advance . physics_steps ; + + iters ) {
2014-02-10 02:10:30 +01:00
2017-10-21 16:28:08 +02:00
uint64_t physics_begin = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2014-02-10 02:10:30 +01:00
PhysicsServer : : get_singleton ( ) - > flush_queries ( ) ;
Physics2DServer : : get_singleton ( ) - > sync ( ) ;
Physics2DServer : : get_singleton ( ) - > flush_queries ( ) ;
2017-03-05 16:44:50 +01:00
if ( OS : : get_singleton ( ) - > get_main_loop ( ) - > iteration ( frame_slice * time_scale ) ) {
exit = true ;
2014-02-10 02:10:30 +01:00
break ;
}
message_queue - > flush ( ) ;
2017-03-05 16:44:50 +01:00
PhysicsServer : : get_singleton ( ) - > step ( frame_slice * time_scale ) ;
2015-05-26 06:05:08 +02:00
Physics2DServer : : get_singleton ( ) - > end_sync ( ) ;
2017-03-05 16:44:50 +01:00
Physics2DServer : : get_singleton ( ) - > step ( frame_slice * time_scale ) ;
2014-02-10 02:10:30 +01:00
message_queue - > flush ( ) ;
2017-10-21 16:28:08 +02:00
physics_process_ticks = MAX ( physics_process_ticks , OS : : get_singleton ( ) - > get_ticks_usec ( ) - physics_begin ) ; // keep the largest one for reference
physics_process_max = MAX ( OS : : get_singleton ( ) - > get_ticks_usec ( ) - physics_begin , physics_process_max ) ;
2017-09-30 16:19:07 +02:00
Engine : : get_singleton ( ) - > _physics_frames + + ;
2014-02-10 02:10:30 +01:00
}
2017-09-30 16:19:07 +02:00
Engine : : get_singleton ( ) - > _in_physics = false ;
2016-09-01 23:58:52 +02:00
2014-02-10 02:10:30 +01:00
uint64_t idle_begin = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2019-03-09 12:36:37 +01:00
if ( OS : : get_singleton ( ) - > get_main_loop ( ) - > idle ( step * time_scale ) ) {
exit = true ;
}
2014-02-10 02:10:30 +01:00
message_queue - > flush ( ) ;
2018-05-15 22:12:35 +02:00
VisualServer : : get_singleton ( ) - > sync ( ) ; //sync if still drawing from previous frames.
2015-06-07 03:06:58 +02:00
2020-06-18 12:49:24 +02:00
if ( OS : : get_singleton ( ) - > can_draw ( ) & & VisualServer : : get_singleton ( ) - > is_render_loop_enabled ( ) ) {
2014-02-10 02:10:30 +01:00
if ( ( ! force_redraw_requested ) & & OS : : get_singleton ( ) - > is_in_low_processor_usage_mode ( ) ) {
if ( VisualServer : : get_singleton ( ) - > has_changed ( ) ) {
2018-05-09 08:11:43 +02:00
VisualServer : : get_singleton ( ) - > draw ( true , scaled_step ) ; // flush visual commands
2017-01-13 16:51:14 +01:00
Engine : : get_singleton ( ) - > frames_drawn + + ;
2014-02-10 02:10:30 +01:00
}
} else {
2018-05-09 08:11:43 +02:00
VisualServer : : get_singleton ( ) - > draw ( true , scaled_step ) ; // flush visual commands
2017-01-13 16:51:14 +01:00
Engine : : get_singleton ( ) - > frames_drawn + + ;
2014-02-10 02:10:30 +01:00
force_redraw_requested = false ;
}
}
2017-03-05 16:44:50 +01:00
idle_process_ticks = OS : : get_singleton ( ) - > get_ticks_usec ( ) - idle_begin ;
idle_process_max = MAX ( idle_process_ticks , idle_process_max ) ;
2016-05-22 02:18:16 +02:00
uint64_t frame_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) - ticks ;
2017-03-05 16:44:50 +01:00
for ( int i = 0 ; i < ScriptServer : : get_language_count ( ) ; i + + ) {
2014-02-10 02:10:30 +01:00
ScriptServer : : get_language ( i ) - > frame ( ) ;
}
2018-06-21 02:02:02 +02:00
AudioServer : : get_singleton ( ) - > update ( ) ;
2016-05-22 02:18:16 +02:00
if ( script_debugger ) {
if ( script_debugger - > is_profiling ( ) ) {
2017-09-30 16:19:07 +02:00
script_debugger - > profiling_set_frame_times ( USEC_TO_SEC ( frame_time ) , USEC_TO_SEC ( idle_process_ticks ) , USEC_TO_SEC ( physics_process_ticks ) , frame_slice ) ;
2016-05-22 02:18:16 +02:00
}
2014-02-10 02:10:30 +01:00
script_debugger - > idle_poll ( ) ;
2016-05-22 02:18:16 +02:00
}
2014-02-10 02:10:30 +01:00
2018-05-28 13:47:09 +02:00
frames + + ;
2017-01-13 16:51:14 +01:00
Engine : : get_singleton ( ) - > _idle_frames + + ;
2014-02-10 02:10:30 +01:00
2018-05-28 13:47:09 +02:00
if ( frame > 1000000 ) {
2014-02-10 02:10:30 +01:00
2018-03-21 08:46:05 +01:00
if ( editor | | project_manager ) {
if ( print_fps ) {
print_line ( " Editor FPS: " + itos ( frames ) ) ;
}
} else if ( GLOBAL_GET ( " debug/settings/stdout/print_fps " ) | | print_fps ) {
print_line ( " Game FPS: " + itos ( frames ) ) ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Engine : : get_singleton ( ) - > _fps = frames ;
2016-05-22 02:18:16 +02:00
performance - > set_process_time ( USEC_TO_SEC ( idle_process_max ) ) ;
2017-09-30 16:19:07 +02:00
performance - > set_physics_process_time ( USEC_TO_SEC ( physics_process_max ) ) ;
2017-03-05 16:44:50 +01:00
idle_process_max = 0 ;
2017-09-30 16:19:07 +02:00
physics_process_max = 0 ;
2014-02-10 02:10:30 +01:00
2018-05-28 13:47:09 +02:00
frame % = 1000000 ;
frames = 0 ;
2014-02-10 02:10:30 +01:00
}
2019-01-24 17:09:05 +01:00
iterating - - ;
2019-01-22 17:17:39 +01:00
2017-08-30 12:40:35 +02:00
if ( fixed_fps ! = - 1 )
return exit ;
2020-06-29 20:46:21 +02:00
OS : : get_singleton ( ) - > add_frame_delay ( OS : : get_singleton ( ) - > can_draw ( ) ) ;
2014-02-19 16:35:39 +01:00
2018-02-14 16:23:04 +01:00
# ifdef TOOLS_ENABLED
if ( auto_build_solutions ) {
auto_build_solutions = false ;
2020-01-13 13:55:54 +01:00
// Only relevant when running the editor.
if ( ! editor ) {
ERR_FAIL_V_MSG ( true , " Command line option --build-solutions was passed, but no project is being edited. Aborting. " ) ;
}
2018-02-14 16:23:04 +01:00
if ( ! EditorNode : : get_singleton ( ) - > call_build ( ) ) {
2020-01-13 13:55:54 +01:00
ERR_FAIL_V_MSG ( true , " Command line option --build-solutions was passed, but the build callback failed. Aborting. " ) ;
2018-02-14 16:23:04 +01:00
}
}
# endif
return exit | | auto_quit ;
2014-02-10 02:10:30 +01:00
}
void Main : : force_redraw ( ) {
force_redraw_requested = true ;
2018-09-20 11:45:05 +02:00
}
/* Engine deinitialization
*
* Responsible for freeing all the memory allocated by previous setup steps ,
* so that the engine closes cleanly without leaking memory or crashing .
* The order matters as some of those steps are linked with each other .
*/
2014-02-10 02:10:30 +01:00
void Main : : cleanup ( ) {
ERR_FAIL_COND ( ! _start_success ) ;
2019-11-29 14:01:56 +01:00
if ( script_debugger ) {
// Flush any remaining messages
script_debugger - > idle_poll ( ) ;
}
2018-06-11 02:59:53 +02:00
ResourceLoader : : remove_custom_loaders ( ) ;
ResourceSaver : : remove_custom_savers ( ) ;
2020-06-24 16:57:37 +02:00
// Flush before uninitializing the scene, but delete the MessageQueue as late as possible.
2018-01-14 13:50:52 +01:00
message_queue - > flush ( ) ;
2016-05-22 02:18:16 +02:00
if ( script_debugger ) {
if ( use_debug_profiler ) {
script_debugger - > profiling_end ( ) ;
}
2014-02-10 02:10:30 +01:00
memdelete ( script_debugger ) ;
2016-05-22 02:18:16 +02:00
}
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > delete_main_loop ( ) ;
OS : : get_singleton ( ) - > _cmdline . clear ( ) ;
2017-03-05 16:44:50 +01:00
OS : : get_singleton ( ) - > _execpath = " " ;
OS : : get_singleton ( ) - > _local_clipboard = " " ;
2014-02-10 02:10:30 +01:00
2017-12-14 19:33:54 +01:00
ResourceLoader : : clear_translation_remaps ( ) ;
ResourceLoader : : clear_path_remaps ( ) ;
2017-07-22 21:11:04 +02:00
ScriptServer : : finish_languages ( ) ;
2017-01-15 20:06:14 +01:00
2020-01-13 21:46:41 +01:00
// Sync pending commands that may have been queued from a different thread during ScriptServer finalization
VisualServer : : get_singleton ( ) - > sync ( ) ;
2014-02-25 13:31:47 +01:00
# ifdef TOOLS_ENABLED
EditorNode : : unregister_editor_types ( ) ;
# endif
2017-10-07 15:51:17 +02:00
if ( arvr_server ) {
// cleanup now before we pull the rug from underneath...
memdelete ( arvr_server ) ;
}
2018-09-03 06:36:35 +02:00
ImageLoader : : cleanup ( ) ;
2016-03-09 00:00:52 +01:00
unregister_driver_types ( ) ;
2014-02-10 02:10:30 +01:00
unregister_module_types ( ) ;
2017-11-16 01:33:48 +01:00
unregister_platform_apis ( ) ;
2016-03-09 00:00:52 +01:00
unregister_scene_types ( ) ;
2014-02-10 02:10:30 +01:00
unregister_server_types ( ) ;
2018-01-11 11:01:35 +01:00
if ( audio_server ) {
audio_server - > finish ( ) ;
memdelete ( audio_server ) ;
}
2019-11-29 07:54:39 +01:00
if ( camera_server ) {
memdelete ( camera_server ) ;
}
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > finalize ( ) ;
2017-10-21 13:02:06 +02:00
finalize_physics ( ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( packed_data )
memdelete ( packed_data ) ;
if ( file_access_network_client )
memdelete ( file_access_network_client ) ;
if ( performance )
memdelete ( performance ) ;
if ( input_map )
memdelete ( input_map ) ;
if ( translation_server )
2017-03-05 16:44:50 +01:00
memdelete ( translation_server ) ;
2014-02-10 02:10:30 +01:00
if ( globals )
memdelete ( globals ) ;
2017-01-13 16:51:14 +01:00
if ( engine )
memdelete ( engine ) ;
2014-02-10 02:10:30 +01:00
2018-07-19 23:58:15 +02:00
if ( OS : : get_singleton ( ) - > is_restart_on_exit_set ( ) ) {
//attempt to restart with arguments
String exec = OS : : get_singleton ( ) - > get_executable_path ( ) ;
2018-07-20 08:37:10 +02:00
List < String > args = OS : : get_singleton ( ) - > get_restart_on_exit_arguments ( ) ;
2018-07-19 23:58:15 +02:00
OS : : ProcessID pid = 0 ;
OS : : get_singleton ( ) - > execute ( exec , args , false , & pid ) ;
OS : : get_singleton ( ) - > set_restart_on_exit ( false , List < String > ( ) ) ; //clear list (uses memory)
}
2020-06-24 16:57:37 +02:00
// Now should be safe to delete MessageQueue (famous last words).
message_queue - > flush ( ) ;
memdelete ( message_queue ) ;
2014-02-10 02:10:30 +01:00
unregister_core_driver_types ( ) ;
unregister_core_types ( ) ;
OS : : get_singleton ( ) - > finalize_core ( ) ;
}