diff options
Diffstat (limited to 'main')
-rw-r--r-- | main/main.cpp | 410 | ||||
-rw-r--r-- | main/main.h | 1 | ||||
-rw-r--r-- | main/main_timer_sync.cpp | 26 | ||||
-rw-r--r-- | main/main_timer_sync.h | 10 | ||||
-rw-r--r-- | main/performance.cpp | 92 | ||||
-rw-r--r-- | main/performance.h | 1 | ||||
-rw-r--r-- | main/tests/test_astar.cpp | 91 | ||||
-rw-r--r-- | main/tests/test_class_db.cpp | 882 | ||||
-rw-r--r-- | main/tests/test_class_db.h | 42 | ||||
-rw-r--r-- | main/tests/test_gdscript.cpp | 221 | ||||
-rw-r--r-- | main/tests/test_gui.cpp | 5 | ||||
-rw-r--r-- | main/tests/test_main.cpp | 32 | ||||
-rw-r--r-- | main/tests/test_math.cpp | 119 | ||||
-rw-r--r-- | main/tests/test_oa_hash_map.cpp | 152 | ||||
-rw-r--r-- | main/tests/test_ordered_hash_map.cpp | 14 | ||||
-rw-r--r-- | main/tests/test_physics_2d.cpp | 35 | ||||
-rw-r--r-- | main/tests/test_physics_3d.cpp | 28 | ||||
-rw-r--r-- | main/tests/test_render.cpp | 12 | ||||
-rw-r--r-- | main/tests/test_shader_lang.cpp | 110 | ||||
-rw-r--r-- | main/tests/test_string.cpp | 138 |
20 files changed, 1760 insertions, 661 deletions
diff --git a/main/main.cpp b/main/main.cpp index 89c8832731..94dd895a26 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -32,7 +32,7 @@ #include "core/crypto/crypto.h" #include "core/debugger/engine_debugger.h" -#include "core/input/input_filter.h" +#include "core/input/input.h" #include "core/input/input_map.h" #include "core/io/file_access_network.h" #include "core/io/file_access_pack.h" @@ -55,13 +55,13 @@ #include "main/splash.gen.h" #include "main/splash_editor.gen.h" #include "main/tests/test_main.h" +#include "modules/modules_enabled.gen.h" #include "modules/register_module_types.h" #include "platform/register_platform_apis.h" #include "scene/main/scene_tree.h" #include "scene/main/window.h" #include "scene/register_scene_types.h" #include "scene/resources/packed_scene.h" -#include "servers/arvr_server.h" #include "servers/audio_server.h" #include "servers/camera_server.h" #include "servers/display_server.h" @@ -72,6 +72,7 @@ #include "servers/register_server_types.h" #include "servers/rendering/rendering_server_raster.h" #include "servers/rendering/rendering_server_wrap_mt.h" +#include "servers/xr_server.h" #ifdef TOOLS_ENABLED #include "editor/doc_data.h" @@ -87,29 +88,29 @@ // Singletons // Initialized in setup() -static Engine *engine = NULL; -static ProjectSettings *globals = NULL; -static InputFilter *input = NULL; -static InputMap *input_map = NULL; -static TranslationServer *translation_server = NULL; -static Performance *performance = NULL; -static PackedData *packed_data = NULL; +static Engine *engine = nullptr; +static ProjectSettings *globals = nullptr; +static Input *input = nullptr; +static InputMap *input_map = nullptr; +static TranslationServer *translation_server = nullptr; +static Performance *performance = nullptr; +static PackedData *packed_data = nullptr; #ifdef MINIZIP_ENABLED -static ZipArchive *zip_packed_data = NULL; +static ZipArchive *zip_packed_data = nullptr; #endif -static FileAccessNetworkClient *file_access_network_client = NULL; -static MessageQueue *message_queue = NULL; +static FileAccessNetworkClient *file_access_network_client = nullptr; +static MessageQueue *message_queue = nullptr; // Initialized in setup2() -static AudioServer *audio_server = NULL; -static DisplayServer *display_server = NULL; -static RenderingServer *rendering_server = NULL; -static CameraServer *camera_server = NULL; -static ARVRServer *arvr_server = NULL; -static PhysicsServer3D *physics_server = NULL; -static PhysicsServer2D *physics_2d_server = NULL; -static NavigationServer3D *navigation_server = NULL; -static NavigationServer2D *navigation_2d_server = NULL; +static AudioServer *audio_server = nullptr; +static DisplayServer *display_server = nullptr; +static RenderingServer *rendering_server = nullptr; +static CameraServer *camera_server = nullptr; +static XRServer *xr_server = nullptr; +static PhysicsServer3D *physics_server = nullptr; +static PhysicsServer2D *physics_2d_server = nullptr; +static NavigationServer3D *navigation_server = nullptr; +static NavigationServer2D *navigation_2d_server = nullptr; // We error out if setup2() doesn't turn this true static bool _start_success = false; @@ -175,8 +176,9 @@ static String unescape_cmdline(const String &p_str) { static String get_full_version_string() { String hash = String(VERSION_HASH); - if (hash.length() != 0) + if (hash.length() != 0) { hash = "." + hash.left(9); + } return String(VERSION_FULL_BUILD) + hash; } @@ -203,7 +205,6 @@ void initialize_physics() { } void finalize_physics() { - physics_server->finish(); memdelete(physics_server); @@ -212,7 +213,6 @@ void finalize_physics() { } void finalize_display() { - rendering_server->finish(); memdelete(rendering_server); @@ -220,7 +220,7 @@ void finalize_display() { } void initialize_navigation_server() { - ERR_FAIL_COND(navigation_server != NULL); + ERR_FAIL_COND(navigation_server != nullptr); navigation_server = NavigationServer3DManager::new_default_server(); navigation_2d_server = memnew(NavigationServer2D); @@ -228,10 +228,10 @@ void initialize_navigation_server() { void finalize_navigation_server() { memdelete(navigation_server); - navigation_server = NULL; + navigation_server = nullptr; memdelete(navigation_2d_server); - navigation_2d_server = NULL; + navigation_2d_server = nullptr; } //#define DEBUG_INIT @@ -242,7 +242,6 @@ void finalize_navigation_server() { #endif void Main::print_help(const char *p_binary) { - print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); OS::get_singleton()->print("Free and open source software under the terms of the MIT license.\n"); OS::get_singleton()->print("(c) 2007-2020 Juan Linietsky, Ariel Manzur.\n"); @@ -313,6 +312,13 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print(" --enable-vsync-via-compositor When vsync is enabled, vsync via the OS' window compositor (Windows only).\n"); OS::get_singleton()->print(" --disable-vsync-via-compositor Disable vsync via the OS' window compositor (Windows only).\n"); OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n"); + OS::get_singleton()->print(" --tablet-driver Tablet input driver ("); + for (int i = 0; i < OS::get_singleton()->get_tablet_driver_count(); i++) { + if (i != 0) + OS::get_singleton()->print(", "); + OS::get_singleton()->print("'%s'", OS::get_singleton()->get_tablet_driver_name(i).utf8().get_data()); + } + OS::get_singleton()->print(") (Windows only).\n"); OS::get_singleton()->print("\n"); #endif @@ -321,7 +327,7 @@ void Main::print_help(const char *p_binary) { 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(" --gpu-abort Abort on GPU errors (usually validation layer errors), may help see the problem if your system freezes.\n"); - OS::get_singleton()->print(" --remote-debug <address> Remote debug (<host/IP>:<port> address).\n"); + OS::get_singleton()->print(" --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n"); #if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED) OS::get_singleton()->print(" --debug-collisions Show collision shapes when running the scene.\n"); OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n"); @@ -387,7 +393,6 @@ void Main::print_help(const char *p_binary) { */ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_phase) { - OS::get_singleton()->initialize(); engine = memnew(Engine); @@ -422,7 +427,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph List<String> main_args; for (int i = 0; i < argc; i++) { - args.push_back(String::utf8(argv[i])); } @@ -431,7 +435,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph I = args.front(); while (I) { - I->get() = unescape_cmdline(I->get().strip_edges()); I = I->next(); } @@ -440,6 +443,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph String display_driver = ""; String audio_driver = ""; + String tablet_driver = ""; String project_path = "."; bool upwards = false; String debug_uri = ""; @@ -461,8 +465,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph bool use_vsync = false; packed_data = PackedData::get_singleton(); - if (!packed_data) + if (!packed_data) { packed_data = memnew(PackedData); + } #ifdef MINIZIP_ENABLED @@ -478,6 +483,14 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph I = args.front(); while (I) { +#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 List<String>::Element *N = I->next(); @@ -487,7 +500,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph goto error; } else if (I->get() == "--version") { - print_line(get_full_version_string()); goto error; @@ -501,7 +513,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--audio-driver") { // audio driver if (I->next()) { - audio_driver = I->next()->get(); bool found = false; @@ -538,7 +549,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--display-driver") { // force video driver if (I->next()) { - display_driver = I->next()->get(); bool found = false; @@ -586,6 +596,26 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--gpu-abort") { // force windowed window Engine::singleton->abort_on_gpu_errors = true; + } 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; + } + } + + 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; + } } else if (I->get() == "--single-window") { // force single window single_window = true; @@ -595,7 +625,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--resolution") { // force resolution if (I->next()) { - String vm = I->next()->get(); if (vm.find("x") == -1) { // invalid parameter format @@ -608,7 +637,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph int h = vm.get_slice("x", 1).to_int(); if (w <= 0 || h <= 0) { - OS::get_singleton()->print("Invalid resolution '%s', width and height must be above 0.\n", vm.utf8().get_data()); goto error; } @@ -626,7 +654,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--position") { // set window position if (I->next()) { - String vm = I->next()->get(); if (vm.find(",") == -1) { // invalid parameter format @@ -654,11 +681,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->set_no_window_mode(true); } else if (I->get() == "--enable-vsync-via-compositor") { - window_vsync_via_compositor = true; saw_vsync_via_compositor_override = true; } else if (I->get() == "--disable-vsync-via-compositor") { - window_vsync_via_compositor = false; saw_vsync_via_compositor_override = true; #endif @@ -669,7 +694,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "-l" || I->get() == "--language") { // language if (I->next()) { - locale = I->next()->get(); N = I->next()->next(); } else { @@ -680,7 +704,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--remote-fs") { // remote filesystem if (I->next()) { - remotefs = I->next()->get(); N = I->next()->next(); } else { @@ -690,7 +713,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--remote-fs-password") { // remote filesystem password if (I->next()) { - remotefs_pass = I->next()->get(); N = I->next()->next(); } else { @@ -700,13 +722,13 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--render-thread") { // render thread mode if (I->next()) { - - if (I->next()->get() == "safe") + if (I->next()->get() == "safe") { rtm = OS::RENDER_THREAD_SAFE; - else if (I->next()->get() == "unsafe") + } else if (I->next()->get() == "unsafe") { rtm = OS::RENDER_THREAD_UNSAFE; - else if (I->next()->get() == "separate") + } else if (I->next()->get() == "separate") { rtm = OS::RENDER_SEPARATE_THREAD; + } N = I->next()->next(); } else { @@ -740,7 +762,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--path") { // set path of project to start or edit if (I->next()) { - String p = I->next()->get(); if (OS::get_singleton()->set_cwd(p) == OK) { //nothing @@ -760,9 +781,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph String path; String file = I->get(); int sep = MAX(file.find_last("/"), file.find_last("\\")); - if (sep == -1) + if (sep == -1) { path = "."; - else { + } else { path = file.substr(0, sep); } if (OS::get_singleton()->set_cwd(path) == OK) { @@ -776,7 +797,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "-b" || I->get() == "--breakpoints") { // add breakpoints if (I->next()) { - String bplist = I->next()->get(); breakpoints = bplist.split(","); N = I->next()->next(); @@ -788,7 +808,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--frame-delay") { // force frame delay if (I->next()) { - frame_delay = I->next()->get().to_int(); N = I->next()->next(); } else { @@ -799,7 +818,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--time-scale") { // force time scale if (I->next()) { - Engine::get_singleton()->set_time_scale(I->next()->get().to_double()); N = I->next()->next(); } else { @@ -808,9 +826,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } } else if (I->get() == "--main-pack") { - if (I->next()) { - main_pack = I->next()->get(); N = I->next()->next(); } else { @@ -828,13 +844,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph #endif } else if (I->get() == "--remote-debug") { if (I->next()) { - debug_uri = I->next()->get(); - if (debug_uri.find(":") == -1) { // wrong address - OS::get_singleton()->print("Invalid debug host address, it should be of the form <host/IP>:<port>.\n"); + if (debug_uri.find("://") == -1) { // wrong address + OS::get_singleton()->print("Invalid debug host address, it should be of the form <protocol>://<host/IP>:<port>.\n"); goto error; } - debug_uri = "tcp://" + debug_uri; // will support multiple protocols eventually. N = I->next()->next(); } else { OS::get_singleton()->print("Missing remote debug host address, aborting.\n"); @@ -842,7 +856,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } } else if (I->get() == "--allow_focus_steal_pid") { // not exposed to user if (I->next()) { - allow_focus_steal_pid = I->next()->get().to_int64(); N = I->next()->next(); } else { @@ -883,7 +896,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph // '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) { @@ -907,7 +919,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph found_project = true; #endif } else { - #ifdef TOOLS_ENABLED editor = false; #else @@ -992,8 +1003,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph _print_error_enabled = false; }; - if (quiet_stdout) + if (quiet_stdout) { _print_line_enabled = false; + } OS::get_singleton()->set_cmdline(execpath, main_args); @@ -1020,13 +1032,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph 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 if (use_custom_res) { - if (!force_res) { window_size.width = GLOBAL_GET("display/window/size/width"); window_size.height = GLOBAL_GET("display/window/size/height"); if (globals->has_setting("display/window/size/test_width") && globals->has_setting("display/window/size/test_height")) { - int tw = globals->get("display/window/size/test_width"); if (tw > 0) { window_size.width = tw; @@ -1070,6 +1080,21 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->_vsync_via_compositor = window_vsync_via_compositor; + if (tablet_driver == "") { // specified in project.godot + tablet_driver = GLOBAL_DEF_RST("display/window/tablet_driver", OS::get_singleton()->get_tablet_driver_name(0)); + } + + 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)); + } + /* todo restore 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); @@ -1099,9 +1124,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph /* Determine audio and video drivers */ for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { - if (display_driver == DisplayServer::get_create_function_name(i)) { - display_driver_idx = i; break; } @@ -1116,9 +1139,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) { - if (audio_driver == AudioDriverManager::get_driver(i)->get_name()) { - audio_driver_idx = i; break; } @@ -1131,20 +1152,21 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph { String orientation = GLOBAL_DEF("display/window/handheld/orientation", "landscape"); - if (orientation == "portrait") + if (orientation == "portrait") { window_orientation = DisplayServer::SCREEN_PORTRAIT; - else if (orientation == "reverse_landscape") + } else if (orientation == "reverse_landscape") { window_orientation = DisplayServer::SCREEN_REVERSE_LANDSCAPE; - else if (orientation == "reverse_portrait") + } else if (orientation == "reverse_portrait") { window_orientation = DisplayServer::SCREEN_REVERSE_PORTRAIT; - else if (orientation == "sensor_landscape") + } else if (orientation == "sensor_landscape") { window_orientation = DisplayServer::SCREEN_SENSOR_LANDSCAPE; - else if (orientation == "sensor_portrait") + } else if (orientation == "sensor_portrait") { window_orientation = DisplayServer::SCREEN_SENSOR_PORTRAIT; - else if (orientation == "sensor") + } else if (orientation == "sensor") { window_orientation = DisplayServer::SCREEN_SENSOR; - else + } else { window_orientation = DisplayServer::SCREEN_LANDSCAPE; + } } Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF("physics/common/physics_fps", 60)); @@ -1154,9 +1176,11 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph 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")); GLOBAL_DEF("debug/settings/stdout/print_fps", false); + GLOBAL_DEF("debug/settings/stdout/verbose_stdout", false); - if (!OS::get_singleton()->_verbose_stdout) //overridden - OS::get_singleton()->_verbose_stdout = GLOBAL_DEF("debug/settings/stdout/verbose_stdout", false); + if (!OS::get_singleton()->_verbose_stdout) { // Not manually overridden. + OS::get_singleton()->_verbose_stdout = GLOBAL_GET("debug/settings/stdout/verbose_stdout"); + } if (frame_delay == 0) { frame_delay = GLOBAL_DEF("application/run/frame_delay_msec", 0); @@ -1173,8 +1197,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph message_queue = memnew(MessageQueue); - if (p_second_phase) + if (p_second_phase) { return setup2(); + } return OK; @@ -1182,38 +1207,48 @@ error: display_driver = ""; audio_driver = ""; + tablet_driver = ""; project_path = ""; args.clear(); main_args.clear(); - if (show_help) + if (show_help) { print_help(execpath); + } EngineDebugger::deinitialize(); - if (performance) + if (performance) { memdelete(performance); - if (input_map) + } + if (input_map) { memdelete(input_map); - if (translation_server) + } + if (translation_server) { memdelete(translation_server); - if (globals) + } + if (globals) { memdelete(globals); - if (engine) + } + if (engine) { memdelete(engine); - if (packed_data) + } + if (packed_data) { memdelete(packed_data); - if (file_access_network_client) + } + if (file_access_network_client) { memdelete(file_access_network_client); + } unregister_core_driver_types(); unregister_core_types(); OS::get_singleton()->_cmdline.clear(); - if (message_queue) + if (message_queue) { memdelete(message_queue); + } OS::get_singleton()->finalize_core(); locale = String(); @@ -1221,7 +1256,6 @@ error: } Error Main::setup2(Thread::ID p_main_tid_override) { - preregister_module_types(); preregister_server_types(); @@ -1238,12 +1272,11 @@ Error Main::setup2(Thread::ID p_main_tid_override) { /* Initialize Input */ - input = memnew(InputFilter); + input = memnew(Input); /* Iniitalize Display Server */ { - String rendering_driver; // temp broken Error err; @@ -1297,8 +1330,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) { audio_server = memnew(AudioServer); audio_server->init(); - // also init our arvr_server from here - arvr_server = memnew(ARVRServer); + // also init our xr_server from here + xr_server = memnew(XRServer); register_core_singletons(); @@ -1348,8 +1381,9 @@ Error Main::setup2(Thread::ID p_main_tid_override) { if (boot_logo_path != String()) { boot_logo.instance(); Error load_err = ImageLoader::load_image(boot_logo_path, boot_logo); - if (load_err) + if (load_err) { ERR_PRINT("Non-existing or invalid boot splash at '" + boot_logo_path + "'. Loading default splash."); + } } Color boot_bg_color = GLOBAL_DEF("application/boot_splash/bg_color", boot_splash_bg_color); @@ -1392,10 +1426,9 @@ Error Main::setup2(Thread::ID p_main_tid_override) { 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")); - InputFilter *id = InputFilter::get_singleton(); + Input *id = Input::get_singleton(); if (id) { if (bool(GLOBAL_DEF("input_devices/pointing/emulate_touch_from_mouse", false)) && !(editor || project_manager)) { - bool found_touchscreen = false; for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) { if (DisplayServer::get_singleton()->screen_is_touchscreen(i)) { @@ -1423,11 +1456,10 @@ Error Main::setup2(Thread::ID p_main_tid_override) { 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")); if (String(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image")) != String()) { - Ref<Texture2D> cursor = ResourceLoader::load(ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image")); if (cursor.is_valid()) { Vector2 hotspot = ProjectSettings::get_singleton()->get("display/mouse_cursor/custom_image_hotspot"); - InputFilter::get_singleton()->set_custom_mouse_cursor(cursor, InputFilter::CURSOR_ARROW, hotspot); + Input::get_singleton()->set_custom_mouse_cursor(cursor, Input::CURSOR_ARROW, hotspot); } } #ifdef TOOLS_ENABLED @@ -1458,7 +1490,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) { translation_server->setup(); //register translations, load them, etc. if (locale != "") { - translation_server->set_locale(locale); } translation_server->load_translations(); @@ -1473,6 +1504,15 @@ Error Main::setup2(Thread::ID p_main_tid_override) { // We could add more, and make the CLI arg require a comma-separated list of profilers. EngineDebugger::get_singleton()->profiler_enable("scripts", true); } + + if (!project_manager) { + // If not running the project manager, and now that the engine is + // able to load resources, load the global shader variables. + // If running on editor, dont load the textures because the editor + // may want to import them first. Editor will reload those later. + rendering_server->global_variables_load_settings(!editor); + } + _start_success = true; locale = String(); @@ -1489,7 +1529,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) { static MainTimerSync main_timer_sync; bool Main::start() { - ERR_FAIL_COND_V(!_start_success, false); bool hasicon = false; @@ -1526,7 +1565,11 @@ bool Main::start() { } else if (args[i].length() && args[i][0] != '-' && positional_arg == "") { positional_arg = args[i]; - if (args[i].ends_with(".scn") || args[i].ends_with(".tscn") || args[i].ends_with(".escn")) { + 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")) { // 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 @@ -1546,8 +1589,9 @@ bool Main::start() { #ifdef TOOLS_ENABLED } else if (args[i] == "--doctool") { doc_tool = args[i + 1]; - for (int j = i + 2; j < args.size(); j++) + for (int j = i + 2; j < args.size(); j++) { removal_docs.push_back(args[j]); + } } else if (args[i] == "--export") { editor = true; //needs editor _export_preset = args[i + 1]; @@ -1573,13 +1617,25 @@ bool Main::start() { String main_loop_type; #ifdef TOOLS_ENABLED if (doc_tool != "") { - Engine::get_singleton()->set_editor_hint(true); // Needed to instance editor-only classes for their default values { DirAccessRef da = DirAccess::open(doc_tool); ERR_FAIL_COND_V_MSG(!da, false, "Argument supplied to --doctool must be a base Godot build directory."); } + +#ifndef MODULE_MONO_ENABLED + // Hack to define Mono-specific project settings even on non-Mono builds, + // so that we don't lose their descriptions and default values in DocData. + // Default values should be synced with mono_gd/gd_mono.cpp. + GLOBAL_DEF("mono/debugger_agent/port", 23685); + GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false); + GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000); + GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd"); + GLOBAL_DEF("mono/profiler/enabled", false); + GLOBAL_DEF("mono/unhandled_exception_policy", 0); +#endif + DocData doc; doc.generate(doc_base); @@ -1589,7 +1645,11 @@ bool Main::start() { print_line("Loading docs..."); for (int i = 0; i < _doc_data_class_path_count; i++) { - String path = doc_tool.plus_file(_doc_data_class_paths[i].path); + // 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); + } String name = _doc_data_class_paths[i].name; doc_data_classes[name] = path; if (!checked_paths.has(path)) { @@ -1642,7 +1702,7 @@ bool Main::start() { game_path = GLOBAL_DEF("application/run/main_scene", ""); } - MainLoop *main_loop = NULL; + MainLoop *main_loop = nullptr; if (editor) { main_loop = memnew(SceneTree); }; @@ -1651,12 +1711,12 @@ bool Main::start() { #ifdef TOOLS_ENABLED main_loop = test_main(test, args); - if (!main_loop) + if (!main_loop) { return false; + } #endif } else if (script != "") { - Ref<Script> script_res = ResourceLoader::load(script); ERR_FAIL_COND_V_MSG(script_res.is_null(), false, "Can't load script: " + script); @@ -1667,21 +1727,20 @@ bool Main::start() { return false; } - if (script_res->can_instance() /*&& script_res->inherits_from("SceneTreeScripted")*/) { - + if (script_res->can_instance()) { StringName instance_type = script_res->get_instance_base_type(); Object *obj = ClassDB::instance(instance_type); MainLoop *script_loop = Object::cast_to<MainLoop>(obj); if (!script_loop) { - if (obj) + if (obj) { memdelete(obj); - ERR_FAIL_V_MSG(false, "Can't load script '" + script + "', it does not inherit from a MainLoop type."); + } + ERR_FAIL_V_MSG(false, vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script)); } script_loop->set_init_script(script_res); main_loop = script_loop; } else { - return false; } @@ -1689,21 +1748,20 @@ bool Main::start() { main_loop_type = GLOBAL_DEF("application/run/main_loop_type", ""); } - if (!main_loop && main_loop_type == "") + if (!main_loop && main_loop_type == "") { main_loop_type = "SceneTree"; + } if (!main_loop) { if (!ClassDB::class_exists(main_loop_type)) { DisplayServer::get_singleton()->alert("Error: MainLoop type doesn't exist: " + main_loop_type); return false; } else { - Object *ml = ClassDB::instance(main_loop_type); ERR_FAIL_COND_V_MSG(!ml, false, "Can't instance MainLoop type."); main_loop = Object::cast_to<MainLoop>(ml); if (!main_loop) { - memdelete(ml); ERR_FAIL_V_MSG(false, "Invalid MainLoop type."); } @@ -1711,7 +1769,6 @@ bool Main::start() { } if (main_loop->is_class("SceneTree")) { - SceneTree *sml = Object::cast_to<SceneTree>(main_loop); #ifdef DEBUG_ENABLED @@ -1723,7 +1780,9 @@ bool Main::start() { } #endif - if (single_window) { + bool embed_subwindows = GLOBAL_DEF("display/window/subwindows/embed_subwindows", false); + + if (single_window || (!project_manager && !editor && embed_subwindows)) { sml->get_root()->set_embed_subwindows_hint(true); } ResourceLoader::add_custom_loaders(); @@ -1737,10 +1796,10 @@ bool Main::start() { //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/")) + if (!s.begins_with("autoload/")) { continue; + } String name = s.get_slicec('/', 1); String path = ProjectSettings::get_singleton()->get(s); bool global_var = false; @@ -1758,10 +1817,10 @@ bool Main::start() { //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/")) + if (!s.begins_with("autoload/")) { continue; + } String name = s.get_slicec('/', 1); String path = ProjectSettings::get_singleton()->get(s); bool global_var = false; @@ -1772,7 +1831,7 @@ bool Main::start() { RES res = ResourceLoader::load(path); ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + path); - Node *n = NULL; + Node *n = nullptr; if (res->is_class("PackedScene")) { Ref<PackedScene> ps = res; n = ps->instance(); @@ -1784,7 +1843,7 @@ bool Main::start() { Object *obj = ClassDB::instance(ibt); - ERR_CONTINUE_MSG(obj == NULL, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt)); + ERR_CONTINUE_MSG(obj == nullptr, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt)); n = Object::cast_to<Node>(obj); n->set_script(script_res); @@ -1804,14 +1863,13 @@ bool Main::start() { } for (List<Node *>::Element *E = to_add.front(); E; E = E->next()) { - sml->get_root()->add_child(E->get()); } } } #ifdef TOOLS_ENABLED - EditorNode *editor_node = NULL; + EditorNode *editor_node = nullptr; if (editor) { editor_node = memnew(EditorNode); sml->get_root()->add_child(editor_node); @@ -1824,7 +1882,6 @@ bool Main::start() { #endif { - int directional_atlas_size = GLOBAL_GET("rendering/quality/directional_shadow/size"); RenderingServer::get_singleton()->directional_shadow_atlas_set_size(directional_atlas_size); } @@ -1837,20 +1894,22 @@ bool Main::start() { Size2i stretch_size = Size2(GLOBAL_DEF("display/window/size/width", 0), GLOBAL_DEF("display/window/size/height", 0)); Window::ContentScaleMode cs_sm = Window::CONTENT_SCALE_MODE_DISABLED; - if (stretch_mode == "objects") + if (stretch_mode == "objects") { cs_sm = Window::CONTENT_SCALE_MODE_OBJECTS; - else if (stretch_mode == "pixels") + } else if (stretch_mode == "pixels") { cs_sm = Window::CONTENT_SCALE_MODE_PIXELS; + } Window::ContentScaleAspect cs_aspect = Window::CONTENT_SCALE_ASPECT_IGNORE; - if (stretch_aspect == "keep") + if (stretch_aspect == "keep") { cs_aspect = Window::CONTENT_SCALE_ASPECT_KEEP; - else if (stretch_aspect == "keep_width") + } else if (stretch_aspect == "keep_width") { cs_aspect = Window::CONTENT_SCALE_ASPECT_KEEP_WIDTH; - else if (stretch_aspect == "keep_height") + } else if (stretch_aspect == "keep_height") { cs_aspect = Window::CONTENT_SCALE_ASPECT_KEEP_HEIGHT; - else if (stretch_aspect == "expand") + } else if (stretch_aspect == "expand") { cs_aspect = Window::CONTENT_SCALE_ASPECT_EXPAND; + } sml->get_root()->set_content_scale_mode(cs_sm); sml->get_root()->set_content_scale_aspect(cs_aspect); @@ -1886,7 +1945,6 @@ bool Main::start() { sml->get_root()->set_default_canvas_item_texture_repeat(Viewport::DefaultCanvasItemTextureRepeat(texture_repeat)); } else { - GLOBAL_DEF("display/window/stretch/mode", "disabled"); ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/mode", PropertyInfo(Variant::STRING, "display/window/stretch/mode", PROPERTY_HINT_ENUM, "disabled,2d,viewport")); GLOBAL_DEF("display/window/stretch/aspect", "ignore"); @@ -1904,18 +1962,25 @@ bool Main::start() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/canvas_textures/default_texture_repeat", PropertyInfo(Variant::INT, "rendering/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror")); } +#ifdef TOOLS_ENABLED + if (editor) { + bool editor_embed_subwindows = EditorSettings::get_singleton()->get_setting("interface/editor/single_window_mode"); + + if (editor_embed_subwindows) { + sml->get_root()->set_embed_subwindows_hint(true); + } + } +#endif + String local_game_path; if (game_path != "" && !project_manager) { - local_game_path = game_path.replace("\\", "/"); if (!local_game_path.begins_with("res://")) { bool absolute = (local_game_path.size() > 1) && (local_game_path[0] == '/' || local_game_path[1] == ':'); if (!absolute) { - if (ProjectSettings::get_singleton()->is_using_datapack()) { - local_game_path = "res://" + local_game_path; } else { @@ -1926,7 +1991,6 @@ bool Main::start() { local_game_path = da->get_current_dir().plus_file(local_game_path); memdelete(da); } else { - DirAccess *da = DirAccess::open(local_game_path.substr(0, sep)); if (da) { local_game_path = da->get_current_dir().plus_file(local_game_path.substr(sep + 1, local_game_path.length())); @@ -1941,11 +2005,11 @@ bool Main::start() { #ifdef TOOLS_ENABLED if (editor) { - 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) + if (serr != OK) { ERR_PRINT("Failed to load scene"); + } } DisplayServer::get_singleton()->set_context(DisplayServer::CONTEXT_EDITOR); } @@ -1958,13 +2022,14 @@ bool Main::start() { if (!project_manager && !editor) { // game // Load SSL Certificates from Project Settings (or builtin). - Crypto::load_default_certificates(GLOBAL_DEF("network/ssl/certificates", "")); + Crypto::load_default_certificates(GLOBAL_DEF("network/ssl/certificate_bundle_override", "")); if (game_path != "") { - Node *scene = NULL; + Node *scene = nullptr; Ref<PackedScene> scenedata = ResourceLoader::load(local_game_path); - if (scenedata.is_valid()) + if (scenedata.is_valid()) { scene = scenedata->instance(); + } ERR_FAIL_COND_V_MSG(!scene, false, "Failed loading scene: " + local_game_path); sml->add_current_scene(scene); @@ -1999,7 +2064,6 @@ bool Main::start() { #ifdef TOOLS_ENABLED if (project_manager || (script == "" && test == "" && game_path == "" && !editor)) { - Engine::get_singleton()->set_editor_hint(true); ProjectManager *pmanager = memnew(ProjectManager); ProgressDialog *progress_dialog = memnew(ProgressDialog); @@ -2010,9 +2074,11 @@ bool Main::start() { } if (project_manager || editor) { - // Hide console window if requested (Windows-only). - bool hide_console = EditorSettings::get_singleton()->get_setting("interface/editor/hide_console_window"); - DisplayServer::get_singleton()->console_set_visible(!hide_console); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CONSOLE_WINDOW)) { + // Hide console window if requested (Windows-only). + bool hide_console = EditorSettings::get_singleton()->get_setting("interface/editor/hide_console_window"); + DisplayServer::get_singleton()->console_set_visible(!hide_console); + } // Load SSL Certificates from Editor Settings (or builtin) Crypto::load_default_certificates(EditorSettings::get_singleton()->get_setting("network/ssl/editor_ssl_certificates").operator String()); @@ -2055,7 +2121,6 @@ static uint64_t physics_process_max = 0; static uint64_t idle_process_max = 0; bool Main::iteration() { - //for now do not error on this //ERR_FAIL_COND_V(iterating, false); @@ -2098,7 +2163,6 @@ bool Main::iteration() { Engine::get_singleton()->_in_physics = true; for (int iters = 0; iters < advance.physics_steps; ++iters) { - uint64_t physics_begin = OS::get_singleton()->get_ticks_usec(); PhysicsServer3D::get_singleton()->sync(); @@ -2140,7 +2204,6 @@ bool Main::iteration() { RenderingServer::get_singleton()->sync(); //sync if still drawing from previous frames. if (DisplayServer::get_singleton()->can_any_window_draw() && !disable_render_loop) { - if ((!force_redraw_requested) && OS::get_singleton()->is_in_low_processor_usage_mode()) { if (RenderingServer::get_singleton()->has_changed()) { RenderingServer::get_singleton()->draw(true, scaled_step); // flush visual commands @@ -2163,14 +2226,14 @@ bool Main::iteration() { AudioServer::get_singleton()->update(); - if (EngineDebugger::is_active()) + if (EngineDebugger::is_active()) { EngineDebugger::get_singleton()->iteration(frame_time, idle_process_ticks, physics_process_ticks, frame_slice); + } frames++; Engine::get_singleton()->_idle_frames++; if (frame > 1000000) { - if (editor || project_manager) { if (print_fps) { print_line("Editor FPS: " + itos(frames)); @@ -2191,15 +2254,17 @@ bool Main::iteration() { iterating--; - if (fixed_fps != -1) + if (fixed_fps != -1) { return exit; + } - if (OS::get_singleton()->is_in_low_processor_usage_mode() || !DisplayServer::get_singleton()->can_any_window_draw()) + if (OS::get_singleton()->is_in_low_processor_usage_mode() || !DisplayServer::get_singleton()->can_any_window_draw()) { OS::get_singleton()->delay_usec(OS::get_singleton()->get_low_processor_usage_mode_sleep_usec()); //apply some delay to force idle time - else { + } else { uint32_t frame_delay = Engine::get_singleton()->get_frame_delay(); - if (frame_delay) + if (frame_delay) { OS::get_singleton()->delay_usec(Engine::get_singleton()->get_frame_delay() * 1000); + } } int target_fps = Engine::get_singleton()->get_target_fps(); @@ -2207,7 +2272,9 @@ bool Main::iteration() { uint64_t time_step = 1000000L / target_fps; target_ticks += time_step; uint64_t current_ticks = OS::get_singleton()->get_ticks_usec(); - if (current_ticks < target_ticks) OS::get_singleton()->delay_usec(target_ticks - current_ticks); + if (current_ticks < target_ticks) { + OS::get_singleton()->delay_usec(target_ticks - current_ticks); + } current_ticks = OS::get_singleton()->get_ticks_usec(); target_ticks = MIN(MAX(target_ticks, current_ticks - time_step), current_ticks + time_step); } @@ -2239,7 +2306,6 @@ void Main::force_redraw() { * The order matters as some of those steps are linked with each other. */ void Main::cleanup() { - ERR_FAIL_COND(!_start_success); EngineDebugger::deinitialize(); @@ -2264,13 +2330,16 @@ void Main::cleanup() { // Sync pending commands that may have been queued from a different thread during ScriptServer finalization RenderingServer::get_singleton()->sync(); + //clear global shader variables before scene and other graphics stuff is deinitialized. + rendering_server->global_variables_clear(); + #ifdef TOOLS_ENABLED EditorNode::unregister_editor_types(); #endif - if (arvr_server) { + if (xr_server) { // cleanup now before we pull the rug from underneath... - memdelete(arvr_server); + memdelete(xr_server); } ImageLoader::cleanup(); @@ -2300,20 +2369,27 @@ void Main::cleanup() { memdelete(input); } - if (packed_data) + if (packed_data) { memdelete(packed_data); - if (file_access_network_client) + } + if (file_access_network_client) { memdelete(file_access_network_client); - if (performance) + } + if (performance) { memdelete(performance); - if (input_map) + } + if (input_map) { memdelete(input_map); - if (translation_server) + } + if (translation_server) { memdelete(translation_server); - if (globals) + } + if (globals) { memdelete(globals); - if (engine) + } + if (engine) { memdelete(engine); + } if (OS::get_singleton()->is_restart_on_exit_set()) { //attempt to restart with arguments diff --git a/main/main.h b/main/main.h index e8f8357518..ab6917a65c 100644 --- a/main/main.h +++ b/main/main.h @@ -36,7 +36,6 @@ #include "core/typedefs.h" class Main { - static void print_help(const char *p_binary); static uint64_t last_ticks; static uint64_t target_ticks; diff --git a/main/main_timer_sync.cpp b/main/main_timer_sync.cpp index 9e23a1f5cb..5252ea005b 100644 --- a/main/main_timer_sync.cpp +++ b/main/main_timer_sync.cpp @@ -56,15 +56,17 @@ int MainTimerSync::get_average_physics_steps(float &p_min, float &p_max) { for (int i = 1; i < CONTROL_STEPS; ++i) { const float typical_lower = typical_physics_steps[i]; const float current_min = typical_lower / (i + 1); - if (current_min > p_max) + if (current_min > p_max) { return i; // bail out of further restrictions would void the interval - else if (current_min > p_min) + } else if (current_min > p_min) { p_min = current_min; + } const float current_max = (typical_lower + 1) / (i + 1); - if (current_max < p_min) + if (current_max < p_min) { return i; - else if (current_max < p_max) + } else if (current_max < p_max) { p_max = current_max; + } } return CONTROL_STEPS; @@ -95,10 +97,12 @@ MainFrameTime MainTimerSync::advance_core(float p_frame_slice, int p_iterations_ break; } - if (steps_left_to_match_typical > min_typical_steps) + if (steps_left_to_match_typical > min_typical_steps) { min_typical_steps = steps_left_to_match_typical; - if (steps_left_to_match_typical + 1 < max_typical_steps) + } + if (steps_left_to_match_typical + 1 < max_typical_steps) { max_typical_steps = steps_left_to_match_typical + 1; + } } // try to keep it consistent with previous iterations @@ -143,8 +147,9 @@ MainFrameTime MainTimerSync::advance_core(float p_frame_slice, int p_iterations_ // calls advance_core, keeps track of deficit it adds to animaption_step, make sure the deficit sum stays close to zero MainFrameTime MainTimerSync::advance_checked(float p_frame_slice, int p_iterations_per_second, float p_idle_step) { - if (fixed_fps != -1) + if (fixed_fps != -1) { p_idle_step = 1.0 / fixed_fps; + } // compensate for last deficit p_idle_step += time_deficit; @@ -193,12 +198,7 @@ float MainTimerSync::get_cpu_idle_step() { return cpu_ticks_elapsed / 1000000.0; } -MainTimerSync::MainTimerSync() : - last_cpu_ticks_usec(0), - current_cpu_ticks_usec(0), - time_accum(0), - time_deficit(0), - fixed_fps(0) { +MainTimerSync::MainTimerSync() { for (int i = CONTROL_STEPS - 1; i >= 0; --i) { typical_physics_steps[i] = i; accumulated_physics_steps[i] = i; diff --git a/main/main_timer_sync.h b/main/main_timer_sync.h index 620d1c747d..2126381c7c 100644 --- a/main/main_timer_sync.h +++ b/main/main_timer_sync.h @@ -43,14 +43,14 @@ struct MainFrameTime { class MainTimerSync { // wall clock time measured on the main thread - uint64_t last_cpu_ticks_usec; - uint64_t current_cpu_ticks_usec; + uint64_t last_cpu_ticks_usec = 0; + uint64_t current_cpu_ticks_usec = 0; // logical game time since last physics timestep - float time_accum; + float time_accum = 0; // current difference between wall clock time and reported sum of idle_steps - float time_deficit; + float time_deficit = 0; // number of frames back for keeping accumulated physics steps roughly constant. // value of 12 chosen because that is what is required to make 144 Hz monitors @@ -64,7 +64,7 @@ class MainTimerSync { // typical value for accumulated_physics_steps[i] is either this or this plus one int typical_physics_steps[CONTROL_STEPS]; - int fixed_fps; + int fixed_fps = 0; protected: // returns the fraction of p_frame_slice required for the timer to overshoot diff --git a/main/performance.cpp b/main/performance.cpp index 335407c9eb..7e6b9fca64 100644 --- a/main/performance.cpp +++ b/main/performance.cpp @@ -39,10 +39,9 @@ #include "servers/physics_server_3d.h" #include "servers/rendering_server.h" -Performance *Performance::singleton = NULL; +Performance *Performance::singleton = nullptr; void Performance::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_monitor", "monitor"), &Performance::get_monitor); BIND_ENUM_CONSTANT(TIME_FPS); @@ -79,13 +78,13 @@ void Performance::_bind_methods() { float Performance::_get_node_count() const { MainLoop *ml = OS::get_singleton()->get_main_loop(); SceneTree *sml = Object::cast_to<SceneTree>(ml); - if (!sml) + if (!sml) { return 0; + } return sml->get_node_count(); } String Performance::get_monitor_name(Monitor p_monitor) const { - ERR_FAIL_INDEX_V(p_monitor, MONITOR_MAX, String()); static const char *names[MONITOR_MAX] = { @@ -123,35 +122,61 @@ String Performance::get_monitor_name(Monitor p_monitor) const { } float Performance::get_monitor(Monitor p_monitor) const { - switch (p_monitor) { - case TIME_FPS: return Engine::get_singleton()->get_frames_per_second(); - case TIME_PROCESS: return _process_time; - case TIME_PHYSICS_PROCESS: return _physics_process_time; - case MEMORY_STATIC: return Memory::get_mem_usage(); - case MEMORY_STATIC_MAX: return Memory::get_mem_max_usage(); - case MEMORY_MESSAGE_BUFFER_MAX: return MessageQueue::get_singleton()->get_max_buffer_usage(); - case OBJECT_COUNT: return ObjectDB::get_object_count(); - case OBJECT_RESOURCE_COUNT: return ResourceCache::get_cached_resource_count(); - case OBJECT_NODE_COUNT: return _get_node_count(); - case OBJECT_ORPHAN_NODE_COUNT: return Node::orphan_node_count; - case RENDER_OBJECTS_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_OBJECTS_IN_FRAME); - case RENDER_VERTICES_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_VERTICES_IN_FRAME); - case RENDER_MATERIAL_CHANGES_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_MATERIAL_CHANGES_IN_FRAME); - case RENDER_SHADER_CHANGES_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_SHADER_CHANGES_IN_FRAME); - case RENDER_SURFACE_CHANGES_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_SURFACE_CHANGES_IN_FRAME); - case RENDER_DRAW_CALLS_IN_FRAME: return RS::get_singleton()->get_render_info(RS::INFO_DRAW_CALLS_IN_FRAME); - case RENDER_VIDEO_MEM_USED: return RS::get_singleton()->get_render_info(RS::INFO_VIDEO_MEM_USED); - case RENDER_TEXTURE_MEM_USED: return RS::get_singleton()->get_render_info(RS::INFO_TEXTURE_MEM_USED); - case RENDER_VERTEX_MEM_USED: return RS::get_singleton()->get_render_info(RS::INFO_VERTEX_MEM_USED); - case RENDER_USAGE_VIDEO_MEM_TOTAL: return RS::get_singleton()->get_render_info(RS::INFO_USAGE_VIDEO_MEM_TOTAL); - case PHYSICS_2D_ACTIVE_OBJECTS: return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_ACTIVE_OBJECTS); - case PHYSICS_2D_COLLISION_PAIRS: return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_COLLISION_PAIRS); - case PHYSICS_2D_ISLAND_COUNT: return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_ISLAND_COUNT); - case PHYSICS_3D_ACTIVE_OBJECTS: return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_ACTIVE_OBJECTS); - case PHYSICS_3D_COLLISION_PAIRS: return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_COLLISION_PAIRS); - case PHYSICS_3D_ISLAND_COUNT: return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_ISLAND_COUNT); - case AUDIO_OUTPUT_LATENCY: return AudioServer::get_singleton()->get_output_latency(); + case TIME_FPS: + return Engine::get_singleton()->get_frames_per_second(); + case TIME_PROCESS: + return _process_time; + case TIME_PHYSICS_PROCESS: + return _physics_process_time; + case MEMORY_STATIC: + return Memory::get_mem_usage(); + case MEMORY_STATIC_MAX: + return Memory::get_mem_max_usage(); + case MEMORY_MESSAGE_BUFFER_MAX: + return MessageQueue::get_singleton()->get_max_buffer_usage(); + case OBJECT_COUNT: + return ObjectDB::get_object_count(); + case OBJECT_RESOURCE_COUNT: + return ResourceCache::get_cached_resource_count(); + case OBJECT_NODE_COUNT: + return _get_node_count(); + case OBJECT_ORPHAN_NODE_COUNT: + return Node::orphan_node_count; + case RENDER_OBJECTS_IN_FRAME: + return RS::get_singleton()->get_render_info(RS::INFO_OBJECTS_IN_FRAME); + case RENDER_VERTICES_IN_FRAME: + return RS::get_singleton()->get_render_info(RS::INFO_VERTICES_IN_FRAME); + case RENDER_MATERIAL_CHANGES_IN_FRAME: + return RS::get_singleton()->get_render_info(RS::INFO_MATERIAL_CHANGES_IN_FRAME); + case RENDER_SHADER_CHANGES_IN_FRAME: + return RS::get_singleton()->get_render_info(RS::INFO_SHADER_CHANGES_IN_FRAME); + case RENDER_SURFACE_CHANGES_IN_FRAME: + return RS::get_singleton()->get_render_info(RS::INFO_SURFACE_CHANGES_IN_FRAME); + case RENDER_DRAW_CALLS_IN_FRAME: + return RS::get_singleton()->get_render_info(RS::INFO_DRAW_CALLS_IN_FRAME); + case RENDER_VIDEO_MEM_USED: + return RS::get_singleton()->get_render_info(RS::INFO_VIDEO_MEM_USED); + case RENDER_TEXTURE_MEM_USED: + return RS::get_singleton()->get_render_info(RS::INFO_TEXTURE_MEM_USED); + case RENDER_VERTEX_MEM_USED: + return RS::get_singleton()->get_render_info(RS::INFO_VERTEX_MEM_USED); + case RENDER_USAGE_VIDEO_MEM_TOTAL: + return RS::get_singleton()->get_render_info(RS::INFO_USAGE_VIDEO_MEM_TOTAL); + case PHYSICS_2D_ACTIVE_OBJECTS: + return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_ACTIVE_OBJECTS); + case PHYSICS_2D_COLLISION_PAIRS: + return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_COLLISION_PAIRS); + case PHYSICS_2D_ISLAND_COUNT: + return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_ISLAND_COUNT); + case PHYSICS_3D_ACTIVE_OBJECTS: + return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_ACTIVE_OBJECTS); + case PHYSICS_3D_COLLISION_PAIRS: + return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_COLLISION_PAIRS); + case PHYSICS_3D_ISLAND_COUNT: + return PhysicsServer3D::get_singleton()->get_process_info(PhysicsServer3D::INFO_ISLAND_COUNT); + case AUDIO_OUTPUT_LATENCY: + return AudioServer::get_singleton()->get_output_latency(); default: { } @@ -199,17 +224,14 @@ Performance::MonitorType Performance::get_monitor_type(Monitor p_monitor) const } void Performance::set_process_time(float p_pt) { - _process_time = p_pt; } void Performance::set_physics_process_time(float p_pt) { - _physics_process_time = p_pt; } Performance::Performance() { - _process_time = 0; _physics_process_time = 0; singleton = this; diff --git a/main/performance.h b/main/performance.h index c0f6044ea0..ddbe45fa00 100644 --- a/main/performance.h +++ b/main/performance.h @@ -37,7 +37,6 @@ #define PERF_WARN_PROCESS_SYNC class Performance : public Object { - GDCLASS(Performance, Object); static Performance *singleton; diff --git a/main/tests/test_astar.cpp b/main/tests/test_astar.cpp index e82d885af2..fe335589b0 100644 --- a/main/tests/test_astar.cpp +++ b/main/tests/test_astar.cpp @@ -173,7 +173,9 @@ bool test_add_remove() { for (int i = 0; i < 20000; i++) { int u = Math::rand() % 5; int v = Math::rand() % 4; - if (u == v) v = 4; + if (u == v) { + v = 4; + } if (Math::rand() % 2 == 1) { // Add a (possibly existing) directed edge and confirm connectivity a.connect_points(u, v, false); @@ -188,18 +190,22 @@ bool test_add_remove() { // Random tests for point removal for (int i = 0; i < 20000; i++) { a.clear(); - for (int j = 0; j < 5; j++) + for (int j = 0; j < 5; j++) { a.add_point(j, Vector3(0, 0, 0)); + } // Add or remove random edges for (int j = 0; j < 10; j++) { int u = Math::rand() % 5; int v = Math::rand() % 4; - if (u == v) v = 4; - if (Math::rand() % 2 == 1) + if (u == v) { + v = 4; + } + if (Math::rand() % 2 == 1) { a.connect_points(u, v, false); - else + } else { a.disconnect_points(u, v, false); + } } // Remove point 0 @@ -239,7 +245,9 @@ bool test_solutions() { int u, v; u = Math::rand() % N; v = Math::rand() % (N - 1); - if (u == v) v = N - 1; + if (u == v) { + v = N - 1; + } // Pick a random operation int op = Math::rand(); @@ -253,14 +261,18 @@ bool test_solutions() { // Add edge (u, v); possibly bidirectional a.connect_points(u, v, op % 2); adj[u][v] = true; - if (op % 2) adj[v][u] = true; + if (op % 2) { + adj[v][u] = true; + } break; case 6: case 7: // Remove edge (u, v); possibly bidirectional a.disconnect_points(u, v, op % 2); adj[u][v] = false; - if (op % 2) adj[v][u] = false; + if (op % 2) { + adj[v][u] = false; + } break; case 8: // Remove point u and add it back; clears adjacent edges and changes coordinates @@ -269,40 +281,55 @@ bool test_solutions() { p[u].y = Math::rand() % 100; p[u].z = Math::rand() % 100; a.add_point(u, p[u]); - for (v = 0; v < N; v++) + for (v = 0; v < N; v++) { adj[u][v] = adj[v][u] = false; + } break; } } // Floyd-Warshall float d[N][N]; - for (int u = 0; u < N; u++) - for (int v = 0; v < N; v++) + for (int u = 0; u < N; u++) { + for (int v = 0; v < N; v++) { d[u][v] = (u == v || adj[u][v]) ? p[u].distance_to(p[v]) : INFINITY; + } + } - for (int w = 0; w < N; w++) - for (int u = 0; u < N; u++) - for (int v = 0; v < N; v++) - if (d[u][v] > d[u][w] + d[w][v]) + for (int w = 0; w < N; w++) { + for (int u = 0; u < N; u++) { + for (int v = 0; v < N; v++) { + if (d[u][v] > d[u][w] + d[w][v]) { d[u][v] = d[u][w] + d[w][v]; + } + } + } + } // Display statistics int count = 0; - for (int u = 0; u < N; u++) - for (int v = 0; v < N; v++) - if (adj[u][v]) count++; + for (int u = 0; u < N; u++) { + for (int v = 0; v < N; v++) { + if (adj[u][v]) { + count++; + } + } + } printf("Test #%4d: %3d edges, ", test + 1, count); count = 0; - for (int u = 0; u < N; u++) - for (int v = 0; v < N; v++) - if (!Math::is_inf(d[u][v])) count++; + for (int u = 0; u < N; u++) { + for (int v = 0; v < N; v++) { + if (!Math::is_inf(d[u][v])) { + count++; + } + } + } printf("%3d/%d pairs of reachable points\n", count - N, N * (N - 1)); // Check A*'s output bool match = true; - for (int u = 0; u < N; u++) - for (int v = 0; v < N; v++) + for (int u = 0; u < N; u++) { + for (int v = 0; v < N; v++) { if (u != v) { Vector<int> route = a.get_id_path(u, v); if (!Math::is_inf(d[u][v])) { @@ -337,21 +364,25 @@ bool test_solutions() { } } } + } + } exit: - if (!match) return false; + if (!match) { + return false; + } } return true; } -typedef bool (*TestFunc)(void); +typedef bool (*TestFunc)(); TestFunc test_funcs[] = { test_abc, test_abcx, test_add_remove, test_solutions, - NULL + nullptr }; MainLoop *test() { @@ -359,18 +390,20 @@ MainLoop *test() { int passed = 0; while (true) { - if (!test_funcs[count]) + if (!test_funcs[count]) { break; + } bool pass = test_funcs[count](); - if (pass) + if (pass) { passed++; + } OS::get_singleton()->print("\t%s\n", pass ? "PASS" : "FAILED"); count++; } OS::get_singleton()->print("\n"); OS::get_singleton()->print("Passed %i of %i tests\n", passed, count); - return NULL; + return nullptr; } } // namespace TestAStar diff --git a/main/tests/test_class_db.cpp b/main/tests/test_class_db.cpp new file mode 100644 index 0000000000..3171091402 --- /dev/null +++ b/main/tests/test_class_db.cpp @@ -0,0 +1,882 @@ +/*************************************************************************/ +/* test_class_db.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "test_class_db.h" + +#include "core/global_constants.h" +#include "core/ordered_hash_map.h" +#include "core/os/os.h" +#include "core/string_name.h" +#include "core/ustring.h" +#include "core/variant.h" + +namespace TestClassDB { + +enum class [[nodiscard]] TestResult{ + FAILED, + PASS +}; + +#define TEST_FAIL_COND(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + ERR_PRINT(m_msg); \ + return TestResult::FAILED; \ + } else \ + ((void)0) + +#define TEST_COND(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + ERR_PRINT(m_msg); \ + __test_result__ = TestResult::FAILED; \ + } else \ + ((void)0) + +#define TEST_FAIL_CHECK(m_test_expr) \ + if (unlikely((m_test_expr) == TestResult::FAILED)) { \ + return TestResult::FAILED; \ + } else \ + ((void)0) + +#define TEST_CHECK(m_test_expr) \ + if (unlikely((m_test_expr) == TestResult::FAILED)) { \ + __test_result__ = TestResult::FAILED; \ + } else \ + ((void)0) + +#define TEST_START() \ + TestResult __test_result__ = TestResult::PASS; \ + ((void)0) + +#define TEST_END() return __test_result__; + +struct TypeReference { + StringName name; + bool is_enum = false; +}; + +struct ConstantData { + String name; + int value = 0; +}; + +struct EnumData { + StringName name; + List<ConstantData> constants; + + _FORCE_INLINE_ bool operator==(const EnumData &p_enum) const { + return p_enum.name == name; + } +}; + +struct PropertyData { + StringName name; + int index = 0; + + StringName getter; + StringName setter; +}; + +struct ArgumentData { + TypeReference type; + String name; + bool has_defval = false; + Variant defval; +}; + +struct MethodData { + StringName name; + TypeReference return_type; + List<ArgumentData> arguments; + bool is_virtual = false; + bool is_vararg = false; +}; + +struct SignalData { + StringName name; + List<ArgumentData> arguments; +}; + +struct ExposedClass { + StringName name; + StringName base; + + bool is_singleton = false; + bool is_instantiable = false; + bool is_reference = false; + + ClassDB::APIType api_type; + + List<ConstantData> constants; + List<EnumData> enums; + List<PropertyData> properties; + List<MethodData> methods; + List<SignalData> signals_; + + const PropertyData *find_property_by_name(const StringName &p_name) const { + for (const List<PropertyData>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().name == p_name) { + return &E->get(); + } + } + + return nullptr; + } + + const MethodData *find_method_by_name(const StringName &p_name) const { + for (const List<MethodData>::Element *E = methods.front(); E; E = E->next()) { + if (E->get().name == p_name) { + return &E->get(); + } + } + + return nullptr; + } +}; + +struct NamesCache { + StringName variant_type = StaticCString::create("Variant"); + StringName object_class = StaticCString::create("Object"); + StringName reference_class = StaticCString::create("Reference"); + StringName string_type = StaticCString::create("String"); + StringName string_name_type = StaticCString::create("StringName"); + StringName node_path_type = StaticCString::create("NodePath"); + StringName bool_type = StaticCString::create("bool"); + StringName int_type = StaticCString::create("int"); + StringName float_type = StaticCString::create("float"); + StringName void_type = StaticCString::create("void"); + StringName vararg_stub_type = StaticCString::create("@VarArg@"); + StringName vector2_type = StaticCString::create("Vector2"); + StringName rect2_type = StaticCString::create("Rect2"); + StringName vector3_type = StaticCString::create("Vector3"); + + // Object not included as it must be checked for all derived classes + static constexpr int nullable_types_count = 17; + StringName nullable_types[nullable_types_count] = { + string_type, + string_name_type, + node_path_type, + + StaticCString::create(_STR(Array)), + StaticCString::create(_STR(Dictionary)), + StaticCString::create(_STR(Callable)), + StaticCString::create(_STR(Signal)), + + StaticCString::create(_STR(PackedByteArray)), + StaticCString::create(_STR(PackedInt32Array)), + StaticCString::create(_STR(PackedInt64rray)), + StaticCString::create(_STR(PackedFloat32Array)), + StaticCString::create(_STR(PackedFloat64Array)), + StaticCString::create(_STR(PackedStringArray)), + StaticCString::create(_STR(PackedVector2Array)), + StaticCString::create(_STR(PackedVector3Array)), + StaticCString::create(_STR(PackedColorArray)), + }; + + bool is_nullable_type(const StringName &p_type) const { + for (int i = 0; i < nullable_types_count; i++) { + if (p_type == nullable_types[i]) { + return true; + } + } + + return false; + } +}; + +typedef OrderedHashMap<StringName, ExposedClass> ExposedClasses; + +struct Context { + Vector<StringName> enum_types; + Vector<StringName> builtin_types; + ExposedClasses exposed_classes; + List<EnumData> global_enums; + NamesCache names_cache; + + const ExposedClass *find_exposed_class(const StringName &p_name) const { + ExposedClasses::ConstElement elem = exposed_classes.find(p_name); + return elem ? &elem.value() : nullptr; + } + + const ExposedClass *find_exposed_class(const TypeReference &p_type_ref) const { + ExposedClasses::ConstElement elem = exposed_classes.find(p_type_ref.name); + return elem ? &elem.value() : nullptr; + } + + bool has_type(const TypeReference &p_type_ref) const { + if (builtin_types.find(p_type_ref.name) >= 0) { + return true; + } + + if (p_type_ref.is_enum) { + if (enum_types.find(p_type_ref.name) >= 0) { + return true; + } + + // Enum not found. Most likely because none of its constants were bound, so it's empty. That's fine. Use int instead. + return builtin_types.find(names_cache.int_type); + } + + return false; + } +}; + +bool arg_default_value_is_assignable_to_type(const Context &p_context, const Variant &p_val, const TypeReference &p_arg_type) { + if (p_arg_type.name == p_context.names_cache.variant_type) { + // Variant can take anything + return true; + } + + switch (p_val.get_type()) { + case Variant::NIL: + return p_context.find_exposed_class(p_arg_type) || + p_context.names_cache.is_nullable_type(p_arg_type.name); + case Variant::BOOL: + return p_arg_type.name == p_context.names_cache.bool_type; + case Variant::INT: + return p_arg_type.name == p_context.names_cache.int_type || + p_arg_type.name == p_context.names_cache.float_type || + p_arg_type.is_enum; + case Variant::FLOAT: + return p_arg_type.name == p_context.names_cache.float_type; + case Variant::STRING: + case Variant::STRING_NAME: + return p_arg_type.name == p_context.names_cache.string_type || + p_arg_type.name == p_context.names_cache.string_name_type || + p_arg_type.name == p_context.names_cache.node_path_type; + case Variant::NODE_PATH: + return p_arg_type.name == p_context.names_cache.node_path_type; + case Variant::TRANSFORM: + case Variant::TRANSFORM2D: + case Variant::BASIS: + case Variant::QUAT: + case Variant::PLANE: + case Variant::AABB: + case Variant::COLOR: + case Variant::VECTOR2: + case Variant::RECT2: + case Variant::VECTOR3: + case Variant::_RID: + case Variant::ARRAY: + case Variant::DICTIONARY: + case Variant::PACKED_BYTE_ARRAY: + case Variant::PACKED_INT32_ARRAY: + case Variant::PACKED_INT64_ARRAY: + case Variant::PACKED_FLOAT32_ARRAY: + case Variant::PACKED_FLOAT64_ARRAY: + case Variant::PACKED_STRING_ARRAY: + case Variant::PACKED_VECTOR2_ARRAY: + case Variant::PACKED_VECTOR3_ARRAY: + case Variant::PACKED_COLOR_ARRAY: + case Variant::CALLABLE: + case Variant::SIGNAL: + return p_arg_type.name == Variant::get_type_name(p_val.get_type()); + case Variant::OBJECT: + return p_context.find_exposed_class(p_arg_type); + case Variant::VECTOR2I: + return p_arg_type.name == p_context.names_cache.vector2_type || + p_arg_type.name == Variant::get_type_name(p_val.get_type()); + case Variant::RECT2I: + return p_arg_type.name == p_context.names_cache.rect2_type || + p_arg_type.name == Variant::get_type_name(p_val.get_type()); + case Variant::VECTOR3I: + return p_arg_type.name == p_context.names_cache.vector3_type || + p_arg_type.name == Variant::get_type_name(p_val.get_type()); + default: + ERR_PRINT("Unexpected Variant type: " + itos(p_val.get_type())); + break; + } + + return false; +} + +TestResult validate_property(const Context &p_context, const ExposedClass &p_class, const PropertyData &p_prop) { + TEST_START(); + + const MethodData *setter = p_class.find_method_by_name(p_prop.setter); + + // Search it in base classes too + const ExposedClass *top = &p_class; + while (!setter && top->base != StringName()) { + top = p_context.find_exposed_class(top->base); + TEST_FAIL_COND(!top, "Class not found '" + top->base + "'. Inherited by '" + top->name + "'."); + setter = top->find_method_by_name(p_prop.setter); + } + + const MethodData *getter = p_class.find_method_by_name(p_prop.getter); + + // Search it in base classes too + top = &p_class; + while (!getter && top->base != StringName()) { + top = p_context.find_exposed_class(top->base); + TEST_FAIL_COND(!top, "Class not found '" + top->base + "'. Inherited by '" + top->name + "'."); + getter = top->find_method_by_name(p_prop.getter); + } + + TEST_FAIL_COND(!setter && !getter, + "Couldn't find neither the setter nor the getter for property: '" + p_class.name + "." + String(p_prop.name) + "'."); + + if (setter) { + int setter_argc = p_prop.index != -1 ? 2 : 1; + TEST_FAIL_COND(setter->arguments.size() != setter_argc, + "Invalid property setter argument count: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + + if (getter) { + int getter_argc = p_prop.index != -1 ? 1 : 0; + TEST_FAIL_COND(getter->arguments.size() != getter_argc, + "Invalid property setter argument count: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + + if (getter && setter) { + const ArgumentData &setter_first_arg = setter->arguments.back()->get(); + if (getter->return_type.name != setter_first_arg.type.name) { + // Special case for Node::set_name + bool whitelisted = getter->return_type.name == p_context.names_cache.string_name_type && + setter_first_arg.type.name == p_context.names_cache.string_type; + + TEST_FAIL_COND(!whitelisted, + "Return type from getter doesn't match first argument of setter, for property: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + } + + const TypeReference &prop_type_ref = getter ? getter->return_type : setter->arguments.back()->get().type; + + const ExposedClass *prop_class = p_context.find_exposed_class(prop_type_ref); + if (prop_class) { + TEST_COND(prop_class->is_singleton, + "Property type is a singleton: '" + p_class.name + "." + String(p_prop.name) + "'."); + } else { + TEST_FAIL_COND(!p_context.has_type(prop_type_ref), + "Property type '" + prop_type_ref.name + "' not found: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + + if (getter) { + if (p_prop.index != -1) { + const ArgumentData &idx_arg = getter->arguments.front()->get(); + if (idx_arg.type.name != p_context.names_cache.int_type) { + // If not an int, it can be an enum + TEST_COND(p_context.enum_types.find(idx_arg.type.name) < 0, + "Invalid type '" + idx_arg.type.name + "' for index argument of property getter: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + } + } + + if (setter) { + if (p_prop.index != -1) { + const ArgumentData &idx_arg = setter->arguments.front()->get(); + if (idx_arg.type.name != p_context.names_cache.int_type) { + // Assume the index parameter is an enum + // If not an int, it can be an enum + TEST_COND(p_context.enum_types.find(idx_arg.type.name) < 0, + "Invalid type '" + idx_arg.type.name + "' for index argument of property setter: '" + p_class.name + "." + String(p_prop.name) + "'."); + } + } + } + + TEST_END(); +} + +TestResult validate_method(const Context &p_context, const ExposedClass &p_class, const MethodData &p_method) { + TEST_START(); + + const ExposedClass *return_class = p_context.find_exposed_class(p_method.return_type); + if (return_class) { + TEST_COND(return_class->is_singleton, + "Method return type is a singleton: '" + p_class.name + "." + p_method.name + "'."); + } + + for (const List<ArgumentData>::Element *F = p_method.arguments.front(); F; F = F->next()) { + const ArgumentData &arg = F->get(); + + const ExposedClass *arg_class = p_context.find_exposed_class(arg.type); + if (arg_class) { + TEST_COND(arg_class->is_singleton, + "Argument type is a singleton: '" + arg.name + "' of method '" + p_class.name + "." + p_method.name + "'."); + } else { + TEST_FAIL_COND(!p_context.has_type(arg.type), + "Argument type '" + arg.type.name + "' not found: '" + arg.name + "' of method" + p_class.name + "." + p_method.name + "'."); + } + + if (arg.has_defval) { + TEST_COND(!arg_default_value_is_assignable_to_type(p_context, arg.defval, arg.type), + "Invalid default value for parameter '" + arg.name + "' of method '" + p_class.name + "." + p_method.name + "'."); + } + } + + TEST_END(); +} + +TestResult validate_signal(const Context &p_context, const ExposedClass &p_class, const SignalData &p_signal) { + TEST_START(); + + for (const List<ArgumentData>::Element *F = p_signal.arguments.front(); F; F = F->next()) { + const ArgumentData &arg = F->get(); + + const ExposedClass *arg_class = p_context.find_exposed_class(arg.type); + if (arg_class) { + TEST_COND(arg_class->is_singleton, + "Argument class is a singleton: '" + arg.name + "' of signal" + p_class.name + "." + p_signal.name + "'."); + } else { + TEST_FAIL_COND(!p_context.has_type(arg.type), + "Argument type '" + arg.type.name + "' not found: '" + arg.name + "' of signal" + p_class.name + "." + p_signal.name + "'."); + } + } + + TEST_END(); +} + +TestResult validate_class(const Context &p_context, const ExposedClass &p_exposed_class) { + TEST_START(); + + bool is_derived_type = p_exposed_class.base != StringName(); + + if (!is_derived_type) { + // Asserts about the base Object class + TEST_FAIL_COND(p_exposed_class.name != p_context.names_cache.object_class, + "Class '" + p_exposed_class.name + "' has no base class."); + TEST_FAIL_COND(!p_exposed_class.is_instantiable, + "Object class is not instantiable."); + TEST_FAIL_COND(p_exposed_class.api_type != ClassDB::API_CORE, + "Object class is API is not API_CORE."); + TEST_FAIL_COND(p_exposed_class.is_singleton, + "Object class is registered as a singleton."); + } + + TEST_FAIL_COND(p_exposed_class.is_singleton && p_exposed_class.base != p_context.names_cache.object_class, + "Singleton base class '" + String(p_exposed_class.base) + "' is not Object, for class '" + p_exposed_class.name + "'."); + + TEST_FAIL_COND(is_derived_type && !p_context.exposed_classes.has(p_exposed_class.base), + "Base type '" + p_exposed_class.base.operator String() + "' does not exist, for class '" + p_exposed_class.name + "'."); + + for (const List<PropertyData>::Element *F = p_exposed_class.properties.front(); F; F = F->next()) { + TEST_CHECK(validate_property(p_context, p_exposed_class, F->get())); + } + + for (const List<MethodData>::Element *F = p_exposed_class.methods.front(); F; F = F->next()) { + TEST_CHECK(validate_method(p_context, p_exposed_class, F->get())); + } + + for (const List<SignalData>::Element *F = p_exposed_class.signals_.front(); F; F = F->next()) { + TEST_CHECK(validate_signal(p_context, p_exposed_class, F->get())); + } + + TEST_END(); +} + +TestResult add_exposed_classes(Context &r_context) { + TEST_START(); + + List<StringName> class_list; + ClassDB::get_class_list(&class_list); + class_list.sort_custom<StringName::AlphCompare>(); + + while (class_list.size()) { + StringName class_name = class_list.front()->get(); + + ClassDB::APIType api_type = ClassDB::get_api_type(class_name); + + if (api_type == ClassDB::API_NONE) { + class_list.pop_front(); + continue; + } + + if (!ClassDB::is_class_exposed(class_name)) { + OS::get_singleton()->print("Ignoring class '%s' because it's not exposed\n", String(class_name).utf8().get_data()); + class_list.pop_front(); + continue; + } + + if (!ClassDB::is_class_enabled(class_name)) { + OS::get_singleton()->print("Ignoring class '%s' because it's not enabled\n", String(class_name).utf8().get_data()); + class_list.pop_front(); + continue; + } + + ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(class_name); + + ExposedClass exposed_class; + exposed_class.name = class_name; + exposed_class.api_type = api_type; + exposed_class.is_singleton = Engine::get_singleton()->has_singleton(class_name); + exposed_class.is_instantiable = class_info->creation_func && !exposed_class.is_singleton; + exposed_class.is_reference = ClassDB::is_parent_class(class_name, "Reference"); + exposed_class.base = ClassDB::get_parent_class(class_name); + + // Add properties + + List<PropertyInfo> property_list; + ClassDB::get_property_list(class_name, &property_list, true); + + Map<StringName, StringName> accessor_methods; + + for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) { + const PropertyInfo &property = E->get(); + + if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_SUBGROUP || property.usage & PROPERTY_USAGE_CATEGORY) { + continue; + } + + PropertyData prop; + prop.name = property.name; + prop.setter = ClassDB::get_property_setter(class_name, prop.name); + prop.getter = ClassDB::get_property_getter(class_name, prop.name); + + if (prop.setter != StringName()) { + accessor_methods[prop.setter] = prop.name; + } + if (prop.getter != StringName()) { + accessor_methods[prop.getter] = prop.name; + } + + bool valid = false; + prop.index = ClassDB::get_property_index(class_name, prop.name, &valid); + TEST_FAIL_COND(!valid, "Invalid property: '" + exposed_class.name + "." + String(prop.name) + "'."); + + exposed_class.properties.push_back(prop); + } + + // Add methods + + List<MethodInfo> virtual_method_list; + ClassDB::get_virtual_methods(class_name, &virtual_method_list, true); + + List<MethodInfo> method_list; + ClassDB::get_method_list(class_name, &method_list, true); + method_list.sort(); + + for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) { + const MethodInfo &method_info = E->get(); + + int argc = method_info.arguments.size(); + + if (method_info.name.empty()) { + continue; + } + + MethodData method; + method.name = method_info.name; + + if (method_info.flags & METHOD_FLAG_VIRTUAL) { + method.is_virtual = true; + } + + PropertyInfo return_info = method_info.return_val; + + MethodBind *m = method.is_virtual ? nullptr : ClassDB::get_method(class_name, method_info.name); + + method.is_vararg = m && m->is_vararg(); + + if (!m && !method.is_virtual) { + TEST_FAIL_COND(!virtual_method_list.find(method_info), + "Missing MethodBind for non-virtual method: '" + exposed_class.name + "." + method.name + "'."); + + // A virtual method without the virtual flag. This is a special case. + + // The method Object.free is registered as a virtual method, but without the virtual flag. + // This is because this method is not supposed to be overridden, but called. + // We assume the return type is void. + method.return_type.name = r_context.names_cache.void_type; + + // Actually, more methods like this may be added in the future, which could return + // something different. Let's put this check to notify us if that ever happens. + if (exposed_class.name != r_context.names_cache.object_class || String(method.name) != "free") { + WARN_PRINT("Notification: New unexpected virtual non-overridable method found." + " We only expected Object.free, but found '" + + exposed_class.name + "." + method.name + "'."); + } + } else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + method.return_type.name = return_info.class_name; + method.return_type.is_enum = true; + } else if (return_info.class_name != StringName()) { + method.return_type.name = return_info.class_name; + + bool bad_reference_hint = !method.is_virtual && return_info.hint != PROPERTY_HINT_RESOURCE_TYPE && + ClassDB::is_parent_class(return_info.class_name, r_context.names_cache.reference_class); + TEST_COND(bad_reference_hint, String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." + + " Are you returning a reference type by pointer? Method: '" + + exposed_class.name + "." + method.name + "'."); + } else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { + method.return_type.name = return_info.hint_string; + } else if (return_info.type == Variant::NIL && return_info.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { + method.return_type.name = r_context.names_cache.variant_type; + } else if (return_info.type == Variant::NIL) { + method.return_type.name = r_context.names_cache.void_type; + } else { + // NOTE: We don't care about the size and sign of int and float in these tests + method.return_type.name = Variant::get_type_name(return_info.type); + } + + for (int i = 0; i < argc; i++) { + PropertyInfo arg_info = method_info.arguments[i]; + + String orig_arg_name = arg_info.name; + + ArgumentData arg; + arg.name = orig_arg_name; + + if (arg_info.type == Variant::INT && arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + arg.type.name = arg_info.class_name; + arg.type.is_enum = true; + } else if (arg_info.class_name != StringName()) { + arg.type.name = arg_info.class_name; + } else if (arg_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { + arg.type.name = arg_info.hint_string; + } else if (arg_info.type == Variant::NIL) { + arg.type.name = r_context.names_cache.variant_type; + } else { + // NOTE: We don't care about the size and sign of int and float in these tests + arg.type.name = Variant::get_type_name(arg_info.type); + } + + if (m && m->has_default_argument(i)) { + arg.has_defval = true; + arg.defval = m->get_default_argument(i); + } + + method.arguments.push_back(arg); + } + + if (method.is_vararg) { + ArgumentData vararg; + vararg.type.name = r_context.names_cache.vararg_stub_type; + vararg.name = "@varargs@"; + method.arguments.push_back(vararg); + } + + TEST_COND(exposed_class.find_property_by_name(method.name), + "Method name conflicts with property: '" + String(class_name) + "." + String(method.name) + "'."); + + // Classes starting with an underscore are ignored unless they're used as a property setter or getter + if (!method.is_virtual && String(method.name)[0] == '_') { + for (const List<PropertyData>::Element *F = exposed_class.properties.front(); F; F = F->next()) { + const PropertyData &prop = F->get(); + + if (prop.setter == method.name || prop.getter == method.name) { + exposed_class.methods.push_back(method); + break; + } + } + } else { + exposed_class.methods.push_back(method); + } + } + + // Add signals + + const HashMap<StringName, MethodInfo> &signal_map = class_info->signal_map; + const StringName *k = nullptr; + + while ((k = signal_map.next(k))) { + SignalData signal; + + const MethodInfo &method_info = signal_map.get(*k); + + signal.name = method_info.name; + + int argc = method_info.arguments.size(); + + for (int i = 0; i < argc; i++) { + PropertyInfo arg_info = method_info.arguments[i]; + + String orig_arg_name = arg_info.name; + + ArgumentData arg; + arg.name = orig_arg_name; + + if (arg_info.type == Variant::INT && arg_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + arg.type.name = arg_info.class_name; + arg.type.is_enum = true; + } else if (arg_info.class_name != StringName()) { + arg.type.name = arg_info.class_name; + } else if (arg_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { + arg.type.name = arg_info.hint_string; + } else if (arg_info.type == Variant::NIL) { + arg.type.name = r_context.names_cache.variant_type; + } else { + // NOTE: We don't care about the size and sign of int and float in these tests + arg.type.name = Variant::get_type_name(arg_info.type); + } + + signal.arguments.push_back(arg); + } + + bool method_conflict = exposed_class.find_property_by_name(signal.name); + + if (method_conflict || exposed_class.find_method_by_name(signal.name)) { + // TODO: + // ClassDB allows signal names that conflict with method or property names. + // However registering a signal with a conflicting name is still considered wrong. + // Unfortunately there are some existing cases that are yet to be fixed. + // Until those are fixed we will print a warning instead of failing the test. + WARN_PRINT("Signal name conflicts with " + String(method_conflict ? "method" : "property") + + ": '" + String(class_name) + "." + String(signal.name) + "'."); + } + + exposed_class.signals_.push_back(signal); + } + + // Add enums and constants + + List<String> constants; + ClassDB::get_integer_constant_list(class_name, &constants, true); + + const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map; + k = nullptr; + + while ((k = enum_map.next(k))) { + EnumData enum_; + enum_.name = *k; + + const List<StringName> &enum_constants = enum_map.get(*k); + for (const List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) { + const StringName &constant_name = E->get(); + int *value = class_info->constant_map.getptr(constant_name); + TEST_FAIL_COND(!value, "Missing enum constant value: '" + + String(class_name) + "." + String(enum_.name) + "." + String(constant_name) + "'."); + constants.erase(constant_name); + + ConstantData constant; + constant.name = constant_name; + constant.value = *value; + + enum_.constants.push_back(constant); + } + + exposed_class.enums.push_back(enum_); + + r_context.enum_types.push_back(String(class_name) + "." + String(*k)); + } + + for (const List<String>::Element *E = constants.front(); E; E = E->next()) { + const String &constant_name = E->get(); + int *value = class_info->constant_map.getptr(StringName(E->get())); + TEST_FAIL_COND(!value, "Missing enum constant value: '" + String(class_name) + "." + String(constant_name) + "'."); + + ConstantData constant; + constant.name = constant_name; + constant.value = *value; + + exposed_class.constants.push_back(constant); + } + + r_context.exposed_classes.insert(class_name, exposed_class); + class_list.pop_front(); + } + + TEST_END(); +} + +void add_builtin_types(Context &r_context) { + // NOTE: We don't care about the size and sign of int and float in these tests + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + r_context.builtin_types.push_back(Variant::get_type_name(Variant::Type(i))); + } + + r_context.builtin_types.push_back(_STR(Variant)); + r_context.builtin_types.push_back(r_context.names_cache.vararg_stub_type); + r_context.builtin_types.push_back("void"); +} + +void add_global_enums(Context &r_context) { + int global_constants_count = GlobalConstants::get_global_constant_count(); + + if (global_constants_count > 0) { + for (int i = 0; i < global_constants_count; i++) { + StringName enum_name = GlobalConstants::get_global_constant_enum(i); + + if (enum_name != StringName()) { + ConstantData constant; + constant.name = GlobalConstants::get_global_constant_name(i); + constant.value = GlobalConstants::get_global_constant_value(i); + + EnumData enum_; + enum_.name = enum_name; + List<EnumData>::Element *enum_match = r_context.global_enums.find(enum_); + if (enum_match) { + enum_match->get().constants.push_back(constant); + } else { + enum_.constants.push_back(constant); + r_context.global_enums.push_back(enum_); + } + } + } + + for (List<EnumData>::Element *E = r_context.global_enums.front(); E; E = E->next()) { + r_context.enum_types.push_back(E->get().name); + } + } + + // HARDCODED + List<StringName> hardcoded_enums; + hardcoded_enums.push_back("Vector2.Axis"); + hardcoded_enums.push_back("Vector2i.Axis"); + hardcoded_enums.push_back("Vector3.Axis"); + hardcoded_enums.push_back("Vector3i.Axis"); + for (List<StringName>::Element *E = hardcoded_enums.front(); E; E = E->next()) { + // These enums are not generated and must be written manually (e.g.: Vector3.Axis) + // Here, we assume core types do not begin with underscore + r_context.enum_types.push_back(E->get()); + } +} + +TestResult run_class_db_tests() { + TEST_START(); + + Context context; + + TEST_FAIL_CHECK(add_exposed_classes(context)); + add_builtin_types(context); + add_global_enums(context); + + const ExposedClass *object_class = context.find_exposed_class(context.names_cache.object_class); + TEST_FAIL_COND(!object_class, "Object class not found."); + TEST_FAIL_COND(object_class->base != StringName(), + "Object class derives from another class: '" + object_class->base + "'."); + + for (ExposedClasses::Element E = context.exposed_classes.front(); E; E = E.next()) { + TEST_CHECK(validate_class(context, E.value())); + } + + TEST_END(); +} + +MainLoop *test() { + TestResult pass = run_class_db_tests(); + + OS::get_singleton()->print("ClassDB tests: %s\n", pass == TestResult::PASS ? "PASS" : "FAILED"); + + if (pass == TestResult::FAILED) { + OS::get_singleton()->set_exit_code(pass == TestResult::PASS ? 0 : 1); + } + + return nullptr; +} + +} // namespace TestClassDB diff --git a/main/tests/test_class_db.h b/main/tests/test_class_db.h new file mode 100644 index 0000000000..1a31cfb01b --- /dev/null +++ b/main/tests/test_class_db.h @@ -0,0 +1,42 @@ +/*************************************************************************/ +/* test_class_db.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef GODOT_TEST_CLASS_DB_H +#define GODOT_TEST_CLASS_DB_H + +#include "core/os/main_loop.h" + +namespace TestClassDB { + +MainLoop *test(); + +} + +#endif //GODOT_TEST_CLASS_DB_H diff --git a/main/tests/test_gdscript.cpp b/main/tests/test_gdscript.cpp index 0e7c45f603..10586c6495 100644 --- a/main/tests/test_gdscript.cpp +++ b/main/tests/test_gdscript.cpp @@ -45,7 +45,6 @@ namespace TestGDScript { static void _print_indent(int p_ident, const String &p_text) { - String txt; for (int i = 0; i < p_ident; i++) { txt += '\t'; @@ -55,18 +54,18 @@ static void _print_indent(int p_ident, const String &p_text) { } static String _parser_extends(const GDScriptParser::ClassNode *p_class) { - String txt = "extends "; if (String(p_class->extends_file) != "") { txt += "\"" + p_class->extends_file + "\""; - if (p_class->extends_class.size()) + if (p_class->extends_class.size()) { txt += "."; + } } for (int i = 0; i < p_class->extends_class.size(); i++) { - - if (i != 0) + if (i != 0) { txt += "."; + } txt += p_class->extends_class[i]; } @@ -75,21 +74,19 @@ static String _parser_extends(const GDScriptParser::ClassNode *p_class) { } static String _parser_expr(const GDScriptParser::Node *p_expr) { - String txt; switch (p_expr->type) { - case GDScriptParser::Node::TYPE_IDENTIFIER: { - const GDScriptParser::IdentifierNode *id_node = static_cast<const GDScriptParser::IdentifierNode *>(p_expr); txt = id_node->name; } break; case GDScriptParser::Node::TYPE_CONSTANT: { const GDScriptParser::ConstantNode *c_node = static_cast<const GDScriptParser::ConstantNode *>(p_expr); - if (c_node->value.get_type() == Variant::STRING) + if (c_node->value.get_type() == Variant::STRING) { txt = "\"" + String(c_node->value) + "\""; - else + } else { txt = c_node->value; + } } break; case GDScriptParser::Node::TYPE_SELF: { @@ -99,9 +96,9 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { const GDScriptParser::ArrayNode *arr_node = static_cast<const GDScriptParser::ArrayNode *>(p_expr); txt += "["; for (int i = 0; i < arr_node->elements.size(); i++) { - - if (i > 0) + if (i > 0) { txt += ", "; + } txt += _parser_expr(arr_node->elements[i]); } txt += "]"; @@ -110,9 +107,9 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { const GDScriptParser::DictionaryNode *dict_node = static_cast<const GDScriptParser::DictionaryNode *>(p_expr); txt += "{"; for (int i = 0; i < dict_node->elements.size(); i++) { - - if (i > 0) + if (i > 0) { txt += ", "; + } const GDScriptParser::DictionaryNode::Pair &p = dict_node->elements[i]; txt += _parser_expr(p.key); @@ -122,37 +119,32 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { txt += "}"; } break; case GDScriptParser::Node::TYPE_OPERATOR: { - const GDScriptParser::OperatorNode *c_node = static_cast<const GDScriptParser::OperatorNode *>(p_expr); switch (c_node->op) { - case GDScriptParser::OperatorNode::OP_PARENT_CALL: txt += "."; [[fallthrough]]; case GDScriptParser::OperatorNode::OP_CALL: { - ERR_FAIL_COND_V(c_node->arguments.size() < 1, ""); String func_name; const GDScriptParser::Node *nfunc = c_node->arguments[0]; int arg_ofs = 0; if (nfunc->type == GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION) { - const GDScriptParser::BuiltInFunctionNode *bif_node = static_cast<const GDScriptParser::BuiltInFunctionNode *>(nfunc); func_name = GDScriptFunctions::get_func_name(bif_node->function); arg_ofs = 1; } else if (nfunc->type == GDScriptParser::Node::TYPE_TYPE) { - const GDScriptParser::TypeNode *t_node = static_cast<const GDScriptParser::TypeNode *>(nfunc); func_name = Variant::get_type_name(t_node->vtype); arg_ofs = 1; } else { - ERR_FAIL_COND_V(c_node->arguments.size() < 2, ""); nfunc = c_node->arguments[1]; ERR_FAIL_COND_V(nfunc->type != GDScriptParser::Node::TYPE_IDENTIFIER, ""); - if (c_node->arguments[0]->type != GDScriptParser::Node::TYPE_SELF) + if (c_node->arguments[0]->type != GDScriptParser::Node::TYPE_SELF) { func_name = _parser_expr(c_node->arguments[0]) + "."; + } func_name += _parser_expr(nfunc); arg_ofs = 2; @@ -161,10 +153,10 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { txt += func_name + "("; for (int i = arg_ofs; i < c_node->arguments.size(); i++) { - const GDScriptParser::Node *arg = c_node->arguments[i]; - if (i > arg_ofs) + if (i > arg_ofs) { txt += ", "; + } txt += _parser_expr(arg); } @@ -172,7 +164,6 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { } break; case GDScriptParser::OperatorNode::OP_INDEX: { - ERR_FAIL_COND_V(c_node->arguments.size() != 2, ""); //index with [] @@ -180,7 +171,6 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { } break; case GDScriptParser::OperatorNode::OP_INDEX_NAMED: { - ERR_FAIL_COND_V(c_node->arguments.size() != 2, ""); txt = _parser_expr(c_node->arguments[0]) + "." + _parser_expr(c_node->arguments[1]); @@ -296,11 +286,9 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { } break; case GDScriptParser::Node::TYPE_NEWLINE: { - //skippie } break; default: { - ERR_FAIL_V_MSG("", "Parser bug at " + itos(p_expr->line) + ", invalid expression type: " + itos(p_expr->type)); } } @@ -309,20 +297,14 @@ static String _parser_expr(const GDScriptParser::Node *p_expr) { } static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_indent) { - for (int i = 0; i < p_block->statements.size(); i++) { - const GDScriptParser::Node *statement = p_block->statements[i]; switch (statement->type) { - case GDScriptParser::Node::TYPE_CONTROL_FLOW: { - const GDScriptParser::ControlFlowNode *cf_node = static_cast<const GDScriptParser::ControlFlowNode *>(statement); switch (cf_node->cf_type) { - case GDScriptParser::ControlFlowNode::CF_IF: { - ERR_FAIL_COND(cf_node->arguments.size() != 1); String txt; txt += "if "; @@ -351,7 +333,6 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i } break; case GDScriptParser::ControlFlowNode::CF_WHILE: { - ERR_FAIL_COND(cf_node->arguments.size() != 1); String txt; txt += "while "; @@ -366,25 +347,22 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i // FIXME: Implement } break; case GDScriptParser::ControlFlowNode::CF_CONTINUE: { - _print_indent(p_indent, "continue"); } break; case GDScriptParser::ControlFlowNode::CF_BREAK: { - _print_indent(p_indent, "break"); } break; case GDScriptParser::ControlFlowNode::CF_RETURN: { - - if (cf_node->arguments.size()) + if (cf_node->arguments.size()) { _print_indent(p_indent, "return " + _parser_expr(cf_node->arguments[0])); - else + } else { _print_indent(p_indent, "return "); + } } break; } } break; case GDScriptParser::Node::TYPE_LOCAL_VAR: { - const GDScriptParser::LocalVarNode *lv_node = static_cast<const GDScriptParser::LocalVarNode *>(statement); _print_indent(p_indent, "var " + String(lv_node->name)); } break; @@ -396,22 +374,23 @@ static void _parser_show_block(const GDScriptParser::BlockNode *p_block, int p_i } } -static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, int p_indent, GDScriptParser::BlockNode *p_initializer = NULL) { - +static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, int p_indent, GDScriptParser::BlockNode *p_initializer = nullptr) { String txt; - if (p_func->_static) + if (p_func->_static) { txt = "static "; + } txt += "func "; - if (p_func->name == "") // initializer + if (p_func->name == "") { // initializer txt += "[built-in-initializer]"; - else + } else { txt += String(p_func->name); + } txt += "("; for (int i = 0; i < p_func->arguments.size(); i++) { - - if (i != 0) + if (i != 0) { txt += ", "; + } txt += "var " + String(p_func->arguments[i]); if (i >= (p_func->arguments.size() - p_func->default_values.size())) { int defarg = i - (p_func->arguments.size() - p_func->default_values.size()); @@ -427,25 +406,24 @@ static void _parser_show_function(const GDScriptParser::FunctionNode *p_func, in txt += ":"; _print_indent(p_indent, txt); - if (p_initializer) + if (p_initializer) { _parser_show_block(p_initializer, p_indent + 1); + } _parser_show_block(p_func->body, p_indent + 1); } static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_indent, const Vector<String> &p_code) { - if (p_indent == 0 && (String(p_class->extends_file) != "" || p_class->extends_class.size())) { - _print_indent(p_indent, _parser_extends(p_class)); print_line("\n"); } for (int i = 0; i < p_class->subclasses.size(); i++) { - const GDScriptParser::ClassNode *subclass = p_class->subclasses[i]; String line = "class " + subclass->name; - if (String(subclass->extends_file) != "" || subclass->extends_class.size()) + if (String(subclass->extends_file) != "" || subclass->extends_class.size()) { line += " " + _parser_extends(subclass); + } line += ":"; _print_indent(p_indent, line); _parser_show_class(subclass, p_indent + 1, p_code); @@ -458,7 +436,6 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i } for (int i = 0; i < p_class->variables.size(); i++) { - const GDScriptParser::ClassNode::Member &m = p_class->variables[i]; _print_indent(p_indent, "var " + String(m.identifier)); @@ -467,17 +444,16 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i print_line("\n"); for (int i = 0; i < p_class->static_functions.size(); i++) { - _parser_show_function(p_class->static_functions[i], p_indent); print_line("\n"); } for (int i = 0; i < p_class->functions.size(); i++) { - if (String(p_class->functions[i]->name) == "_init") { _parser_show_function(p_class->functions[i], p_indent, p_class->initializer); - } else + } else { _parser_show_function(p_class->functions[i], p_indent); + } print_line("\n"); } //_parser_show_function(p_class->initializer,p_indent); @@ -485,11 +461,9 @@ static void _parser_show_class(const GDScriptParser::ClassNode *p_class, int p_i } static String _disassemble_addr(const Ref<GDScript> &p_script, const GDScriptFunction &func, int p_addr) { - int addr = p_addr & GDScriptFunction::ADDR_MASK; switch (p_addr >> GDScriptFunction::ADDR_BITS) { - case GDScriptFunction::ADDR_TYPE_SELF: { return "self"; } break; @@ -497,33 +471,28 @@ static String _disassemble_addr(const Ref<GDScript> &p_script, const GDScriptFun return "class"; } break; case GDScriptFunction::ADDR_TYPE_MEMBER: { - return "member(" + p_script->debug_get_member_by_index(addr) + ")"; } break; case GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT: { - return "class_const(" + func.get_global_name(addr) + ")"; } break; case GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT: { - Variant v = func.get_constant(addr); String txt; - if (v.get_type() == Variant::STRING || v.get_type() == Variant::NODE_PATH) + if (v.get_type() == Variant::STRING || v.get_type() == Variant::NODE_PATH) { txt = "\"" + String(v) + "\""; - else + } else { txt = v; + } return "const(" + txt + ")"; } break; case GDScriptFunction::ADDR_TYPE_STACK: { - return "stack(" + itos(addr) + ")"; } break; case GDScriptFunction::ADDR_TYPE_STACK_VARIABLE: { - return "var_stack(" + itos(addr) + ")"; } break; case GDScriptFunction::ADDR_TYPE_GLOBAL: { - return "global(" + func.get_global_name(addr) + ")"; } break; case GDScriptFunction::ADDR_TYPE_NIL: { @@ -535,11 +504,9 @@ static String _disassemble_addr(const Ref<GDScript> &p_script, const GDScriptFun } static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String> &p_code) { - const Map<StringName, GDScriptFunction *> &mf = p_class->debug_get_member_functions(); for (const Map<StringName, GDScriptFunction *>::Element *E = mf.front(); E; E = E->next()) { - const GDScriptFunction &func = *E->get(); const int *code = func.get_code(); int codelen = func.get_code_size(); @@ -547,9 +514,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String if (func.get_default_argument_count()) { defargs = "defarg at: "; for (int i = 0; i < func.get_default_argument_count(); i++) { - - if (i > 0) + if (i > 0) { defargs += ","; + } defargs += itos(func.get_default_argument_addr(i)); } defargs += " "; @@ -559,14 +526,11 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String #define DADDR(m_ip) (_disassemble_addr(p_class, func, code[ip + m_ip])) for (int ip = 0; ip < codelen;) { - int incr = 0; String txt = itos(ip) + " "; switch (code[ip]) { - case GDScriptFunction::OPCODE_OPERATOR: { - int op = code[ip + 1]; txt += " op "; @@ -581,7 +545,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_SET: { - txt += "set "; txt += DADDR(1); txt += "["; @@ -592,7 +555,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_GET: { - txt += " get "; txt += DADDR(3); txt += "="; @@ -604,7 +566,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_SET_NAMED: { - txt += " set_named "; txt += DADDR(1); txt += "[\""; @@ -615,7 +576,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_GET_NAMED: { - txt += " get_named "; txt += DADDR(3); txt += "="; @@ -627,7 +587,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_SET_MEMBER: { - txt += " set_member "; txt += "[\""; txt += func.get_global_name(code[ip + 1]); @@ -637,7 +596,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_GET_MEMBER: { - txt += " get_member "; txt += DADDR(2); txt += "="; @@ -648,7 +606,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_ASSIGN: { - txt += " assign "; txt += DADDR(1); txt += "="; @@ -657,7 +614,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_ASSIGN_TRUE: { - txt += " assign "; txt += DADDR(1); txt += "= true"; @@ -665,7 +621,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_ASSIGN_FALSE: { - txt += " assign "; txt += DADDR(1); txt += "= false"; @@ -673,7 +628,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN: { - txt += " assign typed builtin ("; txt += Variant::get_type_name((Variant::Type)code[ip + 1]); txt += ") "; @@ -697,7 +651,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CAST_TO_SCRIPT: { - txt += " cast "; txt += DADDR(3); txt += "="; @@ -708,7 +661,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CONSTRUCT: { - Variant::Type t = Variant::Type(code[ip + 1]); int argc = code[ip + 2]; @@ -718,9 +670,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String txt += Variant::get_type_name(t) + "("; for (int i = 0; i < argc; i++) { - - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(i + 3); } txt += ")"; @@ -729,15 +681,15 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CONSTRUCT_ARRAY: { - int argc = code[ip + 1]; txt += " make_array "; txt += DADDR(2 + argc); txt += " = [ "; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(2 + i); } @@ -747,15 +699,15 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY: { - int argc = code[ip + 1]; txt += " make_dict "; txt += DADDR(2 + argc * 2); txt += " = { "; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(2 + i * 2 + 0); txt += ":"; txt += DADDR(2 + i * 2 + 1); @@ -769,13 +721,13 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String case GDScriptFunction::OPCODE_CALL: case GDScriptFunction::OPCODE_CALL_RETURN: { - bool ret = code[ip] == GDScriptFunction::OPCODE_CALL_RETURN; - if (ret) + if (ret) { txt += " call-ret "; - else + } else { txt += " call "; + } int argc = code[ip + 1]; if (ret) { @@ -787,8 +739,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String txt += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(4 + i); } txt += ")"; @@ -797,7 +750,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CALL_BUILT_IN: { - txt += " call-built-in "; int argc = code[ip + 2]; @@ -807,8 +759,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String txt += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(3 + i); } txt += ")"; @@ -817,7 +770,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_CALL_SELF_BASE: { - txt += " call-self-base "; int argc = code[ip + 2]; @@ -827,8 +779,9 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String txt += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { txt += ", "; + } txt += DADDR(3 + i); } txt += ")"; @@ -837,13 +790,11 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_YIELD: { - txt += " yield "; incr = 1; } break; case GDScriptFunction::OPCODE_YIELD_SIGNAL: { - txt += " yield_signal "; txt += DADDR(1); txt += ","; @@ -851,13 +802,11 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String incr = 3; } break; case GDScriptFunction::OPCODE_YIELD_RESUME: { - txt += " yield resume: "; txt += DADDR(1); incr = 2; } break; case GDScriptFunction::OPCODE_JUMP: { - txt += " jump "; txt += itos(code[ip + 1]); @@ -865,7 +814,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_JUMP_IF: { - txt += " jump-if "; txt += DADDR(1); txt += " to "; @@ -874,7 +822,6 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String incr = 3; } break; case GDScriptFunction::OPCODE_JUMP_IF_NOT: { - txt += " jump-if-not "; txt += DADDR(1); txt += " to "; @@ -883,12 +830,10 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String incr = 3; } break; case GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT: { - txt += " jump-to-default-argument "; incr = 1; } break; case GDScriptFunction::OPCODE_RETURN: { - txt += " return "; txt += DADDR(1); @@ -896,33 +841,29 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } break; case GDScriptFunction::OPCODE_ITERATE_BEGIN: { - txt += " for-init " + DADDR(4) + " in " + DADDR(2) + " counter " + DADDR(1) + " end " + itos(code[ip + 3]); incr += 5; } break; case GDScriptFunction::OPCODE_ITERATE: { - txt += " for-loop " + DADDR(4) + " in " + DADDR(2) + " counter " + DADDR(1) + " end " + itos(code[ip + 3]); incr += 5; } break; case GDScriptFunction::OPCODE_LINE: { - int line = code[ip + 1] - 1; - if (line >= 0 && line < p_code.size()) + if (line >= 0 && line < p_code.size()) { txt = "\n" + itos(line + 1) + ": " + p_code[line] + "\n"; - else + } else { txt = ""; + } incr += 2; } break; case GDScriptFunction::OPCODE_END: { - txt += " end"; incr += 1; } break; case GDScriptFunction::OPCODE_ASSERT: { - txt += " assert "; txt += DADDR(1); incr += 2; @@ -931,33 +872,32 @@ static void _disassemble_class(const Ref<GDScript> &p_class, const Vector<String } if (incr == 0) { - ERR_BREAK_MSG(true, "Unhandled opcode: " + itos(code[ip])); } ip += incr; - if (txt != "") + if (txt != "") { print_line(txt); + } } } } MainLoop *test(TestType p_type) { - List<String> cmdlargs = OS::get_singleton()->get_cmdline_args(); if (cmdlargs.empty()) { - return NULL; + return nullptr; } String test = cmdlargs.back()->get(); if (!test.ends_with(".gd") && !test.ends_with(".gdc")) { print_line("This test expects a path to a GDScript file as its last parameter. Got: " + test); - return NULL; + return nullptr; } FileAccess *fa = FileAccess::open(test, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!fa, NULL, "Could not open file: " + test); + ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test); Vector<uint8_t> buf; int flen = fa->get_len(); @@ -972,40 +912,38 @@ MainLoop *test(TestType p_type) { int last = 0; for (int i = 0; i <= code.length(); i++) { - if (code[i] == '\n' || code[i] == 0) { - lines.push_back(code.substr(last, i - last)); last = i + 1; } } if (p_type == TEST_TOKENIZER) { - GDScriptTokenizerText tk; tk.set_code(code); int line = -1; while (tk.get_token() != GDScriptTokenizer::TK_EOF) { - String text; - if (tk.get_token() == GDScriptTokenizer::TK_IDENTIFIER) + if (tk.get_token() == GDScriptTokenizer::TK_IDENTIFIER) { text = "'" + tk.get_token_identifier() + "' (identifier)"; - else if (tk.get_token() == GDScriptTokenizer::TK_CONSTANT) { + } else if (tk.get_token() == GDScriptTokenizer::TK_CONSTANT) { const Variant &c = tk.get_token_constant(); - if (c.get_type() == Variant::STRING) + if (c.get_type() == Variant::STRING) { text = "\"" + String(c) + "\""; - else + } else { text = c; + } text = text + " (" + Variant::get_type_name(c.get_type()) + " constant)"; - } else if (tk.get_token() == GDScriptTokenizer::TK_ERROR) + } else if (tk.get_token() == GDScriptTokenizer::TK_ERROR) { text = "ERROR: " + tk.get_token_error(); - else if (tk.get_token() == GDScriptTokenizer::TK_NEWLINE) + } else if (tk.get_token() == GDScriptTokenizer::TK_NEWLINE) { text = "newline (" + itos(tk.get_token_line()) + ") + indent: " + itos(tk.get_token_line_indent()); - else if (tk.get_token() == GDScriptTokenizer::TK_BUILT_IN_FUNC) + } else if (tk.get_token() == GDScriptTokenizer::TK_BUILT_IN_FUNC) { text = "'" + String(GDScriptFunctions::get_func_name(tk.get_token_built_in_func())) + "' (built-in function)"; - else + } else { text = tk.get_token_name(tk.get_token()); + } if (tk.get_token_line() != line) { int from = line + 1; @@ -1024,31 +962,29 @@ MainLoop *test(TestType p_type) { } if (p_type == TEST_PARSER) { - GDScriptParser parser; Error err = parser.parse(code); if (err) { print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error()); memdelete(fa); - return NULL; + return nullptr; } const GDScriptParser::Node *root = parser.get_parse_tree(); - ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, NULL); + ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, nullptr); const GDScriptParser::ClassNode *cnode = static_cast<const GDScriptParser::ClassNode *>(root); _parser_show_class(cnode, 0, lines); } if (p_type == TEST_COMPILER) { - GDScriptParser parser; Error err = parser.parse(code); if (err) { print_line("Parse Error:\n" + itos(parser.get_error_line()) + ":" + itos(parser.get_error_column()) + ":" + parser.get_error()); memdelete(fa); - return NULL; + return nullptr; } Ref<GDScript> gds; @@ -1057,15 +993,13 @@ MainLoop *test(TestType p_type) { GDScriptCompiler gdc; err = gdc.compile(&parser, gds.ptr()); if (err) { - print_line("Compile Error:\n" + itos(gdc.get_error_line()) + ":" + itos(gdc.get_error_column()) + ":" + gdc.get_error()); - return NULL; + return nullptr; } Ref<GDScript> current = gds; while (current.is_valid()) { - print_line("** CLASS **"); _disassemble_class(current, lines); @@ -1073,7 +1007,6 @@ MainLoop *test(TestType p_type) { } } else if (p_type == TEST_BYTECODE) { - Vector<uint8_t> buf2 = GDScriptTokenizerBuffer::parse_code_string(code); String dst = test.get_basename() + ".gdc"; FileAccess *fw = FileAccess::open(dst, FileAccess::WRITE); @@ -1083,8 +1016,9 @@ MainLoop *test(TestType p_type) { memdelete(fa); - return NULL; + return nullptr; } + } // namespace TestGDScript #else @@ -1093,8 +1027,9 @@ namespace TestGDScript { MainLoop *test(TestType p_type) { ERR_PRINT("The GDScript module is disabled, therefore GDScript tests cannot be used."); - return NULL; + return nullptr; } + } // namespace TestGDScript #endif diff --git a/main/tests/test_gui.cpp b/main/tests/test_gui.cpp index c5c8917a51..d46a13d2c0 100644 --- a/main/tests/test_gui.cpp +++ b/main/tests/test_gui.cpp @@ -59,14 +59,11 @@ namespace TestGUI { class TestMainLoop : public SceneTree { - public: virtual void request_quit() { - quit(); } virtual void init() { - SceneTree::init(); Panel *frame = memnew(Panel); @@ -266,9 +263,9 @@ public: }; MainLoop *test() { - return memnew(TestMainLoop); } + } // namespace TestGUI #endif diff --git a/main/tests/test_main.cpp b/main/tests/test_main.cpp index a9a671e2f1..0bb8367240 100644 --- a/main/tests/test_main.cpp +++ b/main/tests/test_main.cpp @@ -35,6 +35,7 @@ #ifdef DEBUG_ENABLED #include "test_astar.h" +#include "test_class_db.h" #include "test_gdscript.h" #include "test_gui.h" #include "test_math.h" @@ -47,7 +48,6 @@ #include "test_string.h" const char **tests_get_names() { - static const char *test_names[] = { "string", "math", @@ -55,6 +55,7 @@ const char **tests_get_names() { "physics_3d", "render", "oa_hash_map", + "class_db", "gui", "shaderlang", "gd_tokenizer", @@ -63,104 +64,91 @@ const char **tests_get_names() { "gd_bytecode", "ordered_hash_map", "astar", - NULL + nullptr }; return test_names; } MainLoop *test_main(String p_test, const List<String> &p_args) { - if (p_test == "string") { - return TestString::test(); } if (p_test == "math") { - return TestMath::test(); } if (p_test == "physics_2d") { - return TestPhysics2D::test(); } if (p_test == "physics_3d") { - return TestPhysics3D::test(); } if (p_test == "render") { - return TestRender::test(); } if (p_test == "oa_hash_map") { - return TestOAHashMap::test(); } + if (p_test == "class_db") { + return TestClassDB::test(); + } + #ifndef _3D_DISABLED if (p_test == "gui") { - return TestGUI::test(); } #endif if (p_test == "shaderlang") { - return TestShaderLang::test(); } if (p_test == "gd_tokenizer") { - return TestGDScript::test(TestGDScript::TEST_TOKENIZER); } if (p_test == "gd_parser") { - return TestGDScript::test(TestGDScript::TEST_PARSER); } if (p_test == "gd_compiler") { - return TestGDScript::test(TestGDScript::TEST_COMPILER); } if (p_test == "gd_bytecode") { - return TestGDScript::test(TestGDScript::TEST_BYTECODE); } if (p_test == "ordered_hash_map") { - return TestOrderedHashMap::test(); } if (p_test == "astar") { - return TestAStar::test(); } print_line("Unknown test: " + p_test); - return NULL; + return nullptr; } #else const char **tests_get_names() { - static const char *test_names[] = { - NULL + nullptr }; return test_names; } MainLoop *test_main(String p_test, const List<String> &p_args) { - - return NULL; + return nullptr; } #endif diff --git a/main/tests/test_math.cpp b/main/tests/test_math.cpp index 29fa5e73a7..9e159798bb 100644 --- a/main/tests/test_math.cpp +++ b/main/tests/test_math.cpp @@ -32,8 +32,10 @@ #include "core/math/basis.h" #include "core/math/camera_matrix.h" +#include "core/math/delaunay_3d.h" #include "core/math/math_funcs.h" #include "core/math/transform.h" +#include "core/method_ptrcall.h" #include "core/os/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" @@ -45,12 +47,9 @@ #include "scene/resources/texture.h" #include "servers/rendering/shader_language.h" -#include "core/method_ptrcall.h" - namespace TestMath { class GetClassAndNamespace { - String code; int idx; int line; @@ -77,12 +76,9 @@ class GetClassAndNamespace { }; Token get_token() { - while (true) { switch (code[idx]) { - case '\n': { - line++; idx++; break; @@ -92,37 +88,30 @@ class GetClassAndNamespace { } break; case '{': { - idx++; return TK_CURLY_BRACKET_OPEN; }; case '}': { - idx++; return TK_CURLY_BRACKET_CLOSE; }; case '[': { - idx++; return TK_BRACKET_OPEN; }; case ']': { - idx++; return TK_BRACKET_CLOSE; }; case ':': { - idx++; return TK_COLON; }; case ',': { - idx++; return TK_COMMA; }; case '.': { - idx++; return TK_PERIOD; }; @@ -134,7 +123,6 @@ class GetClassAndNamespace { continue; } break; case '/': { - switch (code[idx + 1]) { case '*': { // block comment @@ -145,7 +133,6 @@ class GetClassAndNamespace { error = true; return TK_ERROR; } else if (code[idx] == '*' && code[idx + 1] == '/') { - idx += 2; break; } else if (code[idx] == '\n') { @@ -174,7 +161,6 @@ class GetClassAndNamespace { } break; case '\'': case '"': { - CharType begin_str = code[idx]; idx++; String tk_string = String(); @@ -198,15 +184,24 @@ class GetClassAndNamespace { CharType res = 0; switch (next) { - - case 'b': res = 8; break; - case 't': res = 9; break; - case 'n': res = 10; break; - case 'f': res = 12; break; + case 'b': + res = 8; + break; + case 't': + res = 9; + break; + case 'n': + res = 10; + break; + case 'f': + res = 12; + break; case 'r': res = 13; break; - case '\"': res = '\"'; break; + case '\"': + res = '\"'; + break; case '\\': res = '\\'; break; @@ -218,8 +213,9 @@ class GetClassAndNamespace { tk_string += res; } else { - if (code[idx] == '\n') + if (code[idx] == '\n') { line++; + } tk_string += code[idx]; } idx++; @@ -231,7 +227,6 @@ class GetClassAndNamespace { } break; default: { - if (code[idx] <= 32) { idx++; break; @@ -252,11 +247,9 @@ class GetClassAndNamespace { return TK_NUMBER; } else if ((code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || code[idx] > 127) { - String id; while ((code[idx] >= 'A' && code[idx] <= 'Z') || (code[idx] >= 'a' && code[idx] <= 'z') || code[idx] > 127) { - id += code[idx]; idx++; } @@ -275,7 +268,6 @@ class GetClassAndNamespace { public: Error parse(const String &p_code, const String &p_known_class_name = String()) { - code = p_code; idx = 0; line = 0; @@ -291,7 +283,6 @@ public: int curly_stack = 0; while (!error || tk != TK_EOF) { - if (tk == TK_BRACKET_OPEN) { tk = get_token(); if (tk == TK_IDENTIFIER && String(value) == "ScriptClass") { @@ -348,8 +339,9 @@ public: tk = get_token(); } - if (error) + if (error) { return ERR_PARSE_ERROR; + } return OK; } @@ -364,7 +356,6 @@ public: }; void test_vec(Plane p_vec) { - CameraMatrix cm; cm.set_perspective(45, 1, 0, 100); Plane v0 = cm.xform4(p_vec); @@ -403,6 +394,54 @@ uint32_t ihash3(uint32_t a) { } MainLoop *test() { + { + Vector<Vector3> points; + points.push_back(Vector3(0, 0, 0)); + points.push_back(Vector3(0, 0, 1)); + points.push_back(Vector3(0, 1, 0)); + points.push_back(Vector3(0, 1, 1)); + points.push_back(Vector3(1, 1, 0)); + points.push_back(Vector3(1, 0, 0)); + points.push_back(Vector3(1, 0, 1)); + points.push_back(Vector3(1, 1, 1)); + + for (int i = 0; i < 800; i++) { + points.push_back(Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * Vector3(25, 30, 33)); + } + + Vector<Delaunay3D::OutputSimplex> os = Delaunay3D::tetrahedralize(points); + print_line("simplices in the end: " + itos(os.size())); + for (int i = 0; i < os.size(); i++) { + print_line("Simplex " + itos(i) + ": "); + print_line(points[os[i].points[0]]); + print_line(points[os[i].points[1]]); + print_line(points[os[i].points[2]]); + print_line(points[os[i].points[3]]); + } + + { + FileAccessRef f = FileAccess::open("res://bsp.obj", FileAccess::WRITE); + for (int i = 0; i < os.size(); i++) { + f->store_line("o Simplex" + itos(i)); + for (int j = 0; j < 4; j++) { + f->store_line(vformat("v %f %f %f", points[os[i].points[j]].x, points[os[i].points[j]].y, points[os[i].points[j]].z)); + } + static const int face_order[4][3] = { + { 1, 2, 3 }, + { 1, 3, 4 }, + { 1, 2, 4 }, + { 2, 3, 4 } + }; + + for (int j = 0; j < 4; j++) { + f->store_line(vformat("f %d %d %d", 4 * i + face_order[j][0], 4 * i + face_order[j][1], 4 * i + face_order[j][2])); + } + } + f->close(); + } + + return nullptr; + } { float r = 1; @@ -443,7 +482,7 @@ MainLoop *test() { float gb = (rgbe >> 9) & 0x1ff; float bb = (rgbe >> 18) & 0x1ff; float eb = (rgbe >> 27); - float mb = Math::pow(2, eb - 15.0 - 9.0); + float mb = Math::pow(2.0, eb - 15.0 - 9.0); float rd = rb * mb; float gd = gb * mb; float bd = bb * mb; @@ -475,18 +514,18 @@ MainLoop *test() { if (cmdlargs.empty()) { //try editor! - return NULL; + return nullptr; } String test = cmdlargs.back()->get(); if (test == "math") { // Not a file name but the test name, abort. // FIXME: This test is ugly as heck, needs fixing :) - return NULL; + return nullptr; } FileAccess *fa = FileAccess::open(test, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!fa, NULL, "Could not open file: " + test); + ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test); Vector<uint8_t> buf; int flen = fa->get_len(); @@ -505,26 +544,22 @@ MainLoop *test() { } { - Vector<int> hashes; List<StringName> tl; ClassDB::get_class_list(&tl); for (List<StringName>::Element *E = tl.front(); E; E = E->next()) { - Vector<uint8_t> m5b = E->get().operator String().md5_buffer(); hashes.push_back(hashes.size()); } for (int i = nearest_shift(hashes.size()); i < 20; i++) { - bool success = true; for (int s = 0; s < 10000; s++) { Set<uint32_t> existing; success = true; for (int j = 0; j < hashes.size(); j++) { - uint32_t eh = ihash2(ihash3(hashes[j] + ihash(s) + s)) & ((1 << i) - 1); if (existing.has(eh)) { success = false; @@ -538,8 +573,9 @@ MainLoop *test() { break; } } - if (success) + if (success) { break; + } } print_line("DONE"); @@ -580,7 +616,7 @@ MainLoop *test() { List<String> args; args.push_back("-l"); - Error err = OS::get_singleton()->execute("/bin/ls", args, true, NULL, &ret); + Error err = OS::get_singleton()->execute("/bin/ls", args, true, nullptr, &ret); print_line("error: " + itos(err)); print_line(ret); @@ -660,6 +696,7 @@ MainLoop *test() { print_line("scalar /=: " + v); } - return NULL; + return nullptr; } + } // namespace TestMath diff --git a/main/tests/test_oa_hash_map.cpp b/main/tests/test_oa_hash_map.cpp index ac53f124d2..9182f66b61 100644 --- a/main/tests/test_oa_hash_map.cpp +++ b/main/tests/test_oa_hash_map.cpp @@ -35,8 +35,38 @@ namespace TestOAHashMap { -MainLoop *test() { +struct CountedItem { + static int count; + + int id = -1; + bool destroyed = false; + + CountedItem() { + count++; + } + + CountedItem(int p_id) : + id(p_id) { + count++; + } + + CountedItem(const CountedItem &p_other) : + id(p_other.id) { + count++; + } + + CountedItem &operator=(const CountedItem &p_other) = default; + + ~CountedItem() { + CRASH_COND(destroyed); + count--; + destroyed = true; + } +}; + +int CountedItem::count; +MainLoop *test() { OS::get_singleton()->print("\n\n\nHello from test\n"); // test element tracking. @@ -71,8 +101,9 @@ MainLoop *test() { uint32_t num_elems = 0; for (int i = 0; i < 500; i++) { int tmp; - if (map.lookup(i, tmp) && tmp == i * 2) + if (map.lookup(i, tmp) && tmp == i * 2) { num_elems++; + } } OS::get_singleton()->print("elements %d == %d.\n", map.get_num_elements(), num_elems); @@ -105,8 +136,9 @@ MainLoop *test() { keys[i] = Math::rand(); map.set(keys[i], dummy); - if (!map.lookup(keys[i], dummy)) + if (!map.lookup(keys[i], dummy)) { OS::get_singleton()->print("could not find 0x%X despite it was just inserted!\n", unsigned(keys[i])); + } } // check whether the keys are still present @@ -122,7 +154,6 @@ MainLoop *test() { // regression test / test for issue related to #31402 { - OS::get_singleton()->print("test for issue #31402 started...\n"); const int num_test_values = 12; @@ -152,6 +183,117 @@ MainLoop *test() { map.set(5, 1); } - return NULL; + // test memory management of items, should not crash or leak items + { + // Exercise different patterns of removal + for (int i = 0; i < 4; ++i) { + { + OAHashMap<String, CountedItem> map; + int id = 0; + for (int j = 0; j < 100; ++j) { + map.insert(itos(j), CountedItem(id)); + } + if (i <= 1) { + for (int j = 0; j < 100; ++j) { + map.remove(itos(j)); + } + } + if (i % 2 == 0) { + map.clear(); + } + } + + if (CountedItem::count != 0) { + OS::get_singleton()->print("%d != 0 (not performing the other test sub-cases, breaking...)\n", CountedItem::count); + break; + } + } + } + + // Test map with 0 capacity. + { + OAHashMap<int, String> original_map(0); + original_map.set(1, "1"); + OS::get_singleton()->print("OAHashMap 0 capacity initialization passed.\n"); + } + + // Test copy constructor. + { + OAHashMap<int, String> original_map; + original_map.set(1, "1"); + original_map.set(2, "2"); + original_map.set(3, "3"); + original_map.set(4, "4"); + original_map.set(5, "5"); + + OAHashMap<int, String> map_copy(original_map); + + bool pass = true; + for ( + OAHashMap<int, String>::Iterator it = original_map.iter(); + it.valid; + it = original_map.next_iter(it)) { + if (map_copy.lookup_ptr(*it.key) == nullptr) { + pass = false; + } + if (*it.value != *map_copy.lookup_ptr(*it.key)) { + pass = false; + } + } + if (pass) { + OS::get_singleton()->print("OAHashMap copy constructor test passed.\n"); + } else { + OS::get_singleton()->print("OAHashMap copy constructor test FAILED.\n"); + } + + map_copy.set(1, "Random String"); + if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) { + OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test FAILED.\n"); + } else { + OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test passed.\n"); + } + } + + // Test assign operator. + { + OAHashMap<int, String> original_map; + original_map.set(1, "1"); + original_map.set(2, "2"); + original_map.set(3, "3"); + original_map.set(4, "4"); + original_map.set(5, "5"); + + OAHashMap<int, String> map_copy(100000); + map_copy.set(1, "Just a string."); + map_copy = original_map; + + bool pass = true; + for ( + OAHashMap<int, String>::Iterator it = map_copy.iter(); + it.valid; + it = map_copy.next_iter(it)) { + if (original_map.lookup_ptr(*it.key) == nullptr) { + pass = false; + } + if (*it.value != *original_map.lookup_ptr(*it.key)) { + pass = false; + } + } + if (pass) { + OS::get_singleton()->print("OAHashMap assign operation test passed.\n"); + } else { + OS::get_singleton()->print("OAHashMap assign operation test FAILED.\n"); + } + + map_copy.set(1, "Random String"); + if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) { + OS::get_singleton()->print("OAHashMap assign operation atomic copy test FAILED.\n"); + } else { + OS::get_singleton()->print("OAHashMap assign operation atomic copy test passed.\n"); + } + } + + return nullptr; } + } // namespace TestOAHashMap diff --git a/main/tests/test_ordered_hash_map.cpp b/main/tests/test_ordered_hash_map.cpp index a5553217e2..d18a3784be 100644 --- a/main/tests/test_ordered_hash_map.cpp +++ b/main/tests/test_ordered_hash_map.cpp @@ -130,7 +130,7 @@ bool test_const_iteration() { return test_const_iteration(map); } -typedef bool (*TestFunc)(void); +typedef bool (*TestFunc)(); TestFunc test_funcs[] = { @@ -141,21 +141,22 @@ TestFunc test_funcs[] = { test_size, test_iteration, test_const_iteration, - 0 + nullptr }; MainLoop *test() { - int count = 0; int passed = 0; while (true) { - if (!test_funcs[count]) + if (!test_funcs[count]) { break; + } bool pass = test_funcs[count](); - if (pass) + if (pass) { passed++; + } OS::get_singleton()->print("\t%s\n", pass ? "PASS" : "FAILED"); count++; @@ -168,6 +169,7 @@ MainLoop *test() { OS::get_singleton()->print("Passed %i of %i tests\n", passed, count); - return NULL; + return nullptr; } + } // namespace TestOrderedHashMap diff --git a/main/tests/test_physics_2d.cpp b/main/tests/test_physics_2d.cpp index 6feff3b0a9..6cb9bf7b60 100644 --- a/main/tests/test_physics_2d.cpp +++ b/main/tests/test_physics_2d.cpp @@ -44,7 +44,6 @@ static const unsigned char convex_png[] = { }; class TestPhysics2DMainLoop : public MainLoop { - GDCLASS(TestPhysics2DMainLoop, MainLoop); RID circle_img; @@ -58,7 +57,6 @@ class TestPhysics2DMainLoop : public MainLoop { Vector2 ray_from, ray_to; struct BodyShapeData { - RID image; RID shape; }; @@ -72,13 +70,10 @@ class TestPhysics2DMainLoop : public MainLoop { // SEGMENT { - Vector<uint8_t> pixels; pixels.resize(32 * 2 * 2); for (int i = 0; i < 2; i++) { - for (int j = 0; j < 32; j++) { - pixels.set(i * 32 * 2 + j * 2 + 0, (j == 0) ? 255 : 0); pixels.set(i * 32 * 2 + j * 2 + 1, 255); } @@ -97,13 +92,10 @@ class TestPhysics2DMainLoop : public MainLoop { // CIRCLE { - Vector<uint8_t> pixels; pixels.resize(32 * 32 * 2); for (int i = 0; i < 32; i++) { - for (int j = 0; j < 32; j++) { - bool black = Vector2(i - 16, j - 16).length_squared() < 16 * 16; pixels.set(i * 32 * 2 + j * 2 + 0, (i == 16 || j == 16) ? 255 : 0); @@ -124,13 +116,10 @@ class TestPhysics2DMainLoop : public MainLoop { // BOX { - Vector<uint8_t> pixels; pixels.resize(32 * 32 * 2); for (int i = 0; i < 32; i++) { - for (int j = 0; j < 32; j++) { - bool black = i > 0 && i < 31 && j > 0 && j < 31; pixels.set(i * 32 * 2 + j * 2 + 0, black ? 0 : 255); @@ -151,13 +140,10 @@ class TestPhysics2DMainLoop : public MainLoop { // CAPSULE { - Vector<uint8_t> pixels; pixels.resize(32 * 64 * 2); for (int i = 0; i < 64; i++) { - for (int j = 0; j < 32; j++) { - int si = i > 48 ? i - 32 : (i < 16 ? i : 16); bool black = Vector2(si - 16, j - 16).length_squared() < 16 * 16; @@ -179,7 +165,6 @@ class TestPhysics2DMainLoop : public MainLoop { // CONVEX { - Ref<Image> image = memnew(Image(convex_png)); body_shape_data[PhysicsServer2D::SHAPE_CONVEX_POLYGON].image = vs->texture_2d_create(image); @@ -202,7 +187,6 @@ class TestPhysics2DMainLoop : public MainLoop { } void _do_ray_query() { - /* PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); ps->query_intersection_segment(ray_query,ray_from,ray_to); @@ -211,13 +195,10 @@ class TestPhysics2DMainLoop : public MainLoop { protected: void input_event(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - if (mb->is_pressed()) { - Point2 p(mb->get_position().x, mb->get_position().y); if (mb->get_button_index() == 1) { @@ -233,7 +214,6 @@ protected: Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - Point2 p = mm->get_position(); if (mm->get_button_mask() & BUTTON_MASK_LEFT) { @@ -247,7 +227,6 @@ protected: } RID _add_body(PhysicsServer2D::ShapeType p_shape, const Transform2D &p_xform) { - RenderingServer *vs = RenderingServer::get_singleton(); PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); @@ -272,7 +251,6 @@ protected: } void _add_plane(const Vector2 &p_normal, real_t p_d) { - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); Array arr; @@ -289,7 +267,6 @@ protected: } void _add_concave(const Vector<Vector2> &p_points, const Transform2D &p_xform = Transform2D()) { - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); RenderingServer *vs = RenderingServer::get_singleton(); @@ -315,7 +292,6 @@ protected: } void _ray_query_callback(const RID &p_rid, ObjectID p_id, int p_shape, const Vector2 &p_point, const Vector2 &p_normal) { - Vector2 ray_end; if (p_rid.is_valid()) { @@ -328,19 +304,18 @@ protected: vs->canvas_item_clear(ray); vs->canvas_item_add_line(ray, ray_from, ray_end, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2); - if (p_rid.is_valid()) + if (p_rid.is_valid()) { vs->canvas_item_add_line(ray, ray_end, ray_end + p_normal * 20, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2); + } } static void _bind_methods() { - ClassDB::bind_method(D_METHOD("_body_moved"), &TestPhysics2DMainLoop::_body_moved); ClassDB::bind_method(D_METHOD("_ray_query_callback"), &TestPhysics2DMainLoop::_ray_query_callback); } public: virtual void init() { - RenderingServer *vs = RenderingServer::get_singleton(); PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); @@ -351,7 +326,6 @@ public: ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, 98); { - RID vp = vs->viewport_create(); canvas = vs->canvas_create(); @@ -377,7 +351,6 @@ public: _create_body_shape_data(); for (int i = 0; i < 32; i++) { - PhysicsServer2D::ShapeType types[4] = { PhysicsServer2D::SHAPE_CIRCLE, PhysicsServer2D::SHAPE_CAPSULE, @@ -402,7 +375,6 @@ public: Vector<Point2> parr; for (int i = 0; i < 30; i++) { - Point2 p(i * 60, Math::randf() * 70 + 340); if (i > 0) { parr.push_back(prev); @@ -418,7 +390,6 @@ public: } virtual bool idle(float p_time) { - return false; } virtual void finish() { @@ -430,7 +401,7 @@ public: namespace TestPhysics2D { MainLoop *test() { - return memnew(TestPhysics2DMainLoop); } + } // namespace TestPhysics2D diff --git a/main/tests/test_physics_3d.cpp b/main/tests/test_physics_3d.cpp index 2d208ee317..fe54ece98e 100644 --- a/main/tests/test_physics_3d.cpp +++ b/main/tests/test_physics_3d.cpp @@ -41,7 +41,6 @@ #include "servers/rendering_server.h" class TestPhysics3DMainLoop : public MainLoop { - GDCLASS(TestPhysics3DMainLoop, MainLoop); enum { @@ -69,7 +68,6 @@ class TestPhysics3DMainLoop : public MainLoop { Map<PhysicsServer3D::ShapeType, RID> type_mesh_map; void body_changed_transform(Object *p_state, RID p_visual_instance) { - PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; RenderingServer *vs = RenderingServer::get_singleton(); Transform t = state->get_transform(); @@ -80,12 +78,10 @@ class TestPhysics3DMainLoop : public MainLoop { protected: static void _bind_methods() { - ClassDB::bind_method("body_changed_transform", &TestPhysics3DMainLoop::body_changed_transform); } RID create_body(PhysicsServer3D::ShapeType p_shape, PhysicsServer3D::BodyMode p_body, const Transform p_location, bool p_active_default = true, const Transform &p_shape_xform = Transform()) { - RenderingServer *vs = RenderingServer::get_singleton(); PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); @@ -101,14 +97,12 @@ protected: bodies.push_back(body); if (p_body == PhysicsServer3D::BODY_MODE_STATIC) { - vs->instance_set_transform(mesh_instance, p_location); } return body; } RID create_static_plane(const Plane &p_plane) { - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); RID world_margin_shape = ps->shape_create(PhysicsServer3D::SHAPE_PLANE); @@ -122,7 +116,6 @@ protected: } void configure_body(RID p_body, float p_mass, float p_friction, float p_bounce) { - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_MASS, p_mass); ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_FRICTION, p_friction); @@ -130,7 +123,6 @@ protected: } void init_shapes() { - RenderingServer *vs = RenderingServer::get_singleton(); PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); @@ -188,7 +180,6 @@ protected: } void make_trimesh(Vector<Vector3> p_faces, const Transform &p_xform = Transform()) { - RenderingServer *vs = RenderingServer::get_singleton(); PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); RID trimesh_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON); @@ -196,7 +187,6 @@ protected: p_faces = ps->shape_get_data(trimesh_shape); // optimized one Vector<Vector3> normals; // for drawing for (int i = 0; i < p_faces.size() / 3; i++) { - Plane p(p_faces[i * 3 + 0], p_faces[i * 3 + 1], p_faces[i * 3 + 2]); normals.push_back(p.normal); normals.push_back(p.normal); @@ -222,17 +212,14 @@ protected: } void make_grid(int p_width, int p_height, float p_cellsize, float p_cellheight, const Transform &p_xform = Transform()) { - Vector<Vector<float>> grid; grid.resize(p_width); for (int i = 0; i < p_width; i++) { - grid.write[i].resize(p_height); for (int j = 0; j < p_height; j++) { - grid.write[i].write[j] = 1.0 + Math::random(-p_cellheight, p_cellheight); } } @@ -240,9 +227,7 @@ protected: Vector<Vector3> faces; for (int i = 1; i < p_width; i++) { - for (int j = 1; j < p_height; j++) { - #define MAKE_VERTEX(m_x, m_z) \ faces.push_back(Vector3((m_x - p_width / 2) * p_cellsize, grid[m_x][m_z], (m_z - p_height / 2) * p_cellsize)) @@ -261,21 +246,17 @@ protected: public: virtual void input_event(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid() && mm->get_button_mask() & 4) { - ofs_y -= mm->get_relative().y / 200.0; ofs_x += mm->get_relative().x / 200.0; } if (mm.is_valid() && mm->get_button_mask() & 1) { - float y = -mm->get_relative().y / 20.0; float x = mm->get_relative().x / 20.0; if (mover.is_valid()) { - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); Transform t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); t.origin += Vector3(x, y, 0); @@ -286,11 +267,9 @@ public: } virtual void request_quit() { - quit = true; } virtual void init() { - ofs_x = ofs_y = 0; init_shapes(); @@ -332,7 +311,6 @@ public: quit = false; } virtual bool iteration(float p_time) { - if (mover.is_valid()) { static float joy_speed = 10; PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); @@ -360,7 +338,6 @@ public: } void test_character() { - RenderingServer *vs = RenderingServer::get_singleton(); PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); @@ -393,9 +370,7 @@ public: } void test_fall() { - for (int i = 0; i < 35; i++) { - static const PhysicsServer3D::ShapeType shape_idx[] = { PhysicsServer3D::SHAPE_CAPSULE, PhysicsServer3D::SHAPE_BOX, @@ -417,7 +392,6 @@ public: } void test_activate() { - create_body(PhysicsServer3D::SHAPE_BOX, PhysicsServer3D::BODY_MODE_RIGID, Transform(Basis(), Vector3(0, 2, 0)), true); create_static_plane(Plane(Vector3(0, 1, 0), -1)); } @@ -433,7 +407,7 @@ public: namespace TestPhysics3D { MainLoop *test() { - return memnew(TestPhysics3DMainLoop); } + } // namespace TestPhysics3D diff --git a/main/tests/test_render.cpp b/main/tests/test_render.cpp index bcfcf61e25..afc09374b9 100644 --- a/main/tests/test_render.cpp +++ b/main/tests/test_render.cpp @@ -44,7 +44,6 @@ namespace TestRender { class TestMainLoop : public MainLoop { - RID test_cube; RID instance; RID camera; @@ -53,7 +52,6 @@ class TestMainLoop : public MainLoop { RID scenario; struct InstanceInfo { - RID instance; Transform base; Vector3 rot_axis; @@ -67,13 +65,12 @@ class TestMainLoop : public MainLoop { protected: public: virtual void input_event(const Ref<InputEvent> &p_event) { - - if (p_event->is_pressed()) + if (p_event->is_pressed()) { quit = true; + } } virtual void init() { - print_line("INITIALIZING TEST RENDER"); RenderingServer *vs = RenderingServer::get_singleton(); test_cube = vs->get_test_cube(); @@ -144,7 +141,6 @@ public: }; for (int i = 0; i < object_count; i++) { - InstanceInfo ii; ii.instance = vs->instance_create2(test_cube, scenario); @@ -205,7 +201,6 @@ public: quit = false; } virtual bool iteration(float p_time) { - RenderingServer *vs = RenderingServer::get_singleton(); //Transform t; //t.rotate(Vector3(0, 1, 0), ofs); @@ -217,7 +212,6 @@ public: //return quit; for (List<InstanceInfo>::Element *E = instances.front(); E; E = E->next()) { - Transform pre(Basis(E->get().rot_axis, ofs), Vector3()); vs->instance_set_transform(E->get().instance, pre * E->get().base); /* @@ -240,7 +234,7 @@ public: }; MainLoop *test() { - return memnew(TestMainLoop); } + } // namespace TestRender diff --git a/main/tests/test_shader_lang.cpp b/main/tests/test_shader_lang.cpp index dd525d7653..34ee3e3210 100644 --- a/main/tests/test_shader_lang.cpp +++ b/main/tests/test_shader_lang.cpp @@ -44,7 +44,6 @@ typedef ShaderLanguage SL; namespace TestShaderLang { static String _mktab(int p_level) { - String tb; for (int i = 0; i < p_level; i++) { tb += "\t"; @@ -54,61 +53,74 @@ static String _mktab(int p_level) { } static String _typestr(SL::DataType p_type) { - return ShaderLanguage::get_datatype_name(p_type); } static String _prestr(SL::DataPrecision p_pres) { - switch (p_pres) { - case SL::PRECISION_LOWP: return "lowp "; - case SL::PRECISION_MEDIUMP: return "mediump "; - case SL::PRECISION_HIGHP: return "highp "; - case SL::PRECISION_DEFAULT: return ""; + case SL::PRECISION_LOWP: + return "lowp "; + case SL::PRECISION_MEDIUMP: + return "mediump "; + case SL::PRECISION_HIGHP: + return "highp "; + case SL::PRECISION_DEFAULT: + return ""; } return ""; } static String _opstr(SL::Operator p_op) { - return ShaderLanguage::get_operator_text(p_op); } static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) { - switch (p_type) { - case SL::TYPE_BOOL: return p_values[0].boolean ? "true" : "false"; - case SL::TYPE_BVEC2: return String() + "bvec2(" + (p_values[0].boolean ? "true" : "false") + (p_values[1].boolean ? "true" : "false") + ")"; - case SL::TYPE_BVEC3: return String() + "bvec3(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + ")"; - case SL::TYPE_BVEC4: return String() + "bvec4(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + "," + (p_values[3].boolean ? "true" : "false") + ")"; - case SL::TYPE_INT: return rtos(p_values[0].sint); - case SL::TYPE_IVEC2: return String() + "ivec2(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + ")"; - case SL::TYPE_IVEC3: return String() + "ivec3(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + ")"; - case SL::TYPE_IVEC4: return String() + "ivec4(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + "," + rtos(p_values[3].sint) + ")"; - case SL::TYPE_UINT: return rtos(p_values[0].real); - case SL::TYPE_UVEC2: return String() + "uvec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; - case SL::TYPE_UVEC3: return String() + "uvec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; - case SL::TYPE_UVEC4: return String() + "uvec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; - case SL::TYPE_FLOAT: return rtos(p_values[0].real); - case SL::TYPE_VEC2: return String() + "vec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; - case SL::TYPE_VEC3: return String() + "vec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; - case SL::TYPE_VEC4: return String() + "vec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; - default: ERR_FAIL_V(String()); + case SL::TYPE_BOOL: + return p_values[0].boolean ? "true" : "false"; + case SL::TYPE_BVEC2: + return String() + "bvec2(" + (p_values[0].boolean ? "true" : "false") + (p_values[1].boolean ? "true" : "false") + ")"; + case SL::TYPE_BVEC3: + return String() + "bvec3(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + ")"; + case SL::TYPE_BVEC4: + return String() + "bvec4(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + "," + (p_values[3].boolean ? "true" : "false") + ")"; + case SL::TYPE_INT: + return rtos(p_values[0].sint); + case SL::TYPE_IVEC2: + return String() + "ivec2(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + ")"; + case SL::TYPE_IVEC3: + return String() + "ivec3(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + ")"; + case SL::TYPE_IVEC4: + return String() + "ivec4(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + "," + rtos(p_values[3].sint) + ")"; + case SL::TYPE_UINT: + return rtos(p_values[0].real); + case SL::TYPE_UVEC2: + return String() + "uvec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; + case SL::TYPE_UVEC3: + return String() + "uvec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; + case SL::TYPE_UVEC4: + return String() + "uvec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; + case SL::TYPE_FLOAT: + return rtos(p_values[0].real); + case SL::TYPE_VEC2: + return String() + "vec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; + case SL::TYPE_VEC3: + return String() + "vec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; + case SL::TYPE_VEC4: + return String() + "vec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; + default: + ERR_FAIL_V(String()); } } static String dump_node_code(SL::Node *p_node, int p_level) { - String code; switch (p_node->type) { - case SL::Node::TYPE_SHADER: { - SL::ShaderNode *pnode = (SL::ShaderNode *)p_node; for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) { - String ucode = "uniform "; ucode += _prestr(E->get().precision); ucode += _typestr(E->get().type); @@ -128,14 +140,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) { "white" }; - if (E->get().hint) + if (E->get().hint) { ucode += " : " + String(hint_name[E->get().hint]); + } code += ucode + "\n"; } for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) { - String vcode = "varying "; vcode += _prestr(E->get().precision); vcode += _typestr(E->get().type); @@ -144,15 +156,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) { code += vcode + "\n"; } for (int i = 0; i < pnode->functions.size(); i++) { - SL::FunctionNode *fnode = pnode->functions[i].function; String header; header = _typestr(fnode->return_type) + " " + fnode->name + "("; for (int j = 0; j < fnode->arguments.size(); j++) { - - if (j > 0) + if (j > 0) { header += ", "; + } header += _prestr(fnode->arguments[j].precision) + _typestr(fnode->arguments[j].type) + " " + fnode->arguments[j].name; } @@ -164,10 +175,8 @@ static String dump_node_code(SL::Node *p_node, int p_level) { //code+=dump_node_code(pnode->body,p_level); } break; case SL::Node::TYPE_STRUCT: { - } break; case SL::Node::TYPE_FUNCTION: { - } break; case SL::Node::TYPE_BLOCK: { SL::BlockNode *bnode = (SL::BlockNode *)p_node; @@ -175,12 +184,10 @@ static String dump_node_code(SL::Node *p_node, int p_level) { //variables code += _mktab(p_level - 1) + "{\n"; for (Map<StringName, SL::BlockNode::Variable>::Element *E = bnode->variables.front(); E; E = E->next()) { - code += _mktab(p_level) + _prestr(E->get().precision) + _typestr(E->get().type) + " " + E->key() + ";\n"; } for (int i = 0; i < bnode->statements.size(); i++) { - String scode = dump_node_code(bnode->statements[i], p_level); if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW) { @@ -219,7 +226,6 @@ static String dump_node_code(SL::Node *p_node, int p_level) { SL::OperatorNode *onode = (SL::OperatorNode *)p_node; switch (onode->op) { - case SL::OP_ASSIGN: case SL::OP_ASSIGN_ADD: case SL::OP_ASSIGN_SUB: @@ -248,14 +254,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) { case SL::OP_CONSTRUCT: code = dump_node_code(onode->arguments[0], p_level) + "("; for (int i = 1; i < onode->arguments.size(); i++) { - if (i > 1) + if (i > 1) { code += ", "; + } code += dump_node_code(onode->arguments[i], p_level); } code += ")"; break; default: { - code = "(" + dump_node_code(onode->arguments[0], p_level) + _opstr(onode->op) + dump_node_code(onode->arguments[1], p_level) + ")"; break; } @@ -265,17 +271,14 @@ static String dump_node_code(SL::Node *p_node, int p_level) { case SL::Node::TYPE_CONTROL_FLOW: { SL::ControlFlowNode *cfnode = (SL::ControlFlowNode *)p_node; if (cfnode->flow_op == SL::FLOW_OP_IF) { - code += _mktab(p_level) + "if (" + dump_node_code(cfnode->expressions[0], p_level) + ")\n"; code += dump_node_code(cfnode->blocks[0], p_level + 1); if (cfnode->blocks.size() == 2) { - code += _mktab(p_level) + "else\n"; code += dump_node_code(cfnode->blocks[1], p_level + 1); } } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) { - if (cfnode->blocks.size()) { code = "return " + dump_node_code(cfnode->blocks[0], p_level); } else { @@ -295,7 +298,6 @@ static String dump_node_code(SL::Node *p_node, int p_level) { } static Error recreate_code(void *p_str, SL::ShaderNode *p_program) { - String *str = (String *)p_str; *str = dump_node_code(p_program, 0); @@ -304,13 +306,12 @@ static Error recreate_code(void *p_str, SL::ShaderNode *p_program) { } MainLoop *test() { - List<String> cmdlargs = OS::get_singleton()->get_cmdline_args(); if (cmdlargs.empty()) { //try editor! print_line("usage: godot -test shader_lang <shader>"); - return NULL; + return nullptr; } String test = cmdlargs.back()->get(); @@ -318,15 +319,16 @@ MainLoop *test() { FileAccess *fa = FileAccess::open(test, FileAccess::READ); if (!fa) { - ERR_FAIL_V(NULL); + ERR_FAIL_V(nullptr); } String code; while (true) { CharType c = fa->get_8(); - if (fa->eof_reached()) + if (fa->eof_reached()) { break; + } code += c; } @@ -342,18 +344,18 @@ MainLoop *test() { Set<String> types; types.insert("spatial"); - Error err = sl.compile(code, dt, rm, types); + Error err = sl.compile(code, dt, rm, types, nullptr); if (err) { - print_line("Error at line: " + rtos(sl.get_error_line()) + ": " + sl.get_error_text()); - return NULL; + return nullptr; } else { String code2; recreate_code(&code2, sl.get_shader()); print_line("code:\n\n" + code2); } - return NULL; + return nullptr; } + } // namespace TestShaderLang diff --git a/main/tests/test_string.cpp b/main/tests/test_string.cpp index 84731746fa..775c039282 100644 --- a/main/tests/test_string.cpp +++ b/main/tests/test_string.cpp @@ -45,7 +45,6 @@ namespace TestString { bool test_1() { - OS::get_singleton()->print("\n\nTest 1: Assign from cstr\n"); String s = "Hello"; @@ -57,7 +56,6 @@ bool test_1() { } bool test_2() { - OS::get_singleton()->print("\n\nTest 2: Assign from string (operator=)\n"); String s = "Dolly"; @@ -70,7 +68,6 @@ bool test_2() { } bool test_3() { - OS::get_singleton()->print("\n\nTest 3: Assign from c-string (copycon)\n"); String s("Sheep"); @@ -83,7 +80,6 @@ bool test_3() { } bool test_4() { - OS::get_singleton()->print("\n\nTest 4: Assign from c-widechar (operator=)\n"); String s(L"Give me"); @@ -95,7 +91,6 @@ bool test_4() { } bool test_5() { - OS::get_singleton()->print("\n\nTest 5: Assign from c-widechar (copycon)\n"); String s(L"Wool"); @@ -107,67 +102,72 @@ bool test_5() { } bool test_6() { - OS::get_singleton()->print("\n\nTest 6: comparisons (equal)\n"); String s = "Test Compare"; OS::get_singleton()->print("\tComparing to \"Test Compare\"\n"); - if (!(s == "Test Compare")) + if (!(s == "Test Compare")) { return false; + } - if (!(s == L"Test Compare")) + if (!(s == L"Test Compare")) { return false; + } - if (!(s == String("Test Compare"))) + if (!(s == String("Test Compare"))) { return false; + } return true; } bool test_7() { - OS::get_singleton()->print("\n\nTest 7: comparisons (unequal)\n"); String s = "Test Compare"; OS::get_singleton()->print("\tComparing to \"Test Compare\"\n"); - if (!(s != "Peanut")) + if (!(s != "Peanut")) { return false; + } - if (!(s != L"Coconut")) + if (!(s != L"Coconut")) { return false; + } - if (!(s != String("Butter"))) + if (!(s != String("Butter"))) { return false; + } return true; } bool test_8() { - OS::get_singleton()->print("\n\nTest 8: comparisons (operator<)\n"); String s = "Bees"; OS::get_singleton()->print("\tComparing to \"Bees\"\n"); - if (!(s < "Elephant")) + if (!(s < "Elephant")) { return false; + } - if (s < L"Amber") + if (s < L"Amber") { return false; + } - if (s < String("Beatrix")) + if (s < String("Beatrix")) { return false; + } return true; } bool test_9() { - OS::get_singleton()->print("\n\nTest 9: Concatenation\n"); String s; @@ -186,23 +186,24 @@ bool test_9() { } bool test_10() { - OS::get_singleton()->print("\n\nTest 10: Misc funcs (size/length/empty/etc)\n"); - if (!String("").empty()) + if (!String("").empty()) { return false; + } - if (String("Mellon").size() != 7) + if (String("Mellon").size() != 7) { return false; + } - if (String("Oranges").length() != 7) + if (String("Oranges").length() != 7) { return false; + } return true; } bool test_11() { - OS::get_singleton()->print("\n\nTest 11: Operator[]\n"); String a = "Kugar Sane"; @@ -210,32 +211,34 @@ bool test_11() { a[0] = 'S'; a[6] = 'C'; - if (a != "Sugar Cane") + if (a != "Sugar Cane") { return false; + } - if (a[1] != 'u') + if (a[1] != 'u') { return false; + } return true; } bool test_12() { - OS::get_singleton()->print("\n\nTest 12: case functions\n"); String a = "MoMoNgA"; - if (a.to_upper() != "MOMONGA") + if (a.to_upper() != "MOMONGA") { return false; + } - if (a.nocasecmp_to("momonga") != 0) + if (a.nocasecmp_to("momonga") != 0) { return false; + } return true; } bool test_13() { - OS::get_singleton()->print("\n\nTest 13: UTF8\n"); /* how can i embed UTF in here? */ @@ -252,7 +255,6 @@ bool test_13() { } bool test_14() { - OS::get_singleton()->print("\n\nTest 14: ASCII\n"); String s = L"Primero Leche"; @@ -263,7 +265,6 @@ bool test_14() { } bool test_15() { - OS::get_singleton()->print("\n\nTest 15: substr\n"); String s = "Killer Baby"; @@ -273,7 +274,6 @@ bool test_15() { } bool test_16() { - OS::get_singleton()->print("\n\nTest 16: find\n"); String s = "Pretty Woman"; @@ -281,17 +281,18 @@ bool test_16() { OS::get_singleton()->print("\t\"tty\" is at %i pos.\n", s.find("tty")); OS::get_singleton()->print("\t\"Revenge of the Monster Truck\" is at %i pos.\n", s.find("Revenge of the Monster Truck")); - if (s.find("tty") != 3) + if (s.find("tty") != 3) { return false; + } - if (s.find("Revenge of the Monster Truck") != -1) + if (s.find("Revenge of the Monster Truck") != -1) { return false; + } return true; } bool test_17() { - OS::get_singleton()->print("\n\nTest 17: find no case\n"); String s = "Pretty Whale"; @@ -299,17 +300,18 @@ bool test_17() { OS::get_singleton()->print("\t\"WHA\" is at %i pos.\n", s.findn("WHA")); OS::get_singleton()->print("\t\"Revenge of the Monster SawFish\" is at %i pos.\n", s.findn("Revenge of the Monster Truck")); - if (s.findn("WHA") != 7) + if (s.findn("WHA") != 7) { return false; + } - if (s.findn("Revenge of the Monster SawFish") != -1) + if (s.findn("Revenge of the Monster SawFish") != -1) { return false; + } return true; } bool test_18() { - OS::get_singleton()->print("\n\nTest 18: find no case\n"); String s = "Pretty Whale"; @@ -317,17 +319,18 @@ bool test_18() { OS::get_singleton()->print("\t\"WHA\" is at %i pos.\n", s.findn("WHA")); OS::get_singleton()->print("\t\"Revenge of the Monster SawFish\" is at %i pos.\n", s.findn("Revenge of the Monster Truck")); - if (s.findn("WHA") != 7) + if (s.findn("WHA") != 7) { return false; + } - if (s.findn("Revenge of the Monster SawFish") != -1) + if (s.findn("Revenge of the Monster SawFish") != -1) { return false; + } return true; } bool test_19() { - OS::get_singleton()->print("\n\nTest 19: Search & replace\n"); String s = "Happy Birthday, Anna!"; @@ -340,7 +343,6 @@ bool test_19() { } bool test_20() { - OS::get_singleton()->print("\n\nTest 20: Insertion\n"); String s = "Who is Frederic?"; @@ -353,7 +355,6 @@ bool test_20() { } bool test_21() { - OS::get_singleton()->print("\n\nTest 21: Number -> String\n"); OS::get_singleton()->print("\tPi is %f\n", 33.141593); @@ -363,7 +364,6 @@ bool test_21() { } bool test_22() { - OS::get_singleton()->print("\n\nTest 22: String -> Int\n"); static const char *nums[4] = { "1237461283", "- 22", "0", " - 1123412" }; @@ -372,15 +372,15 @@ bool test_22() { for (int i = 0; i < 4; i++) { OS::get_singleton()->print("\tString: \"%s\" as Int is %i\n", nums[i], String(nums[i]).to_int()); - if (String(nums[i]).to_int() != num[i]) + if (String(nums[i]).to_int() != num[i]) { return false; + } } return true; } bool test_23() { - OS::get_singleton()->print("\n\nTest 23: String -> Float\n"); static const char *nums[4] = { "-12348298412.2", "0.05", "2.0002", " -0.0001" }; @@ -389,15 +389,15 @@ bool test_23() { for (int i = 0; i < 4; i++) { OS::get_singleton()->print("\tString: \"%s\" as Float is %f\n", nums[i], String(nums[i]).to_double()); - if (ABS(String(nums[i]).to_double() - num[i]) > 0.00001) + if (ABS(String(nums[i]).to_double() - num[i]) > 0.00001) { return false; + } } return true; } bool test_24() { - OS::get_singleton()->print("\n\nTest 24: Slicing\n"); String s = "Mars,Jupiter,Saturn,Uranus"; @@ -407,18 +407,17 @@ bool test_24() { OS::get_singleton()->print("\tSlicing \"%ls\" by \"%s\"..\n", s.c_str(), ","); for (int i = 0; i < s.get_slice_count(","); i++) { - OS::get_singleton()->print("\t\t%i- %ls\n", i + 1, s.get_slice(",", i).c_str()); - if (s.get_slice(",", i) != slices[i]) + if (s.get_slice(",", i) != slices[i]) { return false; + } } return true; } bool test_25() { - OS::get_singleton()->print("\n\nTest 25: Erasing\n"); String s = "Josephine is such a cute girl!"; @@ -433,7 +432,6 @@ bool test_25() { } bool test_26() { - OS::get_singleton()->print("\n\nTest 26: RegEx substitution\n"); #ifndef MODULE_REGEX_ENABLED @@ -461,7 +459,6 @@ struct test_27_data { }; bool test_27() { - OS::get_singleton()->print("\n\nTest 27: begins_with\n"); test_27_data tc[] = { { "res://foobar", "res://", true }, @@ -486,7 +483,6 @@ bool test_27() { }; bool test_28() { - OS::get_singleton()->print("\n\nTest 28: sprintf\n"); bool success, state = true; @@ -822,7 +818,6 @@ bool test_28() { } bool test_29() { - bool state = true; IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334"); @@ -972,28 +967,35 @@ bool test_31() { String a = ""; success = a[0] == 0; OS::get_singleton()->print("Is 0 String[0]:, %s\n", success ? "OK" : "FAIL"); - if (!success) state = false; + if (!success) { + state = false; + } String b = "Godot"; success = b[b.size()] == 0; OS::get_singleton()->print("Is 0 String[size()]:, %s\n", success ? "OK" : "FAIL"); - if (!success) state = false; + if (!success) { + state = false; + } const String c = ""; success = c[0] == 0; OS::get_singleton()->print("Is 0 const String[0]:, %s\n", success ? "OK" : "FAIL"); - if (!success) state = false; + if (!success) { + state = false; + } const String d = "Godot"; success = d[d.size()] == 0; OS::get_singleton()->print("Is 0 const String[size()]:, %s\n", success ? "OK" : "FAIL"); - if (!success) state = false; + if (!success) { + state = false; + } return state; }; bool test_32() { - #define STRIP_TEST(x) \ { \ bool success = x; \ @@ -1071,7 +1073,7 @@ bool test_33() { OS::get_singleton()->print("\n\nTest 33: parse_utf8(null, -1)\n"); String empty; - return empty.parse_utf8(NULL, -1); + return empty.parse_utf8(nullptr, -1); } bool test_34() { @@ -1125,7 +1127,7 @@ bool test_35() { return state; } -typedef bool (*TestFunc)(void); +typedef bool (*TestFunc)(); TestFunc test_funcs[] = { @@ -1164,12 +1166,11 @@ TestFunc test_funcs[] = { test_33, test_34, test_35, - 0 + nullptr }; MainLoop *test() { - /** A character length != wchar_t may be forced, so the tests won't work */ static_assert(sizeof(CharType) == sizeof(wchar_t)); @@ -1178,11 +1179,13 @@ MainLoop *test() { int passed = 0; while (true) { - if (!test_funcs[count]) + if (!test_funcs[count]) { break; + } bool pass = test_funcs[count](); - if (pass) + if (pass) { passed++; + } OS::get_singleton()->print("\t%s\n", pass ? "PASS" : "FAILED"); count++; @@ -1195,6 +1198,7 @@ MainLoop *test() { OS::get_singleton()->print("Passed %i of %i tests\n", passed, count); - return NULL; + return nullptr; } + } // namespace TestString |