diff options
Diffstat (limited to 'core')
50 files changed, 577 insertions, 455 deletions
diff --git a/core/SCsub b/core/SCsub index f7b733a221..91620cb075 100644 --- a/core/SCsub +++ b/core/SCsub @@ -29,8 +29,8 @@ if "SCRIPT_AES256_ENCRYPTION_KEY" in os.environ: ec_valid = False txt += txts if not ec_valid: - print("Error: Invalid AES256 encryption key, not 64 hexadecimal characters: '" + key + "'.") - print( + methods.print_error( + f'Invalid AES256 encryption key, not 64 hexadecimal characters: "{key}".\n' "Unset 'SCRIPT_AES256_ENCRYPTION_KEY' in your environment " "or make sure that it contains exactly 64 hexadecimal characters." ) @@ -61,7 +61,6 @@ thirdparty_misc_sources = [ # C++ sources "pcg.cpp", "polypartition.cpp", - "clipper.cpp", "smolv.cpp", ] thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources] diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 104b17961d..ee20aea35d 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1017,7 +1017,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust } } // Check for the existence of a csproj file. - if (_csproj_exists(get_resource_path())) { + if (_csproj_exists(p_path.get_base_dir())) { // If there is a csproj file, add the C# feature if it doesn't already exist. if (!project_features.has("C#")) { project_features.append("C#"); @@ -1473,7 +1473,9 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true); - GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor", false); +#ifdef TOOLS_ENABLED + GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor_hint", false); +#endif GLOBAL_DEF("animation/warnings/check_invalid_track_paths", true); GLOBAL_DEF("animation/warnings/check_angle_interpolation_type_conflicting", true); @@ -1531,6 +1533,10 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_BASIC("internationalization/rendering/root_node_auto_translate", true); GLOBAL_DEF(PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"), 2000); + GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"), 0.5); +#ifdef TOOLS_ENABLED + GLOBAL_DEF("gui/timers/tooltip_delay_sec.editor_hint", 0.5); +#endif GLOBAL_DEF_BASIC("gui/common/snap_controls_to_pixels", true); GLOBAL_DEF_BASIC("gui/fonts/dynamic_fonts/use_oversampling", true); @@ -1568,6 +1574,14 @@ ProjectSettings::ProjectSettings() { ProjectSettings::get_singleton()->add_hidden_prefix("input/"); } +ProjectSettings::ProjectSettings(const String &p_path) { + if (load_custom(p_path) == OK) { + project_loaded = true; + } +} + ProjectSettings::~ProjectSettings() { - singleton = nullptr; + if (singleton == this) { + singleton = nullptr; + } } diff --git a/core/config/project_settings.h b/core/config/project_settings.h index 1bad76acb1..922c88c151 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -224,6 +224,7 @@ public: #endif ProjectSettings(); + ProjectSettings(const String &p_path); ~ProjectSettings(); }; diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 03c31bee28..0996db9d89 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -152,12 +152,10 @@ void ResourceLoader::_bind_methods() { ////// ResourceSaver ////// Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, BitField<SaverFlags> p_flags) { - ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path '" + p_path + "'."); return ::ResourceSaver::save(p_resource, p_path, p_flags); } Vector<String> ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource) { - ERR_FAIL_COND_V_MSG(p_resource.is_null(), Vector<String>(), "It's not a reference to a valid Resource object."); List<String> exts; ::ResourceSaver::get_recognized_extensions(p_resource, &exts); Vector<String> ret; @@ -1444,6 +1442,15 @@ Error ClassDB::class_set_property(Object *p_object, const StringName &p_property return OK; } +Variant ClassDB::class_get_property_default_value(const StringName &p_class, const StringName &p_property) const { + bool valid; + Variant ret = ::ClassDB::class_get_default_property_value(p_class, p_property, &valid); + if (valid) { + return ret; + } + return Variant(); +} + bool ClassDB::class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance) const { return ::ClassDB::has_method(p_class, p_method, p_no_inheritance); } @@ -1533,6 +1540,10 @@ StringName ClassDB::class_get_integer_constant_enum(const StringName &p_class, c return ::ClassDB::get_integer_constant_enum(p_class, p_name, p_no_inheritance); } +bool ClassDB::is_class_enum_bitfield(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance) const { + return ::ClassDB::is_enum_bitfield(p_class, p_enum, p_no_inheritance); +} + bool ClassDB::is_class_enabled(const StringName &p_class) const { return ::ClassDB::is_class_enabled(p_class); } @@ -1549,7 +1560,7 @@ void ClassDB::get_argument_options(const StringName &p_function, int p_idx, List pf == "class_has_method" || pf == "class_get_method_list" || pf == "class_get_integer_constant_list" || pf == "class_has_integer_constant" || pf == "class_get_integer_constant" || pf == "class_has_enum" || pf == "class_get_enum_list" || pf == "class_get_enum_constants" || pf == "class_get_integer_constant_enum" || - pf == "is_class_enabled"); + pf == "is_class_enabled" || pf == "is_class_enum_bitfield"); } if (first_argument_is_class || pf == "is_parent_class") { for (const String &E : get_class_list()) { @@ -1578,6 +1589,8 @@ void ClassDB::_bind_methods() { ::ClassDB::bind_method(D_METHOD("class_get_property", "object", "property"), &ClassDB::class_get_property); ::ClassDB::bind_method(D_METHOD("class_set_property", "object", "property", "value"), &ClassDB::class_set_property); + ::ClassDB::bind_method(D_METHOD("class_get_property_default_value", "class", "property"), &ClassDB::class_get_property_default_value); + ::ClassDB::bind_method(D_METHOD("class_has_method", "class", "method", "no_inheritance"), &ClassDB::class_has_method, DEFVAL(false)); ::ClassDB::bind_method(D_METHOD("class_get_method_argument_count", "class", "method", "no_inheritance"), &ClassDB::class_get_method_argument_count, DEFVAL(false)); @@ -1594,6 +1607,8 @@ void ClassDB::_bind_methods() { ::ClassDB::bind_method(D_METHOD("class_get_enum_constants", "class", "enum", "no_inheritance"), &ClassDB::class_get_enum_constants, DEFVAL(false)); ::ClassDB::bind_method(D_METHOD("class_get_integer_constant_enum", "class", "name", "no_inheritance"), &ClassDB::class_get_integer_constant_enum, DEFVAL(false)); + ::ClassDB::bind_method(D_METHOD("is_class_enum_bitfield", "class", "enum", "no_inheritance"), &ClassDB::is_class_enum_bitfield, DEFVAL(false)); + ::ClassDB::bind_method(D_METHOD("is_class_enabled", "class"), &ClassDB::is_class_enabled); } @@ -1906,7 +1921,7 @@ void EngineDebugger::send_message(const String &p_msg, const Array &p_data) { Error EngineDebugger::call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured) { Callable &capture = *(Callable *)p_user; - if (capture.is_null()) { + if (!capture.is_valid()) { return FAILED; } Variant cmd = p_cmd, data = p_data; diff --git a/core/core_bind.h b/core/core_bind.h index 3c0cdc25ce..148e0ad83e 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -447,6 +447,8 @@ public: Variant class_get_property(Object *p_object, const StringName &p_property) const; Error class_set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const; + Variant class_get_property_default_value(const StringName &p_class, const StringName &p_property) const; + bool class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const; int class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const; @@ -462,6 +464,8 @@ public: PackedStringArray class_get_enum_constants(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const; StringName class_get_integer_constant_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false) const; + bool is_class_enum_bitfield(const StringName &p_class, const StringName &p_enum, bool p_no_inheritance = false) const; + bool is_class_enabled(const StringName &p_class) const; #ifdef TOOLS_ENABLED diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 546c40e9cb..b48ea97040 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -46,6 +46,41 @@ String GDExtension::get_extension_list_config_file() { return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg"); } +Vector<SharedObject> GDExtension::find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature) { + Vector<SharedObject> dependencies_shared_objects; + if (p_config->has_section("dependencies")) { + List<String> config_dependencies; + p_config->get_section_keys("dependencies", &config_dependencies); + + for (const String &dependency : config_dependencies) { + Vector<String> dependency_tags = dependency.split("."); + bool all_tags_met = true; + for (int i = 0; i < dependency_tags.size(); i++) { + String tag = dependency_tags[i].strip_edges(); + if (!p_has_feature(tag)) { + all_tags_met = false; + break; + } + } + + if (all_tags_met) { + Dictionary dependency_value = p_config->get_value("dependencies", dependency); + for (const Variant *key = dependency_value.next(nullptr); key; key = dependency_value.next(key)) { + String dependency_path = *key; + String target_path = dependency_value[*key]; + if (dependency_path.is_relative_path()) { + dependency_path = p_path.get_base_dir().path_join(dependency_path); + } + dependencies_shared_objects.push_back(SharedObject(dependency_path, dependency_tags, target_path)); + } + break; + } + } + } + + return dependencies_shared_objects; +} + String GDExtension::find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags) { // First, check the explicit libraries. if (p_config->has_section("libraries")) { @@ -240,7 +275,7 @@ public: ret_opaque = r_ret->get_type() == Variant::NIL ? r_ret : VariantInternal::get_opaque_pointer(r_ret); } - ptrcall(p_object, argptrs, ret_opaque); + ptrcall_func(method_userdata, extension_instance, reinterpret_cast<GDExtensionConstTypePtr *>(argptrs), (GDExtensionTypePtr)ret_opaque); if (r_ret && r_ret->get_type() == Variant::OBJECT) { VariantInternal::update_object_id(r_ret); @@ -254,7 +289,7 @@ public: ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call GDExtension method bind '%s' on placeholder instance.", name)); #endif ERR_FAIL_COND_MSG(vararg, "Vararg methods don't have ptrcall support. This is most likely an engine bug."); - GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance(); + GDExtensionClassInstancePtr extension_instance = is_static() ? nullptr : p_object->_get_extension_instance(); ptrcall_func(method_userdata, extension_instance, reinterpret_cast<GDExtensionConstTypePtr *>(p_args), (GDExtensionTypePtr)r_ret); } @@ -352,7 +387,7 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library p_extension_funcs->set_func, // GDExtensionClassSet set_func; p_extension_funcs->get_func, // GDExtensionClassGet get_func; p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func; - p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func; + nullptr, // GDExtensionClassFreePropertyList2 free_property_list_func; p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func; p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func; nullptr, // GDExtensionClassValidateProperty validate_property_func; @@ -371,7 +406,8 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library }; const ClassCreationDeprecatedInfo legacy = { - p_extension_funcs->notification_func, + p_extension_funcs->notification_func, // GDExtensionClassNotification notification_func; + p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func; }; _register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info3, &legacy); } @@ -385,7 +421,7 @@ void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_librar p_extension_funcs->set_func, // GDExtensionClassSet set_func; p_extension_funcs->get_func, // GDExtensionClassGet get_func; p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func; - p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func; + nullptr, // GDExtensionClassFreePropertyList2 free_property_list_func; p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func; p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func; p_extension_funcs->validate_property_func, // GDExtensionClassValidateProperty validate_property_func; @@ -403,7 +439,11 @@ void GDExtension::_register_extension_class2(GDExtensionClassLibraryPtr p_librar p_extension_funcs->class_userdata, // void *class_userdata; }; - _register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info3); + const ClassCreationDeprecatedInfo legacy = { + nullptr, // GDExtensionClassNotification notification_func; + p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func; + }; + _register_extension_class_internal(p_library, p_class_name, p_parent_class_name, &class_info3, &legacy); } #endif // DISABLE_DEPRECATED @@ -479,13 +519,14 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr extension->gdextension.set = p_extension_funcs->set_func; extension->gdextension.get = p_extension_funcs->get_func; extension->gdextension.get_property_list = p_extension_funcs->get_property_list_func; - extension->gdextension.free_property_list = p_extension_funcs->free_property_list_func; + extension->gdextension.free_property_list2 = p_extension_funcs->free_property_list_func; extension->gdextension.property_can_revert = p_extension_funcs->property_can_revert_func; extension->gdextension.property_get_revert = p_extension_funcs->property_get_revert_func; extension->gdextension.validate_property = p_extension_funcs->validate_property_func; #ifndef DISABLE_DEPRECATED if (p_deprecated_funcs) { extension->gdextension.notification = p_deprecated_funcs->notification_func; + extension->gdextension.free_property_list = p_deprecated_funcs->free_property_list_func; } #endif // DISABLE_DEPRECATED extension->gdextension.notification2 = p_extension_funcs->notification_func; @@ -727,15 +768,31 @@ GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(const String return *function; } -Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) { +Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol, Vector<SharedObject> *p_dependencies) { String abs_path = ProjectSettings::get_singleton()->globalize_path(p_path); + + Vector<String> abs_dependencies_paths; + if (p_dependencies != nullptr && !p_dependencies->is_empty()) { + for (const SharedObject &dependency : *p_dependencies) { + abs_dependencies_paths.push_back(ProjectSettings::get_singleton()->globalize_path(dependency.path)); + } + } + String actual_lib_path; - Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, true, &actual_lib_path, Engine::get_singleton()->is_editor_hint()); + OS::GDExtensionData data = { + true, // also_set_library_path + &actual_lib_path, // r_resolved_path + Engine::get_singleton()->is_editor_hint(), // generate_temp_files + &abs_dependencies_paths, // library_dependencies + }; + Error err = OS::get_singleton()->open_dynamic_library(abs_path, library, &data); if (actual_lib_path.get_file() != abs_path.get_file()) { // If temporary files are generated, let's change the library path to point at the original, // because that's what we want to check to see if it's changed. library_path = actual_lib_path.get_base_dir().path_join(p_path.get_file()); + } else { + library_path = p_path; } ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, "GDExtension dynamic library not found: " + abs_path); @@ -970,7 +1027,8 @@ Error GDExtensionResourceLoader::load_gdextension_resource(const String &p_path, FileAccess::get_modified_time(library_path)); #endif - err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol); + Vector<SharedObject> library_dependencies = GDExtension::find_extension_dependencies(p_path, config, [](const String &p_feature) { return OS::get_singleton()->has_feature(p_feature); }); + err = p_extension->open_library(is_static_library ? String() : library_path, entry_symbol, &library_dependencies); if (err != OK) { // Unreference the extension so that this loading can be considered a failure. p_extension.unref(); diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index 1f48edecf7..3b15639890 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -37,6 +37,7 @@ #include "core/io/config_file.h" #include "core/io/resource_loader.h" #include "core/object/ref_counted.h" +#include "core/os/shared_object.h" class GDExtensionMethodBind; @@ -70,6 +71,7 @@ class GDExtension : public Resource { struct ClassCreationDeprecatedInfo { #ifndef DISABLE_DEPRECATED GDExtensionClassNotification notification_func = nullptr; + GDExtensionClassFreePropertyList free_property_list_func = nullptr; #endif // DISABLE_DEPRECATED }; @@ -123,8 +125,9 @@ public: static String get_extension_list_config_file(); static String find_extension_library(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature, PackedStringArray *r_tags = nullptr); + static Vector<SharedObject> find_extension_dependencies(const String &p_path, Ref<ConfigFile> p_config, std::function<bool(String)> p_has_feature); - Error open_library(const String &p_path, const String &p_entry_symbol); + Error open_library(const String &p_path, const String &p_entry_symbol, Vector<SharedObject> *p_dependencies = nullptr); void close_library(); enum InitializationLevel { diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h index e9c570e994..00a98af4e2 100644 --- a/core/extension/gdextension_interface.h +++ b/core/extension/gdextension_interface.h @@ -256,6 +256,7 @@ typedef struct { typedef const GDExtensionPropertyInfo *(*GDExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count); typedef void (*GDExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list); +typedef void (*GDExtensionClassFreePropertyList2)(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count); typedef GDExtensionBool (*GDExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name); typedef GDExtensionBool (*GDExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret); typedef GDExtensionBool (*GDExtensionClassValidateProperty)(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property); @@ -333,7 +334,7 @@ typedef struct { GDExtensionClassSet set_func; GDExtensionClassGet get_func; GDExtensionClassGetPropertyList get_property_list_func; - GDExtensionClassFreePropertyList free_property_list_func; + GDExtensionClassFreePropertyList2 free_property_list_func; GDExtensionClassPropertyCanRevert property_can_revert_func; GDExtensionClassPropertyGetRevert property_get_revert_func; GDExtensionClassValidateProperty validate_property_func; diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt index a17e15a62c..7150911e75 100644 --- a/core/input/gamecontrollerdb.txt +++ b/core/input/gamecontrollerdb.txt @@ -917,6 +917,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X, 030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f0000aa00000072050000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000000d0f00000002000017010000,Hori Split Pad Fit,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00000002000015010000,Hori Switch Split Pad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, 030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, @@ -1282,6 +1283,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 030000000d0f00006b00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00001600000000010000,Hori Real Arcade Pro EXSE,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, 030000000d0f0000aa00000011010000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000000d0f00008501000017010000,Hori Split Pad Fit,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, 030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, @@ -1696,6 +1698,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2, 060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000130b000017050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000014050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, 050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, 050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp index e99885befa..5df67b1103 100644 --- a/core/io/dir_access.cpp +++ b/core/io/dir_access.cpp @@ -582,6 +582,10 @@ void DirAccess::_bind_methods() { ClassDB::bind_method(D_METHOD("remove", "path"), &DirAccess::remove); ClassDB::bind_static_method("DirAccess", D_METHOD("remove_absolute", "path"), &DirAccess::remove_absolute); + ClassDB::bind_method(D_METHOD("is_link", "path"), &DirAccess::is_link); + ClassDB::bind_method(D_METHOD("read_link", "path"), &DirAccess::read_link); + ClassDB::bind_method(D_METHOD("create_link", "source", "target"), &DirAccess::create_link); + ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &DirAccess::set_include_navigational); ClassDB::bind_method(D_METHOD("get_include_navigational"), &DirAccess::get_include_navigational); ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden); diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index d2a5103953..1cf388b33a 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -867,6 +867,7 @@ void FileAccess::_bind_methods() { ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_bytes", "path"), &FileAccess::_get_file_as_bytes); ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_string", "path"), &FileAccess::_get_file_as_string); + ClassDB::bind_method(D_METHOD("resize", "length"), &FileAccess::resize); ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush); ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path); ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute); diff --git a/core/io/file_access.h b/core/io/file_access.h index 0b631f68b1..2ab84db4b6 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -166,6 +166,7 @@ public: virtual Error get_error() const = 0; ///< get last error + virtual Error resize(int64_t p_length) = 0; virtual void flush() = 0; virtual void store_8(uint8_t p_dest) = 0; ///< store a byte virtual void store_16(uint16_t p_dest); ///< store 16 bits uint diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index bf57eaa07c..f706c82f8e 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -88,6 +88,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 489d213b8f..42afe49a5e 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -78,6 +78,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index d9efb354c3..e9fbc26d75 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -61,6 +61,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_byte) override; ///< store a byte virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 0deacfebab..594ac8f089 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -177,6 +177,7 @@ public: virtual Error get_error() const override; + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index 3c7f67664d..c0d1afc8e1 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -277,7 +277,7 @@ void FileAccessZip::seek_end(int64_t p_position) { uint64_t FileAccessZip::get_position() const { ERR_FAIL_NULL_V(zfile, 0); - return unztell(zfile); + return unztell64(zfile); } uint64_t FileAccessZip::get_length() const { diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index e9ea74e01d..88b63e93e2 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -100,6 +100,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte diff --git a/core/io/json.cpp b/core/io/json.cpp index 5a1fe45f70..61051727c1 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -344,10 +344,10 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to r_token.value = number; return OK; - } else if (is_ascii_char(p_str[index])) { + } else if (is_ascii_alphabet_char(p_str[index])) { String id; - while (is_ascii_char(p_str[index])) { + while (is_ascii_alphabet_char(p_str[index])) { id += p_str[index]; index++; } diff --git a/core/io/logger.cpp b/core/io/logger.cpp index 441df7f5d1..1476b8ccac 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -37,6 +37,8 @@ #include "core/os/time.h" #include "core/string/print_string.h" +#include "modules/modules_enabled.gen.h" // For regex. + #if defined(MINGW_ENABLED) || defined(_MSC_VER) #define sprintf sprintf_s #endif @@ -180,6 +182,12 @@ RotatedFileLogger::RotatedFileLogger(const String &p_base_path, int p_max_files) base_path(p_base_path.simplify_path()), max_files(p_max_files > 0 ? p_max_files : 1) { rotate_file(); + +#ifdef MODULE_REGEX_ENABLED + strip_ansi_regex.instantiate(); + strip_ansi_regex->detach_from_objectdb(); // Note: This RegEx instance will exist longer than ObjectDB, therefore can't be registered in ObjectDB. + strip_ansi_regex->compile("\u001b\\[((?:\\d|;)*)([a-zA-Z])"); +#endif // MODULE_REGEX_ENABLED } void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) { @@ -199,7 +207,15 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) { vsnprintf(buf, len + 1, p_format, list_copy); } va_end(list_copy); + +#ifdef MODULE_REGEX_ENABLED + // Strip ANSI escape codes (such as those inserted by `print_rich()`) + // before writing to file, as text editors cannot display those + // correctly. + file->store_string(strip_ansi_regex->sub(String(buf), "", true)); +#else file->store_buffer((uint8_t *)buf, len); +#endif // MODULE_REGEX_ENABLED if (len >= static_buf_size) { Memory::free_static(buf); diff --git a/core/io/logger.h b/core/io/logger.h index 3cd18965c5..85ef3031ec 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -34,6 +34,10 @@ #include "core/io/file_access.h" #include "core/string/ustring.h" #include "core/templates/vector.h" +#include "modules/modules_enabled.gen.h" // For regex. +#ifdef MODULE_REGEX_ENABLED +#include "modules/regex/regex.h" +#endif // MODULE_REGEX_ENABLED #include <stdarg.h> @@ -86,6 +90,10 @@ class RotatedFileLogger : public Logger { void clear_old_backups(); void rotate_file(); +#ifdef MODULE_REGEX_ENABLED + Ref<RegEx> strip_ansi_regex; +#endif // MODULE_REGEX_ENABLED + public: explicit RotatedFileLogger(const String &p_base_path, int p_max_files = 10); diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index eea6357084..c3c37aa89d 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -242,16 +242,20 @@ ResourceLoader::LoadToken::~LoadToken() { } Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) { + const String &original_path = p_original_path.is_empty() ? p_path : p_original_path; load_nesting++; if (load_paths_stack->size()) { thread_load_mutex.lock(); - HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(load_paths_stack->get(load_paths_stack->size() - 1)); - if (E) { + const String &parent_task_path = load_paths_stack->get(load_paths_stack->size() - 1); + HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(parent_task_path); + // Avoid double-tracking, for progress reporting, resources that boil down to a remapped path containing the real payload (e.g., imported resources). + bool is_remapped_load = original_path == parent_task_path; + if (E && !is_remapped_load) { E->value.sub_tasks.insert(p_original_path); } thread_load_mutex.unlock(); } - load_paths_stack->push_back(p_original_path); + load_paths_stack->push_back(original_path); // Try all loaders and pick the first match for the type hint bool found = false; @@ -261,7 +265,7 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin continue; } found = true; - res = loader[i]->load(p_path, !p_original_path.is_empty() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress, p_cache_mode); + res = loader[i]->load(p_path, original_path, r_error, p_use_sub_threads, r_progress, p_cache_mode); if (!res.is_null()) { break; } diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index e4022b2073..1dc1245355 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -98,6 +98,7 @@ void ResourceFormatSaver::_bind_methods() { } Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) { + ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path '" + p_path + "'."); String path = p_path; if (path.is_empty()) { path = p_resource->get_path(); @@ -174,6 +175,7 @@ void ResourceSaver::set_save_callback(ResourceSavedCallback p_callback) { } void ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) { + ERR_FAIL_COND_MSG(p_resource.is_null(), "It's not a reference to a valid Resource object."); for (int i = 0; i < saver_count; i++) { saver[i]->get_recognized_extensions(p_resource, p_extensions); } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 84ac878172..34ed1c2d85 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -293,7 +293,7 @@ Vector3 Basis::get_scale_abs() const { Vector3(rows[0][2], rows[1][2], rows[2][2]).length()); } -Vector3 Basis::get_scale_local() const { +Vector3 Basis::get_scale_global() const { real_t det_sign = SIGN(determinant()); return det_sign * Vector3(rows[0].length(), rows[1].length(), rows[2].length()); } diff --git a/core/math/basis.h b/core/math/basis.h index 79f3bda8f8..918cbc18d4 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -103,7 +103,7 @@ struct _NO_DISCARD_ Basis { Vector3 get_scale() const; Vector3 get_scale_abs() const; - Vector3 get_scale_local() const; + Vector3 get_scale_global() const; void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale); void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EulerOrder::YXZ); diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index 45571fb570..25bd4e8d89 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.h @@ -46,7 +46,8 @@ class Delaunay3D { struct Simplex; enum { - ACCEL_GRID_SIZE = 16 + ACCEL_GRID_SIZE = 16, + QUANTIZATION_MAX = 1 << 16 // A power of two smaller than the 23 bit significand of a float. }; struct GridPos { Vector3i pos; @@ -173,38 +174,25 @@ class Delaunay3D { R128 radius2 = rel2_x * rel2_x + rel2_y * rel2_y + rel2_z * rel2_z; - return radius2 < (p_simplex.circum_r2 - R128(0.00001)); + return radius2 < (p_simplex.circum_r2 - R128(0.0000000001)); + // When this tolerance is too big, it can result in overlapping simplices. + // When it's too small, large amounts of planar simplices are created. } static bool simplex_is_coplanar(const Vector3 *p_points, const Simplex &p_simplex) { - Plane p(p_points[p_simplex.points[0]], p_points[p_simplex.points[1]], p_points[p_simplex.points[2]]); - if (ABS(p.distance_to(p_points[p_simplex.points[3]])) < CMP_EPSILON) { - return true; + // Checking every possible distance like this is overkill, but only checking + // one is not enough. If the simplex is almost planar then the vectors p1-p2 + // and p1-p3 can be practically collinear, which makes Plane unreliable. + for (uint32_t i = 0; i < 4; i++) { + Plane p(p_points[p_simplex.points[i]], p_points[p_simplex.points[(i + 1) % 4]], p_points[p_simplex.points[(i + 2) % 4]]); + // This tolerance should not be smaller than the one used with + // Plane::has_point() when creating the LightmapGI probe BSP tree. + if (ABS(p.distance_to(p_points[p_simplex.points[(i + 3) % 4]])) < 0.001) { + return true; + } } - Projection cm; - - cm.columns[0][0] = p_points[p_simplex.points[0]].x; - cm.columns[0][1] = p_points[p_simplex.points[1]].x; - cm.columns[0][2] = p_points[p_simplex.points[2]].x; - cm.columns[0][3] = p_points[p_simplex.points[3]].x; - - cm.columns[1][0] = p_points[p_simplex.points[0]].y; - cm.columns[1][1] = p_points[p_simplex.points[1]].y; - cm.columns[1][2] = p_points[p_simplex.points[2]].y; - cm.columns[1][3] = p_points[p_simplex.points[3]].y; - - cm.columns[2][0] = p_points[p_simplex.points[0]].z; - cm.columns[2][1] = p_points[p_simplex.points[1]].z; - cm.columns[2][2] = p_points[p_simplex.points[2]].z; - cm.columns[2][3] = p_points[p_simplex.points[3]].z; - - cm.columns[3][0] = 1.0; - cm.columns[3][1] = 1.0; - cm.columns[3][2] = 1.0; - cm.columns[3][3] = 1.0; - - return ABS(cm.determinant()) <= CMP_EPSILON; + return false; } public: @@ -215,9 +203,10 @@ public: static Vector<OutputSimplex> tetrahedralize(const Vector<Vector3> &p_points) { uint32_t point_count = p_points.size(); Vector3 *points = (Vector3 *)memalloc(sizeof(Vector3) * (point_count + 4)); + const Vector3 *src_points = p_points.ptr(); + Vector3 proportions; { - const Vector3 *src_points = p_points.ptr(); AABB rect; for (uint32_t i = 0; i < point_count; i++) { Vector3 point = src_points[i]; @@ -226,17 +215,25 @@ public: } else { rect.expand_to(point); } - points[i] = point; } + real_t longest_axis = rect.size[rect.get_longest_axis_index()]; + proportions = Vector3(longest_axis, longest_axis, longest_axis) / rect.size; + for (uint32_t i = 0; i < point_count; i++) { - points[i] = (points[i] - rect.position) / rect.size; + // Scale points to the unit cube to better utilize R128 precision + // and quantize to stabilize triangulation over a wide range of + // distances. + points[i] = Vector3(Vector3i((src_points[i] - rect.position) / longest_axis * QUANTIZATION_MAX)) / QUANTIZATION_MAX; } - const real_t delta_max = Math::sqrt(2.0) * 20.0; + const real_t delta_max = Math::sqrt(2.0) * 100.0; Vector3 center = Vector3(0.5, 0.5, 0.5); - // any simplex that contains everything is good + // The larger the root simplex is, the more likely it is that the + // triangulation is convex. If it's not absolutely huge, there can + // be missing simplices that are not created for the outermost faces + // of the point cloud if the point density is very low there. points[point_count + 0] = center + Vector3(0, 1, 0) * delta_max; points[point_count + 1] = center + Vector3(0, -1, 1) * delta_max; points[point_count + 2] = center + Vector3(1, -1, -1) * delta_max; @@ -271,7 +268,7 @@ public: for (uint32_t i = 0; i < point_count; i++) { bool unique = true; for (uint32_t j = i + 1; j < point_count; j++) { - if (points[i].is_equal_approx(points[j])) { + if (points[i] == points[j]) { unique = false; break; } @@ -280,7 +277,7 @@ public: continue; } - Vector3i grid_pos = Vector3i(points[i] * ACCEL_GRID_SIZE); + Vector3i grid_pos = Vector3i(points[i] * proportions * ACCEL_GRID_SIZE); grid_pos = grid_pos.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1)); for (List<Simplex *>::Element *E = acceleration_grid[grid_pos.x][grid_pos.y][grid_pos.z].front(); E;) { @@ -300,6 +297,9 @@ public: Triangle t = Triangle(simplex->points[triangle_order[k][0]], simplex->points[triangle_order[k][1]], simplex->points[triangle_order[k][2]]); uint32_t *p = triangles_inserted.lookup_ptr(t); if (p) { + // This Delaunay implementation uses the Bowyer-Watson algorithm. + // The rule is that you don't reuse any triangles that were + // shared by any of the retriangulated simplices. triangles[*p].bad = true; } else { triangles_inserted.insert(t, triangles.size()); @@ -307,7 +307,6 @@ public: } } - //remove simplex and continue simplex_list.erase(simplex->SE); for (const GridPos &gp : simplex->grid_positions) { @@ -334,8 +333,8 @@ public: const real_t radius2 = Math::sqrt(double(new_simplex->circum_r2)) + 0.0001; Vector3 extents = Vector3(radius2, radius2, radius2); - Vector3i from = Vector3i((center - extents) * ACCEL_GRID_SIZE); - Vector3i to = Vector3i((center + extents) * ACCEL_GRID_SIZE); + Vector3i from = Vector3i((center - extents) * proportions * ACCEL_GRID_SIZE); + Vector3i to = Vector3i((center + extents) * proportions * ACCEL_GRID_SIZE); from = from.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1)); to = to.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1)); @@ -370,7 +369,7 @@ public: break; } } - if (invalid || simplex_is_coplanar(points, *simplex)) { + if (invalid || simplex_is_coplanar(src_points, *simplex)) { memdelete(simplex); continue; } diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp index 602e95bc13..d60619b27f 100644 --- a/core/math/geometry_2d.cpp +++ b/core/math/geometry_2d.cpp @@ -30,12 +30,12 @@ #include "geometry_2d.h" -#include "thirdparty/misc/clipper.hpp" +#include "thirdparty/clipper2/include/clipper2/clipper.h" #include "thirdparty/misc/polypartition.h" #define STB_RECT_PACK_IMPLEMENTATION #include "thirdparty/misc/stb_rect_pack.h" -#define SCALE_FACTOR 100000.0 // Based on CMP_EPSILON. +#define PRECISION 5 // Based on CMP_EPSILON. Vector<Vector<Vector2>> Geometry2D::decompose_polygon_in_convex(const Vector<Point2> &polygon) { Vector<Vector<Vector2>> decomp; @@ -196,58 +196,59 @@ void Geometry2D::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_re } Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open) { - using namespace ClipperLib; + using namespace Clipper2Lib; - ClipType op = ctUnion; + ClipType op = ClipType::Union; switch (p_op) { case OPERATION_UNION: - op = ctUnion; + op = ClipType::Union; break; case OPERATION_DIFFERENCE: - op = ctDifference; + op = ClipType::Difference; break; case OPERATION_INTERSECTION: - op = ctIntersection; + op = ClipType::Intersection; break; case OPERATION_XOR: - op = ctXor; + op = ClipType::Xor; break; } - Path path_a, path_b; - // Need to scale points (Clipper's requirement for robust computation). + PathD path_a(p_polypath_a.size()); for (int i = 0; i != p_polypath_a.size(); ++i) { - path_a << IntPoint(p_polypath_a[i].x * (real_t)SCALE_FACTOR, p_polypath_a[i].y * (real_t)SCALE_FACTOR); + path_a[i] = PointD(p_polypath_a[i].x, p_polypath_a[i].y); } + PathD path_b(p_polypath_b.size()); for (int i = 0; i != p_polypath_b.size(); ++i) { - path_b << IntPoint(p_polypath_b[i].x * (real_t)SCALE_FACTOR, p_polypath_b[i].y * (real_t)SCALE_FACTOR); + path_b[i] = PointD(p_polypath_b[i].x, p_polypath_b[i].y); } - Clipper clp; - clp.AddPath(path_a, ptSubject, !is_a_open); // Forward compatible with Clipper 10.0.0. - clp.AddPath(path_b, ptClip, true); // Polylines cannot be set as clip. - Paths paths; + ClipperD clp(PRECISION); // Scale points up internally to attain the desired precision. + clp.PreserveCollinear(false); // Remove redundant vertices. + if (is_a_open) { + clp.AddOpenSubject({ path_a }); + } else { + clp.AddSubject({ path_a }); + } + clp.AddClip({ path_b }); + + PathsD paths; if (is_a_open) { - PolyTree tree; // Needed to populate polylines. - clp.Execute(op, tree); - OpenPathsFromPolyTree(tree, paths); + PolyTreeD tree; // Needed to populate polylines. + clp.Execute(op, FillRule::EvenOdd, tree, paths); } else { - clp.Execute(op, paths); // Works on closed polygons only. + clp.Execute(op, FillRule::EvenOdd, paths); // Works on closed polygons only. } - // Have to scale points down now. + Vector<Vector<Point2>> polypaths; + for (PathsD::size_type i = 0; i < paths.size(); ++i) { + const PathD &path = paths[i]; - for (Paths::size_type i = 0; i < paths.size(); ++i) { Vector<Vector2> polypath; - - const Path &scaled_path = paths[i]; - - for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { - polypath.push_back(Point2( - static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR, - static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR)); + for (PathsD::size_type j = 0; j < path.size(); ++j) { + polypath.push_back(Point2(static_cast<real_t>(path[j].x), static_cast<real_t>(path[j].y))); } polypaths.push_back(polypath); } @@ -255,67 +256,61 @@ Vector<Vector<Point2>> Geometry2D::_polypaths_do_operation(PolyBooleanOperation } Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { - using namespace ClipperLib; + using namespace Clipper2Lib; - JoinType jt = jtSquare; + JoinType jt = JoinType::Square; switch (p_join_type) { case JOIN_SQUARE: - jt = jtSquare; + jt = JoinType::Square; break; case JOIN_ROUND: - jt = jtRound; + jt = JoinType::Round; break; case JOIN_MITER: - jt = jtMiter; + jt = JoinType::Miter; break; } - EndType et = etClosedPolygon; + EndType et = EndType::Polygon; switch (p_end_type) { case END_POLYGON: - et = etClosedPolygon; + et = EndType::Polygon; break; case END_JOINED: - et = etClosedLine; + et = EndType::Joined; break; case END_BUTT: - et = etOpenButt; + et = EndType::Butt; break; case END_SQUARE: - et = etOpenSquare; + et = EndType::Square; break; case END_ROUND: - et = etOpenRound; + et = EndType::Round; break; } - ClipperOffset co(2.0, 0.25f * (real_t)SCALE_FACTOR); // Defaults from ClipperOffset. - Path path; - // Need to scale points (Clipper's requirement for robust computation). + PathD polypath(p_polypath.size()); for (int i = 0; i != p_polypath.size(); ++i) { - path << IntPoint(p_polypath[i].x * (real_t)SCALE_FACTOR, p_polypath[i].y * (real_t)SCALE_FACTOR); + polypath[i] = PointD(p_polypath[i].x, p_polypath[i].y); } - co.AddPath(path, jt, et); - Paths paths; - co.Execute(paths, p_delta * (real_t)SCALE_FACTOR); // Inflate/deflate. + // Inflate/deflate. + PathsD paths = InflatePaths({ polypath }, p_delta, jt, et, 2.0, PRECISION, 0.0); + // Here the miter_limit = 2.0 and arc_tolerance = 0.0 are Clipper2 defaults, + // and the PRECISION is used to scale points up internally, to attain the desired precision. - // Have to scale points down now. Vector<Vector<Point2>> polypaths; + for (PathsD::size_type i = 0; i < paths.size(); ++i) { + const PathD &path = paths[i]; - for (Paths::size_type i = 0; i < paths.size(); ++i) { - Vector<Vector2> polypath; - - const Path &scaled_path = paths[i]; - - for (Paths::size_type j = 0; j < scaled_path.size(); ++j) { - polypath.push_back(Point2( - static_cast<real_t>(scaled_path[j].X) / (real_t)SCALE_FACTOR, - static_cast<real_t>(scaled_path[j].Y) / (real_t)SCALE_FACTOR)); + Vector<Vector2> polypath2; + for (PathsD::size_type j = 0; j < path.size(); ++j) { + polypath2.push_back(Point2(static_cast<real_t>(path[j].x), static_cast<real_t>(path[j].y))); } - polypaths.push_back(polypath); + polypaths.push_back(polypath2); } return polypaths; } diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 80a2703c2f..876635529c 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -138,7 +138,7 @@ public: return nullptr; } - static void placeholder_instance_free_property_list(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list) { + static void placeholder_instance_free_property_list(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list, uint32_t p_count) { } static GDExtensionBool placeholder_instance_property_can_revert(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name) { @@ -182,8 +182,20 @@ public: // Construct a placeholder. Object *obj = native_parent->creation_func(); + + // ClassDB::set_object_extension_instance() won't be called for placeholders. + // We need need to make sure that all the things it would have done (even if + // done in a different way to support placeholders) will also be done here. + obj->_extension = ClassDB::get_placeholder_extension(ti->name); obj->_extension_instance = memnew(PlaceholderExtensionInstance(ti->name)); + +#ifdef TOOLS_ENABLED + if (obj->_extension->track_instance) { + obj->_extension->track_instance(obj->_extension->tracking_userdata, obj); + } +#endif + return obj; } @@ -506,14 +518,7 @@ Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require extension = get_placeholder_extension(ti->name); } #endif - Object *obj = (Object *)extension->create_instance(extension->class_userdata); - -#ifdef TOOLS_ENABLED - if (extension->track_instance) { - extension->track_instance(extension->tracking_userdata, obj); - } -#endif - return obj; + return (Object *)extension->create_instance(extension->class_userdata); } else { #ifdef TOOLS_ENABLED if (!p_require_real_class && ti->is_runtime && Engine::get_singleton()->is_editor_hint()) { @@ -595,12 +600,13 @@ ObjectGDExtension *ClassDB::get_placeholder_extension(const StringName &p_class) placeholder_extension->set = &PlaceholderExtensionInstance::placeholder_instance_set; placeholder_extension->get = &PlaceholderExtensionInstance::placeholder_instance_get; placeholder_extension->get_property_list = &PlaceholderExtensionInstance::placeholder_instance_get_property_list; - placeholder_extension->free_property_list = &PlaceholderExtensionInstance::placeholder_instance_free_property_list; + placeholder_extension->free_property_list2 = &PlaceholderExtensionInstance::placeholder_instance_free_property_list; placeholder_extension->property_can_revert = &PlaceholderExtensionInstance::placeholder_instance_property_can_revert; placeholder_extension->property_get_revert = &PlaceholderExtensionInstance::placeholder_instance_property_get_revert; placeholder_extension->validate_property = &PlaceholderExtensionInstance::placeholder_instance_validate_property; #ifndef DISABLE_DEPRECATED placeholder_extension->notification = nullptr; + placeholder_extension->free_property_list = nullptr; #endif // DISABLE_DEPRECATED placeholder_extension->notification2 = &PlaceholderExtensionInstance::placeholder_instance_notification; placeholder_extension->to_string = &PlaceholderExtensionInstance::placeholder_instance_to_string; @@ -638,6 +644,12 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName & p_object->_extension = ti->gdextension; p_object->_extension_instance = p_instance; + +#ifdef TOOLS_ENABLED + if (p_object->_extension->track_instance) { + p_object->_extension->track_instance(p_object->_extension->tracking_userdata, p_object); + } +#endif } bool ClassDB::can_instantiate(const StringName &p_class) { diff --git a/core/object/class_db.h b/core/object/class_db.h index adb525cbe8..37a864c109 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -195,7 +195,7 @@ public: template <typename T> static void register_class(bool p_virtual = false) { GLOBAL_LOCK_FUNCTION; - static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS."); + static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_NULL(t); @@ -210,7 +210,7 @@ public: template <typename T> static void register_abstract_class() { GLOBAL_LOCK_FUNCTION; - static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS."); + static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_NULL(t); @@ -223,7 +223,7 @@ public: template <typename T> static void register_internal_class() { GLOBAL_LOCK_FUNCTION; - static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS."); + static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_NULL(t); @@ -238,7 +238,7 @@ public: template <typename T> static void register_runtime_class() { GLOBAL_LOCK_FUNCTION; - static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS."); + static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_NULL(t); @@ -263,7 +263,7 @@ public: template <typename T> static void register_custom_instance_class() { GLOBAL_LOCK_FUNCTION; - static_assert(types_are_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS."); + static_assert(std::is_same_v<typename T::self_type, T>, "Class not declared properly, please use GDCLASS."); T::initialize_class(); ClassInfo *t = classes.getptr(T::get_class_static()); ERR_FAIL_NULL(t); diff --git a/core/object/object.cpp b/core/object/object.cpp index f8d2feb5a8..b6c8a87a22 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -503,9 +503,14 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons for (uint32_t i = 0; i < pcount; i++) { p_list->push_back(PropertyInfo(pinfo[i])); } - if (current_extension->free_property_list) { + if (current_extension->free_property_list2) { + current_extension->free_property_list2(_extension_instance, pinfo, pcount); + } +#ifndef DISABLE_DEPRECATED + else if (current_extension->free_property_list) { current_extension->free_property_list(_extension_instance, pinfo); } +#endif // DISABLE_DEPRECATED #ifdef TOOLS_ENABLED } #endif @@ -1455,7 +1460,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui } bool Object::is_connected(const StringName &p_signal, const Callable &p_callable) const { - ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot determine if connected to '" + p_signal + "': the provided callable is null."); + ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot determine if connected to '" + p_signal + "': the provided callable is null."); // Should use `is_null`, see note in `connect` about the use of `is_valid`. const SignalData *s = signal_map.getptr(p_signal); if (!s) { bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal); @@ -1478,7 +1483,7 @@ void Object::disconnect(const StringName &p_signal, const Callable &p_callable) } bool Object::_disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force) { - ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot disconnect from '" + p_signal + "': the provided callable is null."); + ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot disconnect from '" + p_signal + "': the provided callable is null."); // Should use `is_null`, see note in `connect` about the use of `is_valid`. SignalData *s = signal_map.getptr(p_signal); if (!s) { diff --git a/core/object/object.h b/core/object/object.h index 915c3a8c25..adb50268d2 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -324,12 +324,13 @@ struct ObjectGDExtension { GDExtensionClassSet set; GDExtensionClassGet get; GDExtensionClassGetPropertyList get_property_list; - GDExtensionClassFreePropertyList free_property_list; + GDExtensionClassFreePropertyList2 free_property_list2; GDExtensionClassPropertyCanRevert property_can_revert; GDExtensionClassPropertyGetRevert property_get_revert; GDExtensionClassValidateProperty validate_property; #ifndef DISABLE_DEPRECATED GDExtensionClassNotification notification; + GDExtensionClassFreePropertyList free_property_list; #endif // DISABLE_DEPRECATED GDExtensionClassNotification2 notification2; GDExtensionClassToString to_string; diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 660e13e819..bd3199ca0a 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -51,7 +51,7 @@ void Script::_notification(int p_what) { switch (p_what) { case NOTIFICATION_POSTINITIALIZE: { if (EngineDebugger::is_active()) { - EngineDebugger::get_script_debugger()->set_break_language(get_language()); + callable_mp(this, &Script::_set_debugger_break_language).call_deferred(); } } break; } @@ -103,6 +103,12 @@ Dictionary Script::_get_script_constant_map() { return ret; } +void Script::_set_debugger_break_language() { + if (EngineDebugger::is_active()) { + EngineDebugger::get_script_debugger()->set_break_language(get_language()); + } +} + int Script::get_script_method_argument_count(const StringName &p_method, bool *r_is_valid) const { MethodInfo mi = get_method_info(p_method); diff --git a/core/object/script_language.h b/core/object/script_language.h index c6c6f3de9f..223f114150 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -124,6 +124,8 @@ protected: TypedArray<Dictionary> _get_script_signal_list(); Dictionary _get_script_constant_map(); + void _set_debugger_break_language(); + public: virtual void reload_from_file() override; diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index 6a1385e268..4d67cd930e 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -144,7 +144,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode, bool p_back } void UndoRedo::add_do_method(const Callable &p_callable) { - ERR_FAIL_COND(p_callable.is_null()); + ERR_FAIL_COND(!p_callable.is_valid()); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); @@ -169,7 +169,7 @@ void UndoRedo::add_do_method(const Callable &p_callable) { } void UndoRedo::add_undo_method(const Callable &p_callable) { - ERR_FAIL_COND(p_callable.is_null()); + ERR_FAIL_COND(!p_callable.is_valid()); ERR_FAIL_COND(action_level <= 0); ERR_FAIL_COND((current_action + 1) >= actions.size()); diff --git a/core/os/os.cpp b/core/os/os.cpp index 8582888740..fa7f23ded0 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -398,6 +398,11 @@ bool OS::has_feature(const String &p_feature) { if (p_feature == "editor") { return true; } + if (p_feature == "editor_hint") { + return _in_editor; + } else if (p_feature == "editor_runtime") { + return !_in_editor; + } #else if (p_feature == "template") { return true; diff --git a/core/os/os.h b/core/os/os.h index 06be0e2b41..d20f84b4ff 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -63,6 +63,7 @@ class OS { bool _stdout_enabled = true; bool _stderr_enabled = true; bool _writing_movie = false; + bool _in_editor = false; CompositeLogger *_logger = nullptr; @@ -153,7 +154,14 @@ public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); - virtual Error open_dynamic_library(const String &p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr, bool p_generate_temp_files = false) { return ERR_UNAVAILABLE; } + struct GDExtensionData { + bool also_set_library_path = false; + String *r_resolved_path = nullptr; + bool generate_temp_files = false; + PackedStringArray *library_dependencies = nullptr; + }; + + virtual Error open_dynamic_library(const String &p_path, void *&p_library_handle, GDExtensionData *p_data = nullptr) { return ERR_UNAVAILABLE; } virtual Error close_dynamic_library(void *p_library_handle) { return ERR_UNAVAILABLE; } virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String &p_name, void *&p_symbol_handle, bool p_optional = false) { return ERR_UNAVAILABLE; } diff --git a/core/os/shared_object.h b/core/os/shared_object.h new file mode 100644 index 0000000000..88423bed13 --- /dev/null +++ b/core/os/shared_object.h @@ -0,0 +1,51 @@ +/**************************************************************************/ +/* shared_object.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef SHARED_OBJECT_H +#define SHARED_OBJECT_H + +#include "core/string/ustring.h" +#include "core/templates/vector.h" + +struct SharedObject { + String path; + Vector<String> tags; + String target; + + SharedObject(const String &p_path, const Vector<String> &p_tags, const String &p_target) : + path(p_path), + tags(p_tags), + target(p_target) { + } + + SharedObject() {} +}; + +#endif // SHARED_OBJECT_H diff --git a/core/string/char_utils.h b/core/string/char_utils.h index aa9bc198ca..fc2fbb95a1 100644 --- a/core/string/char_utils.h +++ b/core/string/char_utils.h @@ -92,7 +92,7 @@ static _FORCE_INLINE_ bool is_binary_digit(char32_t c) { return (c == '0' || c == '1'); } -static _FORCE_INLINE_ bool is_ascii_char(char32_t c) { +static _FORCE_INLINE_ bool is_ascii_alphabet_char(char32_t c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 613edd11cd..344fe42fa0 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -993,7 +993,7 @@ String TranslationServer::add_padding(const String &p_message, int p_length) con } const char32_t *TranslationServer::get_accented_version(char32_t p_character) const { - if (!is_ascii_char(p_character)) { + if (!is_ascii_alphabet_char(p_character)) { return nullptr; } diff --git a/core/templates/command_queue_mt.cpp b/core/templates/command_queue_mt.cpp index 0c5c6394a1..d9e5e0b217 100644 --- a/core/templates/command_queue_mt.cpp +++ b/core/templates/command_queue_mt.cpp @@ -41,35 +41,6 @@ void CommandQueueMT::unlock() { mutex.unlock(); } -void CommandQueueMT::wait_for_flush() { - // wait one millisecond for a flush to happen - OS::get_singleton()->delay_usec(1000); -} - -CommandQueueMT::SyncSemaphore *CommandQueueMT::_alloc_sync_sem() { - int idx = -1; - - while (true) { - lock(); - for (int i = 0; i < SYNC_SEMAPHORES; i++) { - if (!sync_sems[i].in_use) { - sync_sems[i].in_use = true; - idx = i; - break; - } - } - unlock(); - - if (idx == -1) { - wait_for_flush(); - } else { - break; - } - } - - return &sync_sems[idx]; -} - CommandQueueMT::CommandQueueMT() { } diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h index a4ac338bed..c149861467 100644 --- a/core/templates/command_queue_mt.h +++ b/core/templates/command_queue_mt.h @@ -32,9 +32,9 @@ #define COMMAND_QUEUE_MT_H #include "core/object/worker_thread_pool.h" +#include "core/os/condition_variable.h" #include "core/os/memory.h" #include "core/os/mutex.h" -#include "core/os/semaphore.h" #include "core/string/print_string.h" #include "core/templates/local_vector.h" #include "core/templates/simple_type.h" @@ -251,14 +251,14 @@ #define DECL_PUSH(N) \ template <typename T, typename M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \ void push(T *p_instance, M p_method COMMA(N) COMMA_SEP_LIST(PARAM, N)) { \ - CMD_TYPE(N) *cmd = allocate_and_lock<CMD_TYPE(N)>(); \ + MutexLock mlock(mutex); \ + CMD_TYPE(N) *cmd = allocate<CMD_TYPE(N)>(); \ cmd->instance = p_instance; \ cmd->method = p_method; \ SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \ if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \ WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \ } \ - unlock(); \ } #define CMD_RET_TYPE(N) CommandRet##N<T, M, COMMA_SEP_LIST(TYPE_ARG, N) COMMA(N) R> @@ -266,19 +266,17 @@ #define DECL_PUSH_AND_RET(N) \ template <typename T, typename M, COMMA_SEP_LIST(TYPE_PARAM, N) COMMA(N) typename R> \ void push_and_ret(T *p_instance, M p_method, COMMA_SEP_LIST(PARAM, N) COMMA(N) R *r_ret) { \ - SyncSemaphore *ss = _alloc_sync_sem(); \ - CMD_RET_TYPE(N) *cmd = allocate_and_lock<CMD_RET_TYPE(N)>(); \ + MutexLock mlock(mutex); \ + CMD_RET_TYPE(N) *cmd = allocate<CMD_RET_TYPE(N)>(); \ cmd->instance = p_instance; \ cmd->method = p_method; \ SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \ cmd->ret = r_ret; \ - cmd->sync_sem = ss; \ if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \ WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \ } \ - unlock(); \ - ss->sem.wait(); \ - ss->in_use = false; \ + sync_tail++; \ + _wait_for_sync(mlock); \ } #define CMD_SYNC_TYPE(N) CommandSync##N<T, M COMMA(N) COMMA_SEP_LIST(TYPE_ARG, N)> @@ -286,39 +284,31 @@ #define DECL_PUSH_AND_SYNC(N) \ template <typename T, typename M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \ void push_and_sync(T *p_instance, M p_method COMMA(N) COMMA_SEP_LIST(PARAM, N)) { \ - SyncSemaphore *ss = _alloc_sync_sem(); \ - CMD_SYNC_TYPE(N) *cmd = allocate_and_lock<CMD_SYNC_TYPE(N)>(); \ + MutexLock mlock(mutex); \ + CMD_SYNC_TYPE(N) *cmd = allocate<CMD_SYNC_TYPE(N)>(); \ cmd->instance = p_instance; \ cmd->method = p_method; \ SEMIC_SEP_LIST(CMD_ASSIGN_PARAM, N); \ - cmd->sync_sem = ss; \ if (pump_task_id != WorkerThreadPool::INVALID_TASK_ID) { \ WorkerThreadPool::get_singleton()->notify_yield_over(pump_task_id); \ } \ - unlock(); \ - ss->sem.wait(); \ - ss->in_use = false; \ + sync_tail++; \ + _wait_for_sync(mlock); \ } #define MAX_CMD_PARAMS 15 class CommandQueueMT { - struct SyncSemaphore { - Semaphore sem; - bool in_use = false; - }; - struct CommandBase { + bool sync = false; virtual void call() = 0; - virtual SyncSemaphore *get_sync_semaphore() { return nullptr; } virtual ~CommandBase() = default; // Won't be called. }; struct SyncCommand : public CommandBase { - SyncSemaphore *sync_sem = nullptr; - - virtual SyncSemaphore *get_sync_semaphore() override { - return sync_sem; + virtual void call() override {} + SyncCommand() { + sync = true; } }; @@ -340,9 +330,11 @@ class CommandQueueMT { SYNC_SEMAPHORES = 8 }; + BinaryMutex mutex; LocalVector<uint8_t> command_mem; - SyncSemaphore sync_sems[SYNC_SEMAPHORES]; - Mutex mutex; + ConditionVariable sync_cond_var; + uint32_t sync_head = 0; + uint32_t sync_tail = 0; WorkerThreadPool::TaskID pump_task_id = WorkerThreadPool::INVALID_TASK_ID; uint64_t flush_read_ptr = 0; @@ -357,32 +349,23 @@ class CommandQueueMT { return cmd; } - template <typename T> - T *allocate_and_lock() { - lock(); - T *ret = allocate<T>(); - return ret; - } - void _flush() { - lock(); - if (unlikely(flush_read_ptr)) { // Re-entrant call. - unlock(); return; } + lock(); + WorkerThreadPool::thread_enter_command_queue_mt_flush(this); while (flush_read_ptr < command_mem.size()) { uint64_t size = *(uint64_t *)&command_mem[flush_read_ptr]; flush_read_ptr += 8; CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[flush_read_ptr]); - - SyncSemaphore *sync_sem = cmd->get_sync_semaphore(); cmd->call(); - if (sync_sem) { - sync_sem->sem.post(); // Release in case it needs sync/ret. + if (unlikely(cmd->sync)) { + sync_head++; + sync_cond_var.notify_all(); } flush_read_ptr += size; @@ -394,8 +377,12 @@ class CommandQueueMT { unlock(); } - void wait_for_flush(); - SyncSemaphore *_alloc_sync_sem(); + _FORCE_INLINE_ void _wait_for_sync(MutexLock<BinaryMutex> &p_lock) { + uint32_t sync_head_goal = sync_tail; + do { + sync_cond_var.wait(p_lock); + } while (sync_head != sync_head_goal); // Can't use lower-than because of wraparound. + } public: void lock(); diff --git a/core/templates/ring_buffer.h b/core/templates/ring_buffer.h index 54148a59bf..f5161cefa4 100644 --- a/core/templates/ring_buffer.h +++ b/core/templates/ring_buffer.h @@ -211,10 +211,10 @@ public: size_mask = mask; } - RingBuffer<T>(int p_power = 0) { + RingBuffer(int p_power = 0) { resize(p_power); } - ~RingBuffer<T>() {} + ~RingBuffer() {} }; #endif // RING_BUFFER_H diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h index 637b068da9..16b605eaff 100644 --- a/core/templates/safe_refcount.h +++ b/core/templates/safe_refcount.h @@ -146,7 +146,7 @@ public: } } - _ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) { + _ALWAYS_INLINE_ explicit SafeNumeric(T p_value = static_cast<T>(0)) { set(p_value); } }; diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h index 123f2067e2..c8d1241d3d 100644 --- a/core/variant/method_ptrcall.h +++ b/core/variant/method_ptrcall.h @@ -159,10 +159,7 @@ MAKE_PTRARG_BY_REFERENCE(Variant); template <typename T> struct PtrToArg<T *> { _FORCE_INLINE_ static T *convert(const void *p_ptr) { - if (p_ptr == nullptr) { - return nullptr; - } - return const_cast<T *>(*reinterpret_cast<T *const *>(p_ptr)); + return likely(p_ptr) ? const_cast<T *>(*reinterpret_cast<T *const *>(p_ptr)) : nullptr; } typedef Object *EncodeT; _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { @@ -173,10 +170,7 @@ struct PtrToArg<T *> { template <typename T> struct PtrToArg<const T *> { _FORCE_INLINE_ static const T *convert(const void *p_ptr) { - if (p_ptr == nullptr) { - return nullptr; - } - return *reinterpret_cast<T *const *>(p_ptr); + return likely(p_ptr) ? *reinterpret_cast<T *const *>(p_ptr) : nullptr; } typedef const Object *EncodeT; _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { diff --git a/core/variant/type_info.h b/core/variant/type_info.h index 9c52db3345..15cb6c9c1a 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -33,31 +33,7 @@ #include "core/typedefs.h" -template <bool C, typename T = void> -struct EnableIf { - typedef T type; -}; - -template <typename T> -struct EnableIf<false, T> { -}; - -template <typename, typename> -inline constexpr bool types_are_same_v = false; - -template <typename T> -inline constexpr bool types_are_same_v<T, T> = true; - -template <typename B, typename D> -struct TypeInherits { - static D *get_d(); - - static char (&test(B *))[1]; - static char (&test(...))[2]; - - static bool const value = sizeof(test(get_d())) == sizeof(char) && - !types_are_same_v<B volatile const, void volatile const>; -}; +#include <type_traits> namespace GodotTypeInfo { enum Metadata { @@ -223,16 +199,7 @@ MAKE_TEMPLATE_TYPE_INFO(Vector, Face3, Variant::PACKED_VECTOR3_ARRAY) MAKE_TEMPLATE_TYPE_INFO(Vector, StringName, Variant::PACKED_STRING_ARRAY) template <typename T> -struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> { - static const Variant::Type VARIANT_TYPE = Variant::OBJECT; - static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; - static inline PropertyInfo get_class_info() { - return PropertyInfo(StringName(T::get_class_static())); - } -}; - -template <typename T> -struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> { +struct GetTypeInfo<T *, std::enable_if_t<std::is_base_of_v<Object, T>>> { static const Variant::Type VARIANT_TYPE = Variant::OBJECT; static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; static inline PropertyInfo get_class_info() { diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 155a5b2781..fcbfdd4741 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -2373,184 +2373,183 @@ Variant::operator IPAddress() const { return IPAddress(operator String()); } -Variant::Variant(bool p_bool) { - type = BOOL; +Variant::Variant(bool p_bool) : + type(BOOL) { _data._bool = p_bool; } -Variant::Variant(int64_t p_int64) { - type = INT; +Variant::Variant(int64_t p_int64) : + type(INT) { _data._int = p_int64; } -Variant::Variant(int32_t p_int32) { - type = INT; +Variant::Variant(int32_t p_int32) : + type(INT) { _data._int = p_int32; } -Variant::Variant(int16_t p_int16) { - type = INT; +Variant::Variant(int16_t p_int16) : + type(INT) { _data._int = p_int16; } -Variant::Variant(int8_t p_int8) { - type = INT; +Variant::Variant(int8_t p_int8) : + type(INT) { _data._int = p_int8; } -Variant::Variant(uint64_t p_uint64) { - type = INT; +Variant::Variant(uint64_t p_uint64) : + type(INT) { _data._int = p_uint64; } -Variant::Variant(uint32_t p_uint32) { - type = INT; +Variant::Variant(uint32_t p_uint32) : + type(INT) { _data._int = p_uint32; } -Variant::Variant(uint16_t p_uint16) { - type = INT; +Variant::Variant(uint16_t p_uint16) : + type(INT) { _data._int = p_uint16; } -Variant::Variant(uint8_t p_uint8) { - type = INT; +Variant::Variant(uint8_t p_uint8) : + type(INT) { _data._int = p_uint8; } -Variant::Variant(float p_float) { - type = FLOAT; +Variant::Variant(float p_float) : + type(FLOAT) { _data._float = p_float; } -Variant::Variant(double p_double) { - type = FLOAT; +Variant::Variant(double p_double) : + type(FLOAT) { _data._float = p_double; } -Variant::Variant(const ObjectID &p_id) { - type = INT; +Variant::Variant(const ObjectID &p_id) : + type(INT) { _data._int = p_id; } -Variant::Variant(const StringName &p_string) { - type = STRING_NAME; +Variant::Variant(const StringName &p_string) : + type(STRING_NAME) { memnew_placement(_data._mem, StringName(p_string)); } -Variant::Variant(const String &p_string) { - type = STRING; +Variant::Variant(const String &p_string) : + type(STRING) { memnew_placement(_data._mem, String(p_string)); } -Variant::Variant(const char *const p_cstring) { - type = STRING; +Variant::Variant(const char *const p_cstring) : + type(STRING) { memnew_placement(_data._mem, String((const char *)p_cstring)); } -Variant::Variant(const char32_t *p_wstring) { - type = STRING; +Variant::Variant(const char32_t *p_wstring) : + type(STRING) { memnew_placement(_data._mem, String(p_wstring)); } -Variant::Variant(const Vector3 &p_vector3) { - type = VECTOR3; +Variant::Variant(const Vector3 &p_vector3) : + type(VECTOR3) { memnew_placement(_data._mem, Vector3(p_vector3)); } -Variant::Variant(const Vector3i &p_vector3i) { - type = VECTOR3I; +Variant::Variant(const Vector3i &p_vector3i) : + type(VECTOR3I) { memnew_placement(_data._mem, Vector3i(p_vector3i)); } -Variant::Variant(const Vector4 &p_vector4) { - type = VECTOR4; +Variant::Variant(const Vector4 &p_vector4) : + type(VECTOR4) { memnew_placement(_data._mem, Vector4(p_vector4)); } -Variant::Variant(const Vector4i &p_vector4i) { - type = VECTOR4I; +Variant::Variant(const Vector4i &p_vector4i) : + type(VECTOR4I) { memnew_placement(_data._mem, Vector4i(p_vector4i)); } -Variant::Variant(const Vector2 &p_vector2) { - type = VECTOR2; +Variant::Variant(const Vector2 &p_vector2) : + type(VECTOR2) { memnew_placement(_data._mem, Vector2(p_vector2)); } -Variant::Variant(const Vector2i &p_vector2i) { - type = VECTOR2I; +Variant::Variant(const Vector2i &p_vector2i) : + type(VECTOR2I) { memnew_placement(_data._mem, Vector2i(p_vector2i)); } -Variant::Variant(const Rect2 &p_rect2) { - type = RECT2; +Variant::Variant(const Rect2 &p_rect2) : + type(RECT2) { memnew_placement(_data._mem, Rect2(p_rect2)); } -Variant::Variant(const Rect2i &p_rect2i) { - type = RECT2I; +Variant::Variant(const Rect2i &p_rect2i) : + type(RECT2I) { memnew_placement(_data._mem, Rect2i(p_rect2i)); } -Variant::Variant(const Plane &p_plane) { - type = PLANE; +Variant::Variant(const Plane &p_plane) : + type(PLANE) { memnew_placement(_data._mem, Plane(p_plane)); } -Variant::Variant(const ::AABB &p_aabb) { - type = AABB; +Variant::Variant(const ::AABB &p_aabb) : + type(AABB) { _data._aabb = (::AABB *)Pools::_bucket_small.alloc(); memnew_placement(_data._aabb, ::AABB(p_aabb)); } -Variant::Variant(const Basis &p_matrix) { - type = BASIS; +Variant::Variant(const Basis &p_matrix) : + type(BASIS) { _data._basis = (Basis *)Pools::_bucket_medium.alloc(); memnew_placement(_data._basis, Basis(p_matrix)); } -Variant::Variant(const Quaternion &p_quaternion) { - type = QUATERNION; +Variant::Variant(const Quaternion &p_quaternion) : + type(QUATERNION) { memnew_placement(_data._mem, Quaternion(p_quaternion)); } -Variant::Variant(const Transform3D &p_transform) { - type = TRANSFORM3D; +Variant::Variant(const Transform3D &p_transform) : + type(TRANSFORM3D) { _data._transform3d = (Transform3D *)Pools::_bucket_medium.alloc(); memnew_placement(_data._transform3d, Transform3D(p_transform)); } -Variant::Variant(const Projection &pp_projection) { - type = PROJECTION; +Variant::Variant(const Projection &pp_projection) : + type(PROJECTION) { _data._projection = (Projection *)Pools::_bucket_large.alloc(); memnew_placement(_data._projection, Projection(pp_projection)); } -Variant::Variant(const Transform2D &p_transform) { - type = TRANSFORM2D; +Variant::Variant(const Transform2D &p_transform) : + type(TRANSFORM2D) { _data._transform2d = (Transform2D *)Pools::_bucket_small.alloc(); memnew_placement(_data._transform2d, Transform2D(p_transform)); } -Variant::Variant(const Color &p_color) { - type = COLOR; +Variant::Variant(const Color &p_color) : + type(COLOR) { memnew_placement(_data._mem, Color(p_color)); } -Variant::Variant(const NodePath &p_node_path) { - type = NODE_PATH; +Variant::Variant(const NodePath &p_node_path) : + type(NODE_PATH) { memnew_placement(_data._mem, NodePath(p_node_path)); } -Variant::Variant(const ::RID &p_rid) { - type = RID; +Variant::Variant(const ::RID &p_rid) : + type(RID) { memnew_placement(_data._mem, ::RID(p_rid)); } -Variant::Variant(const Object *p_object) { - type = OBJECT; - +Variant::Variant(const Object *p_object) : + type(OBJECT) { memnew_placement(_data._mem, ObjData); if (p_object) { @@ -2571,76 +2570,74 @@ Variant::Variant(const Object *p_object) { } } -Variant::Variant(const Callable &p_callable) { - type = CALLABLE; +Variant::Variant(const Callable &p_callable) : + type(CALLABLE) { memnew_placement(_data._mem, Callable(p_callable)); } -Variant::Variant(const Signal &p_callable) { - type = SIGNAL; +Variant::Variant(const Signal &p_callable) : + type(SIGNAL) { memnew_placement(_data._mem, Signal(p_callable)); } -Variant::Variant(const Dictionary &p_dictionary) { - type = DICTIONARY; +Variant::Variant(const Dictionary &p_dictionary) : + type(DICTIONARY) { memnew_placement(_data._mem, Dictionary(p_dictionary)); } -Variant::Variant(const Array &p_array) { - type = ARRAY; +Variant::Variant(const Array &p_array) : + type(ARRAY) { memnew_placement(_data._mem, Array(p_array)); } -Variant::Variant(const PackedByteArray &p_byte_array) { - type = PACKED_BYTE_ARRAY; - +Variant::Variant(const PackedByteArray &p_byte_array) : + type(PACKED_BYTE_ARRAY) { _data.packed_array = PackedArrayRef<uint8_t>::create(p_byte_array); } -Variant::Variant(const PackedInt32Array &p_int32_array) { - type = PACKED_INT32_ARRAY; +Variant::Variant(const PackedInt32Array &p_int32_array) : + type(PACKED_INT32_ARRAY) { _data.packed_array = PackedArrayRef<int32_t>::create(p_int32_array); } -Variant::Variant(const PackedInt64Array &p_int64_array) { - type = PACKED_INT64_ARRAY; +Variant::Variant(const PackedInt64Array &p_int64_array) : + type(PACKED_INT64_ARRAY) { _data.packed_array = PackedArrayRef<int64_t>::create(p_int64_array); } -Variant::Variant(const PackedFloat32Array &p_float32_array) { - type = PACKED_FLOAT32_ARRAY; +Variant::Variant(const PackedFloat32Array &p_float32_array) : + type(PACKED_FLOAT32_ARRAY) { _data.packed_array = PackedArrayRef<float>::create(p_float32_array); } -Variant::Variant(const PackedFloat64Array &p_float64_array) { - type = PACKED_FLOAT64_ARRAY; +Variant::Variant(const PackedFloat64Array &p_float64_array) : + type(PACKED_FLOAT64_ARRAY) { _data.packed_array = PackedArrayRef<double>::create(p_float64_array); } -Variant::Variant(const PackedStringArray &p_string_array) { - type = PACKED_STRING_ARRAY; +Variant::Variant(const PackedStringArray &p_string_array) : + type(PACKED_STRING_ARRAY) { _data.packed_array = PackedArrayRef<String>::create(p_string_array); } -Variant::Variant(const PackedVector2Array &p_vector2_array) { - type = PACKED_VECTOR2_ARRAY; +Variant::Variant(const PackedVector2Array &p_vector2_array) : + type(PACKED_VECTOR2_ARRAY) { _data.packed_array = PackedArrayRef<Vector2>::create(p_vector2_array); } -Variant::Variant(const PackedVector3Array &p_vector3_array) { - type = PACKED_VECTOR3_ARRAY; +Variant::Variant(const PackedVector3Array &p_vector3_array) : + type(PACKED_VECTOR3_ARRAY) { _data.packed_array = PackedArrayRef<Vector3>::create(p_vector3_array); } -Variant::Variant(const PackedColorArray &p_color_array) { - type = PACKED_COLOR_ARRAY; +Variant::Variant(const PackedColorArray &p_color_array) : + type(PACKED_COLOR_ARRAY) { _data.packed_array = PackedArrayRef<Color>::create(p_color_array); } /* helpers */ -Variant::Variant(const Vector<::RID> &p_array) { - type = ARRAY; - +Variant::Variant(const Vector<::RID> &p_array) : + type(ARRAY) { Array *rid_array = memnew_placement(_data._mem, Array); rid_array->resize(p_array.size()); @@ -2650,9 +2647,8 @@ Variant::Variant(const Vector<::RID> &p_array) { } } -Variant::Variant(const Vector<Plane> &p_array) { - type = ARRAY; - +Variant::Variant(const Vector<Plane> &p_array) : + type(ARRAY) { Array *plane_array = memnew_placement(_data._mem, Array); plane_array->resize(p_array.size()); @@ -2662,7 +2658,8 @@ Variant::Variant(const Vector<Plane> &p_array) { } } -Variant::Variant(const Vector<Face3> &p_face_array) { +Variant::Variant(const Vector<Face3> &p_face_array) : + type(NIL) { PackedVector3Array vertices; int face_count = p_face_array.size(); vertices.resize(face_count * 3); @@ -2678,13 +2675,11 @@ Variant::Variant(const Vector<Face3> &p_face_array) { } } - type = NIL; - *this = vertices; } -Variant::Variant(const Vector<Variant> &p_array) { - type = NIL; +Variant::Variant(const Vector<Variant> &p_array) : + type(NIL) { Array arr; arr.resize(p_array.size()); for (int i = 0; i < p_array.size(); i++) { @@ -2693,8 +2688,8 @@ Variant::Variant(const Vector<Variant> &p_array) { *this = arr; } -Variant::Variant(const Vector<StringName> &p_array) { - type = NIL; +Variant::Variant(const Vector<StringName> &p_array) : + type(NIL) { PackedStringArray v; int len = p_array.size(); v.resize(len); @@ -2863,12 +2858,13 @@ void Variant::operator=(const Variant &p_variant) { } } -Variant::Variant(const IPAddress &p_address) { - type = STRING; +Variant::Variant(const IPAddress &p_address) : + type(STRING) { memnew_placement(_data._mem, String(p_address)); } -Variant::Variant(const Variant &p_variant) { +Variant::Variant(const Variant &p_variant) : + type(NIL) { reference(p_variant); } @@ -3499,50 +3495,6 @@ bool Variant::is_ref_counted() const { return type == OBJECT && _get_obj().id.is_ref_counted(); } -Vector<Variant> varray() { - return Vector<Variant>(); -} - -Vector<Variant> varray(const Variant &p_arg1) { - Vector<Variant> v; - v.push_back(p_arg1); - return v; -} - -Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2) { - Vector<Variant> v; - v.push_back(p_arg1); - v.push_back(p_arg2); - return v; -} - -Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3) { - Vector<Variant> v; - v.push_back(p_arg1); - v.push_back(p_arg2); - v.push_back(p_arg3); - return v; -} - -Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4) { - Vector<Variant> v; - v.push_back(p_arg1); - v.push_back(p_arg2); - v.push_back(p_arg3); - v.push_back(p_arg4); - return v; -} - -Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5) { - Vector<Variant> v; - v.push_back(p_arg1); - v.push_back(p_arg2); - v.push_back(p_arg3); - v.push_back(p_arg4); - v.push_back(p_arg5); - return v; -} - void Variant::static_assign(const Variant &p_variant) { } diff --git a/core/variant/variant.h b/core/variant/variant.h index 10f8dc3c7f..ea6ae02c1e 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -165,7 +165,7 @@ private: // Variant takes 20 bytes when real_t is float, and 36 if double // it only allocates extra memory for aabb/matrix. - Type type = NIL; + Type type; struct ObjData { ObjectID id; @@ -483,8 +483,8 @@ public: Variant(const IPAddress &p_address); #define VARIANT_ENUM_CLASS_CONSTRUCTOR(m_enum) \ - Variant(m_enum p_value) { \ - type = INT; \ + Variant(m_enum p_value) : \ + type(INT) { \ _data._int = (int64_t)p_value; \ } @@ -788,7 +788,8 @@ public: static void unregister_types(); Variant(const Variant &p_variant); - _FORCE_INLINE_ Variant() {} + _FORCE_INLINE_ Variant() : + type(NIL) {} _FORCE_INLINE_ ~Variant() { clear(); } @@ -797,12 +798,23 @@ public: //typedef Dictionary Dictionary; no //typedef Array Array; -Vector<Variant> varray(); -Vector<Variant> varray(const Variant &p_arg1); -Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2); -Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3); -Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4); -Vector<Variant> varray(const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5); +template <typename... VarArgs> +Vector<Variant> varray(VarArgs... p_args) { + Vector<Variant> v; + + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + uint32_t argc = sizeof...(p_args); + + if (argc > 0) { + v.resize(argc); + Variant *vw = v.ptrw(); + + for (uint32_t i = 0; i < argc; i++) { + vw[i] = args[i]; + } + } + return v; +} struct VariantHasher { static _FORCE_INLINE_ uint32_t hash(const Variant &p_variant) { return p_variant.hash(); } diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index dcb94b16b1..50f8007efa 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -489,11 +489,11 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri r_token.value = num.as_int(); } return OK; - } else if (is_ascii_char(cchar) || is_underscore(cchar)) { + } else if (is_ascii_alphabet_char(cchar) || is_underscore(cchar)) { StringBuffer<> id; bool first = true; - while (is_ascii_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) { + while (is_ascii_alphabet_char(cchar) || is_underscore(cchar) || (!first && is_digit(cchar))) { id += cchar; cchar = p_stream->get_char(); first = false; @@ -1789,7 +1789,7 @@ static String rtos_fix(double p_value) { } } -Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count) { +Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count, bool p_compat) { switch (p_variant.get_type()) { case Variant::NIL: { p_store_string_func(p_store_string_ud, "null"); @@ -2009,7 +2009,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } p_store_string_func(p_store_string_ud, "\"" + E.name + "\":"); - write(obj->get(E.name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); + write(obj->get(E.name), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat); } } @@ -2035,9 +2035,9 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, "{\n"); for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { - write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); + write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat); p_store_string_func(p_store_string_ud, ": "); - write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); + write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat); if (E->next()) { p_store_string_func(p_store_string_ud, ",\n"); } else { @@ -2096,7 +2096,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } else { p_store_string_func(p_store_string_ud, ", "); } - write(var, p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count); + write(var, p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, p_recursion_count, p_compat); } p_store_string_func(p_store_string_ud, "]"); @@ -2110,7 +2110,16 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str case Variant::PACKED_BYTE_ARRAY: { p_store_string_func(p_store_string_ud, "PackedByteArray("); Vector<uint8_t> data = p_variant; - if (data.size() > 0) { + if (p_compat) { + int len = data.size(); + const uint8_t *ptr = data.ptr(); + for (int i = 0; i < len; i++) { + if (i > 0) { + p_store_string_func(p_store_string_ud, ", "); + } + p_store_string_func(p_store_string_ud, itos(ptr[i])); + } + } else if (data.size() > 0) { p_store_string_func(p_store_string_ud, "\""); p_store_string_func(p_store_string_ud, CryptoCore::b64_encode_str(data.ptr(), data.size())); p_store_string_func(p_store_string_ud, "\""); @@ -2255,8 +2264,8 @@ static Error _write_to_str(void *ud, const String &p_string) { return OK; } -Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud) { +Error VariantWriter::write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, bool p_compat) { r_string = String(); - return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud); + return write(p_variant, _write_to_str, &r_string, p_encode_res_func, p_encode_res_ud, 0, p_compat); } diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h index 2f8974849f..b0ac07170d 100644 --- a/core/variant/variant_parser.h +++ b/core/variant/variant_parser.h @@ -161,8 +161,8 @@ public: typedef Error (*StoreStringFunc)(void *ud, const String &p_string); typedef String (*EncodeResourceFunc)(void *ud, const Ref<Resource> &p_resource); - static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0); - static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr); + static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int p_recursion_count = 0, bool p_compat = true); + static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr, bool p_compat = true); }; #endif // VARIANT_PARSER_H diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 9d5ed22b1a..f49e9e54b3 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -251,15 +251,21 @@ void Variant::set_named(const StringName &p_member, const Variant &p_value, bool return; } } else if (type == Variant::DICTIONARY) { - Variant *v = VariantGetInternalPtr<Dictionary>::get_ptr(this)->getptr(p_member); + Dictionary &dict = *VariantGetInternalPtr<Dictionary>::get_ptr(this); + + if (dict.is_read_only()) { + r_valid = false; + return; + } + + Variant *v = dict.getptr(p_member); if (v) { *v = p_value; - r_valid = true; } else { - VariantGetInternalPtr<Dictionary>::get_ptr(this)->operator[](p_member) = p_value; - r_valid = true; + dict[p_member] = p_value; } + r_valid = true; } else { r_valid = false; } |