diff options
Diffstat (limited to 'core')
70 files changed, 955 insertions, 781 deletions
diff --git a/core/SCsub b/core/SCsub index a0176f6c33..7e9cd97351 100644 --- a/core/SCsub +++ b/core/SCsub @@ -65,7 +65,7 @@ thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_mis env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources) # Brotli -if env["brotli"]: +if env["brotli"] and env["builtin_brotli"]: thirdparty_brotli_dir = "#thirdparty/brotli/" thirdparty_brotli_sources = [ "common/constants.c", diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index cb25dc9ebf..79fab50882 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -67,14 +67,6 @@ String ProjectSettings::get_resource_path() const { return resource_path; } -String ProjectSettings::get_safe_project_name() const { - String safe_name = OS::get_singleton()->get_safe_dir_name(get("application/config/name")); - if (safe_name.is_empty()) { - safe_name = "UnnamedProject"; - } - return safe_name; -} - String ProjectSettings::get_imported_files_path() const { return get_project_data_path().path_join("imported"); } @@ -930,10 +922,26 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<Str } Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other params as dictionary and array? - return save_custom(p_file); } +#ifdef TOOLS_ENABLED +bool _csproj_exists(String p_root_dir) { + Ref<DirAccess> dir = DirAccess::open(p_root_dir); + + dir->list_dir_begin(); + String file_name = dir->_get_next(); + while (file_name != "") { + if (!dir->current_is_dir() && file_name.get_extension() == "csproj") { + return true; + } + file_name = dir->_get_next(); + } + + return false; +} +#endif // TOOLS_ENABLED + Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features, bool p_merge_with_current) { ERR_FAIL_COND_V_MSG(p_path.is_empty(), ERR_INVALID_PARAMETER, "Project settings save path cannot be empty."); @@ -952,7 +960,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust } } // Check for the existence of a csproj file. - if (FileAccess::exists(get_resource_path().path_join(get_safe_project_name() + ".csproj"))) { + if (_csproj_exists(get_resource_path())) { // 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#"); diff --git a/core/config/project_settings.h b/core/config/project_settings.h index a0249ef267..b89e6694b0 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -166,7 +166,6 @@ public: String get_project_data_dir_name() const; String get_project_data_path() const; String get_resource_path() const; - String get_safe_project_name() const; String get_imported_files_path() const; static ProjectSettings *get_singleton(); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 8771aa88cc..2d0d24406c 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -39,6 +39,7 @@ #include "core/math/geometry_2d.h" #include "core/math/geometry_3d.h" #include "core/os/keyboard.h" +#include "core/os/thread_safe.h" #include "core/variant/typed_array.h" namespace core_bind { @@ -1187,7 +1188,11 @@ void Thread::_start_func(void *ud) { ERR_FAIL_MSG(vformat("Could not call function '%s' on previously freed instance to start thread %s.", t->target_callable.get_method(), t->get_id())); } + // Finding out a suitable name for the thread can involve querying a node, if the target is one. + // We know this is safe (unless the user is causing life cycle race conditions, which would be a bug on their part). + set_current_thread_safe_for_nodes(true); String func_name = t->target_callable.is_custom() ? t->target_callable.get_custom()->get_as_text() : String(t->target_callable.get_method()); + set_current_thread_safe_for_nodes(false); ::Thread::set_name(func_name); // To avoid a circular reference between the thread and the script which can possibly contain a reference @@ -1255,6 +1260,11 @@ Variant Thread::wait_to_finish() { return r; } +void Thread::set_thread_safety_checks_enabled(bool p_enabled) { + ERR_FAIL_COND_MSG(::Thread::is_main_thread(), "This call is forbidden on the main thread."); + set_current_thread_safe_for_nodes(!p_enabled); +} + void Thread::_bind_methods() { ClassDB::bind_method(D_METHOD("start", "callable", "priority"), &Thread::start, DEFVAL(PRIORITY_NORMAL)); ClassDB::bind_method(D_METHOD("get_id"), &Thread::get_id); @@ -1262,6 +1272,8 @@ void Thread::_bind_methods() { ClassDB::bind_method(D_METHOD("is_alive"), &Thread::is_alive); ClassDB::bind_method(D_METHOD("wait_to_finish"), &Thread::wait_to_finish); + ClassDB::bind_static_method("Thread", D_METHOD("set_thread_safety_checks_enabled", "enabled"), &Thread::set_thread_safety_checks_enabled); + BIND_ENUM_CONSTANT(PRIORITY_LOW); BIND_ENUM_CONSTANT(PRIORITY_NORMAL); BIND_ENUM_CONSTANT(PRIORITY_HIGH); diff --git a/core/core_bind.h b/core/core_bind.h index 55c365eb7c..6b25510b14 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -408,6 +408,8 @@ public: bool is_started() const; bool is_alive() const; Variant wait_to_finish(); + + static void set_thread_safety_checks_enabled(bool p_enabled); }; namespace special { diff --git a/core/core_builders.py b/core/core_builders.py index b0a3b85d58..e40ebbb14d 100644 --- a/core/core_builders.py +++ b/core/core_builders.py @@ -239,7 +239,6 @@ def make_license_header(target, source, env): data_list += part["Copyright"] with open(dst, "w", encoding="utf-8") as f: - f.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") f.write("#ifndef LICENSE_GEN_H\n") f.write("#define LICENSE_GEN_H\n") diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp index 623b1eb0ce..dc46ffc307 100644 --- a/core/debugger/local_debugger.cpp +++ b/core/debugger/local_debugger.cpp @@ -138,7 +138,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { // Cache options String variable_prefix = options["variable_prefix"]; - if (line.is_empty()) { + if (line.is_empty() && !feof(stdin)) { print_line("\nDebugger Break, Reason: '" + script_lang->debug_get_error() + "'"); print_line("*Frame " + itos(current_frame) + " - " + script_lang->debug_get_stack_level_source(current_frame) + ":" + itos(script_lang->debug_get_stack_level_line(current_frame)) + " in function '" + script_lang->debug_get_stack_level_function(current_frame) + "'"); print_line("Enter \"help\" for assistance."); @@ -267,7 +267,8 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { print_line("Added breakpoint at " + source + ":" + itos(linenr)); } - } else if (line == "q" || line == "quit") { + } else if (line == "q" || line == "quit" || + (line.is_empty() && feof(stdin))) { // Do not stop again on quit script_debugger->clear_breakpoints(); script_debugger->set_depth(-1); diff --git a/core/doc_data.cpp b/core/doc_data.cpp index 2d909f5335..7549ba884e 100644 --- a/core/doc_data.cpp +++ b/core/doc_data.cpp @@ -51,6 +51,7 @@ void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const Proper if (p_method.return_enum.begins_with("_")) { //proxy class p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length()); } + p_method.return_is_bitfield = p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD; p_method.return_type = "int"; } else if (p_retinfo.class_name != StringName()) { p_method.return_type = p_retinfo.class_name; @@ -82,6 +83,7 @@ void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const if (p_argument.enumeration.begins_with("_")) { //proxy class p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length()); } + p_argument.is_bitfield = p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_BITFIELD; p_argument.type = "int"; } else if (p_arginfo.class_name != StringName()) { p_argument.type = p_arginfo.class_name; diff --git a/core/doc_data.h b/core/doc_data.h index fc184c411c..0fe7414b98 100644 --- a/core/doc_data.h +++ b/core/doc_data.h @@ -50,6 +50,7 @@ public: String name; String type; String enumeration; + bool is_bitfield = false; String default_value; bool operator<(const ArgumentDoc &p_arg) const { if (name == p_arg.name) { @@ -70,6 +71,9 @@ public: if (p_dict.has("enumeration")) { doc.enumeration = p_dict["enumeration"]; + if (p_dict.has("is_bitfield")) { + doc.is_bitfield = p_dict["is_bitfield"]; + } } if (p_dict.has("default_value")) { @@ -91,6 +95,7 @@ public: if (!p_doc.enumeration.is_empty()) { dict["enumeration"] = p_doc.enumeration; + dict["is_bitfield"] = p_doc.is_bitfield; } if (!p_doc.default_value.is_empty()) { @@ -105,6 +110,7 @@ public: String name; String return_type; String return_enum; + bool return_is_bitfield = false; String qualifiers; String description; bool is_deprecated = false; @@ -152,6 +158,9 @@ public: if (p_dict.has("return_enum")) { doc.return_enum = p_dict["return_enum"]; + if (p_dict.has("return_is_bitfield")) { + doc.return_is_bitfield = p_dict["return_is_bitfield"]; + } } if (p_dict.has("qualifiers")) { @@ -201,6 +210,7 @@ public: if (!p_doc.return_enum.is_empty()) { dict["return_enum"] = p_doc.return_enum; + dict["return_is_bitfield"] = p_doc.return_is_bitfield; } if (!p_doc.qualifiers.is_empty()) { @@ -264,10 +274,9 @@ public: if (p_dict.has("enumeration")) { doc.enumeration = p_dict["enumeration"]; - } - - if (p_dict.has("is_bitfield")) { - doc.is_bitfield = p_dict["is_bitfield"]; + if (p_dict.has("is_bitfield")) { + doc.is_bitfield = p_dict["is_bitfield"]; + } } if (p_dict.has("description")) { @@ -299,10 +308,9 @@ public: if (!p_doc.enumeration.is_empty()) { dict["enumeration"] = p_doc.enumeration; + dict["is_bitfield"] = p_doc.is_bitfield; } - dict["is_bitfield"] = p_doc.is_bitfield; - if (!p_doc.description.is_empty()) { dict["description"] = p_doc.description; } @@ -319,6 +327,7 @@ public: String name; String type; String enumeration; + bool is_bitfield = false; String description; String setter, getter; String default_value; @@ -342,6 +351,9 @@ public: if (p_dict.has("enumeration")) { doc.enumeration = p_dict["enumeration"]; + if (p_dict.has("is_bitfield")) { + doc.is_bitfield = p_dict["is_bitfield"]; + } } if (p_dict.has("description")) { @@ -391,6 +403,7 @@ public: if (!p_doc.enumeration.is_empty()) { dict["enumeration"] = p_doc.enumeration; + dict["is_bitfield"] = p_doc.is_bitfield; } if (!p_doc.description.is_empty()) { diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 8bdea01ae6..73526fae3e 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -37,7 +37,6 @@ #include "core/version.h" extern void gdextension_setup_interface(); -extern void *gdextension_get_legacy_interface(); extern GDExtensionInterfaceFunctionPtr gdextension_get_proc_address(const char *p_name); typedef GDExtensionBool (*GDExtensionLegacyInitializationFunction)(void *p_interface, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization); @@ -450,7 +449,7 @@ GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(StringName p return *function; } -Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol, bool p_use_legacy_interface) { +Error GDExtension::open_library(const String &p_path, const String &p_entry_symbol) { Error err = OS::get_singleton()->open_dynamic_library(p_path, library, true, &library_path); if (err != OK) { ERR_PRINT("GDExtension dynamic library not found: " + p_path); @@ -467,15 +466,8 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb return err; } - GDExtensionBool ret = 0; - if (p_use_legacy_interface) { - GDExtensionLegacyInitializationFunction initialization_function = (GDExtensionLegacyInitializationFunction)entry_funcptr; - ret = initialization_function(gdextension_get_legacy_interface(), this, &initialization); - - } else { - GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr; - ret = initialization_function(&gdextension_get_proc_address, this, &initialization); - } + GDExtensionInitializationFunction initialization_function = (GDExtensionInitializationFunction)entry_funcptr; + GDExtensionBool ret = initialization_function(&gdextension_get_proc_address, this, &initialization); if (ret) { level_initialized = -1; @@ -486,10 +478,6 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb } } -Error GDExtension::open_library_compat_76406(const String &p_path, const String &p_entry_symbol) { - return open_library(p_path, p_entry_symbol, true); -} - void GDExtension::close_library() { ERR_FAIL_COND(library == nullptr); OS::get_singleton()->close_dynamic_library(library); @@ -525,8 +513,7 @@ void GDExtension::deinitialize_library(InitializationLevel p_level) { } void GDExtension::_bind_methods() { - ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol", "use_legacy_interface"), &GDExtension::open_library, DEFVAL(false)); - ClassDB::bind_compatibility_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library_compat_76406); + ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol"), &GDExtension::open_library); ClassDB::bind_method(D_METHOD("close_library"), &GDExtension::close_library); ClassDB::bind_method(D_METHOD("is_library_open"), &GDExtension::is_library_open); @@ -599,9 +586,20 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String compatibility_minimum[i] = parts[i]; } } + } else { + if (r_error) { + *r_error = ERR_INVALID_DATA; + } + ERR_PRINT("GDExtension configuration file must contain a \"configuration/compatibility_minimum\" key: " + p_path); + return Ref<Resource>(); } - if (compatibility_minimum[0] < 4) { - compatibility_minimum[0] = 4; + + if (compatibility_minimum[0] < 4 || (compatibility_minimum[0] == 4 && compatibility_minimum[1] == 0)) { + if (r_error) { + *r_error = ERR_INVALID_DATA; + } + ERR_PRINT(vformat("GDExtension's compatibility_minimum (%d.%d.%d) must be at least 4.1.0: %s", compatibility_minimum[0], compatibility_minimum[1], compatibility_minimum[2], p_path)); + return Ref<Resource>(); } bool compatible = true; @@ -635,12 +633,10 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String library_path = p_path.get_base_dir().path_join(library_path); } - bool use_legacy_interface = compatibility_minimum[0] == 4 && compatibility_minimum[1] == 0; - Ref<GDExtension> lib; lib.instantiate(); String abs_path = ProjectSettings::get_singleton()->globalize_path(library_path); - err = lib->open_library(abs_path, entry_symbol, use_legacy_interface); + err = lib->open_library(abs_path, entry_symbol); if (r_error) { *r_error = err; diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index 49f1cf1d8e..77ec458d30 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -72,8 +72,7 @@ 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); - Error open_library(const String &p_path, const String &p_entry_symbol, bool p_use_legacy_interface = false); - Error open_library_compat_76406(const String &p_path, const String &p_entry_symbol); + Error open_library(const String &p_path, const String &p_entry_symbol); void close_library(); enum InitializationLevel { diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp index 21d34b6e0c..7fbf2d00a1 100644 --- a/core/extension/gdextension_interface.cpp +++ b/core/extension/gdextension_interface.cpp @@ -1218,322 +1218,3 @@ void gdextension_setup_interface() { } #undef REGISTER_INTERFACE_FUNCTION - -/* - * Handle legacy GDExtension interface from Godot 4.0. - */ - -typedef struct { - uint32_t version_major; - uint32_t version_minor; - uint32_t version_patch; - const char *version_string; - - GDExtensionInterfaceMemAlloc mem_alloc; - GDExtensionInterfaceMemRealloc mem_realloc; - GDExtensionInterfaceMemFree mem_free; - - GDExtensionInterfacePrintError print_error; - GDExtensionInterfacePrintErrorWithMessage print_error_with_message; - GDExtensionInterfacePrintWarning print_warning; - GDExtensionInterfacePrintWarningWithMessage print_warning_with_message; - GDExtensionInterfacePrintScriptError print_script_error; - GDExtensionInterfacePrintScriptErrorWithMessage print_script_error_with_message; - - GDExtensionInterfaceGetNativeStructSize get_native_struct_size; - - GDExtensionInterfaceVariantNewCopy variant_new_copy; - GDExtensionInterfaceVariantNewNil variant_new_nil; - GDExtensionInterfaceVariantDestroy variant_destroy; - - GDExtensionInterfaceVariantCall variant_call; - GDExtensionInterfaceVariantCallStatic variant_call_static; - GDExtensionInterfaceVariantEvaluate variant_evaluate; - GDExtensionInterfaceVariantSet variant_set; - GDExtensionInterfaceVariantSetNamed variant_set_named; - GDExtensionInterfaceVariantSetKeyed variant_set_keyed; - GDExtensionInterfaceVariantSetIndexed variant_set_indexed; - GDExtensionInterfaceVariantGet variant_get; - GDExtensionInterfaceVariantGetNamed variant_get_named; - GDExtensionInterfaceVariantGetKeyed variant_get_keyed; - GDExtensionInterfaceVariantGetIndexed variant_get_indexed; - GDExtensionInterfaceVariantIterInit variant_iter_init; - GDExtensionInterfaceVariantIterNext variant_iter_next; - GDExtensionInterfaceVariantIterGet variant_iter_get; - GDExtensionInterfaceVariantHash variant_hash; - GDExtensionInterfaceVariantRecursiveHash variant_recursive_hash; - GDExtensionInterfaceVariantHashCompare variant_hash_compare; - GDExtensionInterfaceVariantBooleanize variant_booleanize; - GDExtensionInterfaceVariantDuplicate variant_duplicate; - GDExtensionInterfaceVariantStringify variant_stringify; - - GDExtensionInterfaceVariantGetType variant_get_type; - GDExtensionInterfaceVariantHasMethod variant_has_method; - GDExtensionInterfaceVariantHasMember variant_has_member; - GDExtensionInterfaceVariantHasKey variant_has_key; - GDExtensionInterfaceVariantGetTypeName variant_get_type_name; - GDExtensionInterfaceVariantCanConvert variant_can_convert; - GDExtensionInterfaceVariantCanConvertStrict variant_can_convert_strict; - - GDExtensionInterfaceGetVariantFromTypeConstructor get_variant_from_type_constructor; - GDExtensionInterfaceGetVariantToTypeConstructor get_variant_to_type_constructor; - GDExtensionInterfaceVariantGetPtrOperatorEvaluator variant_get_ptr_operator_evaluator; - GDExtensionInterfaceVariantGetPtrBuiltinMethod variant_get_ptr_builtin_method; - GDExtensionInterfaceVariantGetPtrConstructor variant_get_ptr_constructor; - GDExtensionInterfaceVariantGetPtrDestructor variant_get_ptr_destructor; - GDExtensionInterfaceVariantConstruct variant_construct; - GDExtensionInterfaceVariantGetPtrSetter variant_get_ptr_setter; - GDExtensionInterfaceVariantGetPtrGetter variant_get_ptr_getter; - GDExtensionInterfaceVariantGetPtrIndexedSetter variant_get_ptr_indexed_setter; - GDExtensionInterfaceVariantGetPtrIndexedGetter variant_get_ptr_indexed_getter; - GDExtensionInterfaceVariantGetPtrKeyedSetter variant_get_ptr_keyed_setter; - GDExtensionInterfaceVariantGetPtrKeyedGetter variant_get_ptr_keyed_getter; - GDExtensionInterfaceVariantGetPtrKeyedChecker variant_get_ptr_keyed_checker; - GDExtensionInterfaceVariantGetConstantValue variant_get_constant_value; - GDExtensionInterfaceVariantGetPtrUtilityFunction variant_get_ptr_utility_function; - - GDExtensionInterfaceStringNewWithLatin1Chars string_new_with_latin1_chars; - GDExtensionInterfaceStringNewWithUtf8Chars string_new_with_utf8_chars; - GDExtensionInterfaceStringNewWithUtf16Chars string_new_with_utf16_chars; - GDExtensionInterfaceStringNewWithUtf32Chars string_new_with_utf32_chars; - GDExtensionInterfaceStringNewWithWideChars string_new_with_wide_chars; - GDExtensionInterfaceStringNewWithLatin1CharsAndLen string_new_with_latin1_chars_and_len; - GDExtensionInterfaceStringNewWithUtf8CharsAndLen string_new_with_utf8_chars_and_len; - GDExtensionInterfaceStringNewWithUtf16CharsAndLen string_new_with_utf16_chars_and_len; - GDExtensionInterfaceStringNewWithUtf32CharsAndLen string_new_with_utf32_chars_and_len; - GDExtensionInterfaceStringNewWithWideCharsAndLen string_new_with_wide_chars_and_len; - GDExtensionInterfaceStringToLatin1Chars string_to_latin1_chars; - GDExtensionInterfaceStringToUtf8Chars string_to_utf8_chars; - GDExtensionInterfaceStringToUtf16Chars string_to_utf16_chars; - GDExtensionInterfaceStringToUtf32Chars string_to_utf32_chars; - GDExtensionInterfaceStringToWideChars string_to_wide_chars; - GDExtensionInterfaceStringOperatorIndex string_operator_index; - GDExtensionInterfaceStringOperatorIndexConst string_operator_index_const; - - GDExtensionInterfaceStringOperatorPlusEqString string_operator_plus_eq_string; - GDExtensionInterfaceStringOperatorPlusEqChar string_operator_plus_eq_char; - GDExtensionInterfaceStringOperatorPlusEqCstr string_operator_plus_eq_cstr; - GDExtensionInterfaceStringOperatorPlusEqWcstr string_operator_plus_eq_wcstr; - GDExtensionInterfaceStringOperatorPlusEqC32str string_operator_plus_eq_c32str; - - GDExtensionInterfaceXmlParserOpenBuffer xml_parser_open_buffer; - - GDExtensionInterfaceFileAccessStoreBuffer file_access_store_buffer; - GDExtensionInterfaceFileAccessGetBuffer file_access_get_buffer; - - GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask worker_thread_pool_add_native_group_task; - GDExtensionInterfaceWorkerThreadPoolAddNativeTask worker_thread_pool_add_native_task; - - GDExtensionInterfacePackedByteArrayOperatorIndex packed_byte_array_operator_index; - GDExtensionInterfacePackedByteArrayOperatorIndexConst packed_byte_array_operator_index_const; - GDExtensionInterfacePackedColorArrayOperatorIndex packed_color_array_operator_index; - GDExtensionInterfacePackedColorArrayOperatorIndexConst packed_color_array_operator_index_const; - GDExtensionInterfacePackedFloat32ArrayOperatorIndex packed_float32_array_operator_index; - GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst packed_float32_array_operator_index_const; - GDExtensionInterfacePackedFloat64ArrayOperatorIndex packed_float64_array_operator_index; - GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst packed_float64_array_operator_index_const; - GDExtensionInterfacePackedInt32ArrayOperatorIndex packed_int32_array_operator_index; - GDExtensionInterfacePackedInt32ArrayOperatorIndexConst packed_int32_array_operator_index_const; - GDExtensionInterfacePackedInt64ArrayOperatorIndex packed_int64_array_operator_index; - GDExtensionInterfacePackedInt64ArrayOperatorIndexConst packed_int64_array_operator_index_const; - GDExtensionInterfacePackedStringArrayOperatorIndex packed_string_array_operator_index; - GDExtensionInterfacePackedStringArrayOperatorIndexConst packed_string_array_operator_index_const; - GDExtensionInterfacePackedVector2ArrayOperatorIndex packed_vector2_array_operator_index; - GDExtensionInterfacePackedVector2ArrayOperatorIndexConst packed_vector2_array_operator_index_const; - GDExtensionInterfacePackedVector3ArrayOperatorIndex packed_vector3_array_operator_index; - GDExtensionInterfacePackedVector3ArrayOperatorIndexConst packed_vector3_array_operator_index_const; - GDExtensionInterfaceArrayOperatorIndex array_operator_index; - GDExtensionInterfaceArrayOperatorIndexConst array_operator_index_const; - GDExtensionInterfaceArrayRef array_ref; - GDExtensionInterfaceArraySetTyped array_set_typed; - - GDExtensionInterfaceDictionaryOperatorIndex dictionary_operator_index; - GDExtensionInterfaceDictionaryOperatorIndexConst dictionary_operator_index_const; - - GDExtensionInterfaceObjectMethodBindCall object_method_bind_call; - GDExtensionInterfaceObjectMethodBindPtrcall object_method_bind_ptrcall; - GDExtensionInterfaceObjectDestroy object_destroy; - GDExtensionInterfaceGlobalGetSingleton global_get_singleton; - GDExtensionInterfaceObjectGetInstanceBinding object_get_instance_binding; - GDExtensionInterfaceObjectSetInstanceBinding object_set_instance_binding; - GDExtensionInterfaceObjectSetInstance object_set_instance; - GDExtensionInterfaceObjectCastTo object_cast_to; - GDExtensionInterfaceObjectGetInstanceFromId object_get_instance_from_id; - GDExtensionInterfaceObjectGetInstanceId object_get_instance_id; - - GDExtensionInterfaceRefGetObject ref_get_object; - GDExtensionInterfaceRefSetObject ref_set_object; - - GDExtensionInterfaceScriptInstanceCreate script_instance_create; - - GDExtensionInterfaceClassdbConstructObject classdb_construct_object; - GDExtensionInterfaceClassdbGetMethodBind classdb_get_method_bind; - GDExtensionInterfaceClassdbGetClassTag classdb_get_class_tag; - - GDExtensionInterfaceClassdbRegisterExtensionClass classdb_register_extension_class; - GDExtensionInterfaceClassdbRegisterExtensionClassMethod classdb_register_extension_class_method; - GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant classdb_register_extension_class_integer_constant; - GDExtensionInterfaceClassdbRegisterExtensionClassProperty classdb_register_extension_class_property; - GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup classdb_register_extension_class_property_group; - GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup classdb_register_extension_class_property_subgroup; - GDExtensionInterfaceClassdbRegisterExtensionClassSignal classdb_register_extension_class_signal; - GDExtensionInterfaceClassdbUnregisterExtensionClass classdb_unregister_extension_class; - - GDExtensionInterfaceGetLibraryPath get_library_path; - -} LegacyGDExtensionInterface; - -static LegacyGDExtensionInterface *legacy_gdextension_interface = nullptr; - -#define SETUP_LEGACY_FUNC(m_name, m_type) legacy_gdextension_interface->m_name = (m_type)GDExtension::get_interface_function(#m_name) - -void *gdextension_get_legacy_interface() { - if (legacy_gdextension_interface != nullptr) { - return legacy_gdextension_interface; - } - - legacy_gdextension_interface = memnew(LegacyGDExtensionInterface); - - // Force to 4.0.999 to make it easier to detect this structure. - legacy_gdextension_interface->version_major = 4; - legacy_gdextension_interface->version_minor = 0; - legacy_gdextension_interface->version_patch = 999; - legacy_gdextension_interface->version_string = "Godot Engine v4.0.999.stable.official [000000000]"; - - SETUP_LEGACY_FUNC(mem_alloc, GDExtensionInterfaceMemAlloc); - SETUP_LEGACY_FUNC(mem_realloc, GDExtensionInterfaceMemRealloc); - SETUP_LEGACY_FUNC(mem_free, GDExtensionInterfaceMemFree); - SETUP_LEGACY_FUNC(print_error, GDExtensionInterfacePrintError); - SETUP_LEGACY_FUNC(print_error_with_message, GDExtensionInterfacePrintErrorWithMessage); - SETUP_LEGACY_FUNC(print_warning, GDExtensionInterfacePrintWarning); - SETUP_LEGACY_FUNC(print_warning_with_message, GDExtensionInterfacePrintWarningWithMessage); - SETUP_LEGACY_FUNC(print_script_error, GDExtensionInterfacePrintScriptError); - SETUP_LEGACY_FUNC(print_script_error_with_message, GDExtensionInterfacePrintScriptErrorWithMessage); - SETUP_LEGACY_FUNC(get_native_struct_size, GDExtensionInterfaceGetNativeStructSize); - SETUP_LEGACY_FUNC(variant_new_copy, GDExtensionInterfaceVariantNewCopy); - SETUP_LEGACY_FUNC(variant_new_nil, GDExtensionInterfaceVariantNewNil); - SETUP_LEGACY_FUNC(variant_destroy, GDExtensionInterfaceVariantDestroy); - SETUP_LEGACY_FUNC(variant_call, GDExtensionInterfaceVariantCall); - SETUP_LEGACY_FUNC(variant_call_static, GDExtensionInterfaceVariantCallStatic); - SETUP_LEGACY_FUNC(variant_evaluate, GDExtensionInterfaceVariantEvaluate); - SETUP_LEGACY_FUNC(variant_set, GDExtensionInterfaceVariantSet); - SETUP_LEGACY_FUNC(variant_set_named, GDExtensionInterfaceVariantSetNamed); - SETUP_LEGACY_FUNC(variant_set_keyed, GDExtensionInterfaceVariantSetKeyed); - SETUP_LEGACY_FUNC(variant_set_indexed, GDExtensionInterfaceVariantSetIndexed); - SETUP_LEGACY_FUNC(variant_get, GDExtensionInterfaceVariantGet); - SETUP_LEGACY_FUNC(variant_get_named, GDExtensionInterfaceVariantGetNamed); - SETUP_LEGACY_FUNC(variant_get_keyed, GDExtensionInterfaceVariantGetKeyed); - SETUP_LEGACY_FUNC(variant_get_indexed, GDExtensionInterfaceVariantGetIndexed); - SETUP_LEGACY_FUNC(variant_iter_init, GDExtensionInterfaceVariantIterInit); - SETUP_LEGACY_FUNC(variant_iter_next, GDExtensionInterfaceVariantIterNext); - SETUP_LEGACY_FUNC(variant_iter_get, GDExtensionInterfaceVariantIterGet); - SETUP_LEGACY_FUNC(variant_hash, GDExtensionInterfaceVariantHash); - SETUP_LEGACY_FUNC(variant_recursive_hash, GDExtensionInterfaceVariantRecursiveHash); - SETUP_LEGACY_FUNC(variant_hash_compare, GDExtensionInterfaceVariantHashCompare); - SETUP_LEGACY_FUNC(variant_booleanize, GDExtensionInterfaceVariantBooleanize); - SETUP_LEGACY_FUNC(variant_duplicate, GDExtensionInterfaceVariantDuplicate); - SETUP_LEGACY_FUNC(variant_stringify, GDExtensionInterfaceVariantStringify); - SETUP_LEGACY_FUNC(variant_get_type, GDExtensionInterfaceVariantGetType); - SETUP_LEGACY_FUNC(variant_has_method, GDExtensionInterfaceVariantHasMethod); - SETUP_LEGACY_FUNC(variant_has_member, GDExtensionInterfaceVariantHasMember); - SETUP_LEGACY_FUNC(variant_has_key, GDExtensionInterfaceVariantHasKey); - SETUP_LEGACY_FUNC(variant_get_type_name, GDExtensionInterfaceVariantGetTypeName); - SETUP_LEGACY_FUNC(variant_can_convert, GDExtensionInterfaceVariantCanConvert); - SETUP_LEGACY_FUNC(variant_can_convert_strict, GDExtensionInterfaceVariantCanConvertStrict); - SETUP_LEGACY_FUNC(get_variant_from_type_constructor, GDExtensionInterfaceGetVariantFromTypeConstructor); - SETUP_LEGACY_FUNC(get_variant_to_type_constructor, GDExtensionInterfaceGetVariantToTypeConstructor); - SETUP_LEGACY_FUNC(variant_get_ptr_operator_evaluator, GDExtensionInterfaceVariantGetPtrOperatorEvaluator); - SETUP_LEGACY_FUNC(variant_get_ptr_builtin_method, GDExtensionInterfaceVariantGetPtrBuiltinMethod); - SETUP_LEGACY_FUNC(variant_get_ptr_constructor, GDExtensionInterfaceVariantGetPtrConstructor); - SETUP_LEGACY_FUNC(variant_get_ptr_destructor, GDExtensionInterfaceVariantGetPtrDestructor); - SETUP_LEGACY_FUNC(variant_construct, GDExtensionInterfaceVariantConstruct); - SETUP_LEGACY_FUNC(variant_get_ptr_setter, GDExtensionInterfaceVariantGetPtrSetter); - SETUP_LEGACY_FUNC(variant_get_ptr_getter, GDExtensionInterfaceVariantGetPtrGetter); - SETUP_LEGACY_FUNC(variant_get_ptr_indexed_setter, GDExtensionInterfaceVariantGetPtrIndexedSetter); - SETUP_LEGACY_FUNC(variant_get_ptr_indexed_getter, GDExtensionInterfaceVariantGetPtrIndexedGetter); - SETUP_LEGACY_FUNC(variant_get_ptr_keyed_setter, GDExtensionInterfaceVariantGetPtrKeyedSetter); - SETUP_LEGACY_FUNC(variant_get_ptr_keyed_getter, GDExtensionInterfaceVariantGetPtrKeyedGetter); - SETUP_LEGACY_FUNC(variant_get_ptr_keyed_checker, GDExtensionInterfaceVariantGetPtrKeyedChecker); - SETUP_LEGACY_FUNC(variant_get_constant_value, GDExtensionInterfaceVariantGetConstantValue); - SETUP_LEGACY_FUNC(variant_get_ptr_utility_function, GDExtensionInterfaceVariantGetPtrUtilityFunction); - SETUP_LEGACY_FUNC(string_new_with_latin1_chars, GDExtensionInterfaceStringNewWithLatin1Chars); - SETUP_LEGACY_FUNC(string_new_with_utf8_chars, GDExtensionInterfaceStringNewWithUtf8Chars); - SETUP_LEGACY_FUNC(string_new_with_utf16_chars, GDExtensionInterfaceStringNewWithUtf16Chars); - SETUP_LEGACY_FUNC(string_new_with_utf32_chars, GDExtensionInterfaceStringNewWithUtf32Chars); - SETUP_LEGACY_FUNC(string_new_with_wide_chars, GDExtensionInterfaceStringNewWithWideChars); - SETUP_LEGACY_FUNC(string_new_with_latin1_chars_and_len, GDExtensionInterfaceStringNewWithLatin1CharsAndLen); - SETUP_LEGACY_FUNC(string_new_with_utf8_chars_and_len, GDExtensionInterfaceStringNewWithUtf8CharsAndLen); - SETUP_LEGACY_FUNC(string_new_with_utf16_chars_and_len, GDExtensionInterfaceStringNewWithUtf16CharsAndLen); - SETUP_LEGACY_FUNC(string_new_with_utf32_chars_and_len, GDExtensionInterfaceStringNewWithUtf32CharsAndLen); - SETUP_LEGACY_FUNC(string_new_with_wide_chars_and_len, GDExtensionInterfaceStringNewWithWideCharsAndLen); - SETUP_LEGACY_FUNC(string_to_latin1_chars, GDExtensionInterfaceStringToLatin1Chars); - SETUP_LEGACY_FUNC(string_to_utf8_chars, GDExtensionInterfaceStringToUtf8Chars); - SETUP_LEGACY_FUNC(string_to_utf16_chars, GDExtensionInterfaceStringToUtf16Chars); - SETUP_LEGACY_FUNC(string_to_utf32_chars, GDExtensionInterfaceStringToUtf32Chars); - SETUP_LEGACY_FUNC(string_to_wide_chars, GDExtensionInterfaceStringToWideChars); - SETUP_LEGACY_FUNC(string_operator_index, GDExtensionInterfaceStringOperatorIndex); - SETUP_LEGACY_FUNC(string_operator_index_const, GDExtensionInterfaceStringOperatorIndexConst); - SETUP_LEGACY_FUNC(string_operator_plus_eq_string, GDExtensionInterfaceStringOperatorPlusEqString); - SETUP_LEGACY_FUNC(string_operator_plus_eq_char, GDExtensionInterfaceStringOperatorPlusEqChar); - SETUP_LEGACY_FUNC(string_operator_plus_eq_cstr, GDExtensionInterfaceStringOperatorPlusEqCstr); - SETUP_LEGACY_FUNC(string_operator_plus_eq_wcstr, GDExtensionInterfaceStringOperatorPlusEqWcstr); - SETUP_LEGACY_FUNC(string_operator_plus_eq_c32str, GDExtensionInterfaceStringOperatorPlusEqC32str); - SETUP_LEGACY_FUNC(xml_parser_open_buffer, GDExtensionInterfaceXmlParserOpenBuffer); - SETUP_LEGACY_FUNC(file_access_store_buffer, GDExtensionInterfaceFileAccessStoreBuffer); - SETUP_LEGACY_FUNC(file_access_get_buffer, GDExtensionInterfaceFileAccessGetBuffer); - SETUP_LEGACY_FUNC(worker_thread_pool_add_native_group_task, GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask); - SETUP_LEGACY_FUNC(worker_thread_pool_add_native_task, GDExtensionInterfaceWorkerThreadPoolAddNativeTask); - SETUP_LEGACY_FUNC(packed_byte_array_operator_index, GDExtensionInterfacePackedByteArrayOperatorIndex); - SETUP_LEGACY_FUNC(packed_byte_array_operator_index_const, GDExtensionInterfacePackedByteArrayOperatorIndexConst); - SETUP_LEGACY_FUNC(packed_color_array_operator_index, GDExtensionInterfacePackedColorArrayOperatorIndex); - SETUP_LEGACY_FUNC(packed_color_array_operator_index_const, GDExtensionInterfacePackedColorArrayOperatorIndexConst); - SETUP_LEGACY_FUNC(packed_float32_array_operator_index, GDExtensionInterfacePackedFloat32ArrayOperatorIndex); - SETUP_LEGACY_FUNC(packed_float32_array_operator_index_const, GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst); - SETUP_LEGACY_FUNC(packed_float64_array_operator_index, GDExtensionInterfacePackedFloat64ArrayOperatorIndex); - SETUP_LEGACY_FUNC(packed_float64_array_operator_index_const, GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst); - SETUP_LEGACY_FUNC(packed_int32_array_operator_index, GDExtensionInterfacePackedInt32ArrayOperatorIndex); - SETUP_LEGACY_FUNC(packed_int32_array_operator_index_const, GDExtensionInterfacePackedInt32ArrayOperatorIndexConst); - SETUP_LEGACY_FUNC(packed_int64_array_operator_index, GDExtensionInterfacePackedInt64ArrayOperatorIndex); - SETUP_LEGACY_FUNC(packed_int64_array_operator_index_const, GDExtensionInterfacePackedInt64ArrayOperatorIndexConst); - SETUP_LEGACY_FUNC(packed_string_array_operator_index, GDExtensionInterfacePackedStringArrayOperatorIndex); - SETUP_LEGACY_FUNC(packed_string_array_operator_index_const, GDExtensionInterfacePackedStringArrayOperatorIndexConst); - SETUP_LEGACY_FUNC(packed_vector2_array_operator_index, GDExtensionInterfacePackedVector2ArrayOperatorIndex); - SETUP_LEGACY_FUNC(packed_vector2_array_operator_index_const, GDExtensionInterfacePackedVector2ArrayOperatorIndexConst); - SETUP_LEGACY_FUNC(packed_vector3_array_operator_index, GDExtensionInterfacePackedVector3ArrayOperatorIndex); - SETUP_LEGACY_FUNC(packed_vector3_array_operator_index_const, GDExtensionInterfacePackedVector3ArrayOperatorIndexConst); - SETUP_LEGACY_FUNC(array_operator_index, GDExtensionInterfaceArrayOperatorIndex); - SETUP_LEGACY_FUNC(array_operator_index_const, GDExtensionInterfaceArrayOperatorIndexConst); - SETUP_LEGACY_FUNC(array_ref, GDExtensionInterfaceArrayRef); - SETUP_LEGACY_FUNC(array_set_typed, GDExtensionInterfaceArraySetTyped); - SETUP_LEGACY_FUNC(dictionary_operator_index, GDExtensionInterfaceDictionaryOperatorIndex); - SETUP_LEGACY_FUNC(dictionary_operator_index_const, GDExtensionInterfaceDictionaryOperatorIndexConst); - SETUP_LEGACY_FUNC(object_method_bind_call, GDExtensionInterfaceObjectMethodBindCall); - SETUP_LEGACY_FUNC(object_method_bind_ptrcall, GDExtensionInterfaceObjectMethodBindPtrcall); - SETUP_LEGACY_FUNC(object_destroy, GDExtensionInterfaceObjectDestroy); - SETUP_LEGACY_FUNC(global_get_singleton, GDExtensionInterfaceGlobalGetSingleton); - SETUP_LEGACY_FUNC(object_get_instance_binding, GDExtensionInterfaceObjectGetInstanceBinding); - SETUP_LEGACY_FUNC(object_set_instance_binding, GDExtensionInterfaceObjectSetInstanceBinding); - SETUP_LEGACY_FUNC(object_set_instance, GDExtensionInterfaceObjectSetInstance); - SETUP_LEGACY_FUNC(object_cast_to, GDExtensionInterfaceObjectCastTo); - SETUP_LEGACY_FUNC(object_get_instance_from_id, GDExtensionInterfaceObjectGetInstanceFromId); - SETUP_LEGACY_FUNC(object_get_instance_id, GDExtensionInterfaceObjectGetInstanceId); - SETUP_LEGACY_FUNC(ref_get_object, GDExtensionInterfaceRefGetObject); - SETUP_LEGACY_FUNC(ref_set_object, GDExtensionInterfaceRefSetObject); - SETUP_LEGACY_FUNC(script_instance_create, GDExtensionInterfaceScriptInstanceCreate); - SETUP_LEGACY_FUNC(classdb_construct_object, GDExtensionInterfaceClassdbConstructObject); - SETUP_LEGACY_FUNC(classdb_get_method_bind, GDExtensionInterfaceClassdbGetMethodBind); - SETUP_LEGACY_FUNC(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag); - SETUP_LEGACY_FUNC(classdb_register_extension_class, GDExtensionInterfaceClassdbRegisterExtensionClass); - SETUP_LEGACY_FUNC(classdb_register_extension_class_method, GDExtensionInterfaceClassdbRegisterExtensionClassMethod); - SETUP_LEGACY_FUNC(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant); - SETUP_LEGACY_FUNC(classdb_register_extension_class_property, GDExtensionInterfaceClassdbRegisterExtensionClassProperty); - SETUP_LEGACY_FUNC(classdb_register_extension_class_property_group, GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup); - SETUP_LEGACY_FUNC(classdb_register_extension_class_property_subgroup, GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup); - SETUP_LEGACY_FUNC(classdb_register_extension_class_signal, GDExtensionInterfaceClassdbRegisterExtensionClassSignal); - SETUP_LEGACY_FUNC(classdb_unregister_extension_class, GDExtensionInterfaceClassdbUnregisterExtensionClass); - SETUP_LEGACY_FUNC(get_library_path, GDExtensionInterfaceGetLibraryPath); - - return legacy_gdextension_interface; -} - -#undef SETUP_LEGACY_FUNC diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h index 3aa41f28da..4d7bdf9502 100644 --- a/core/extension/gdextension_interface.h +++ b/core/extension/gdextension_interface.h @@ -195,11 +195,11 @@ typedef struct { int32_t expected; } GDExtensionCallError; -typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionVariantPtr, GDExtensionTypePtr); -typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionTypePtr, GDExtensionVariantPtr); +typedef void (*GDExtensionVariantFromTypeConstructorFunc)(GDExtensionUninitializedVariantPtr, GDExtensionTypePtr); +typedef void (*GDExtensionTypeFromVariantConstructorFunc)(GDExtensionUninitializedTypePtr, GDExtensionVariantPtr); typedef void (*GDExtensionPtrOperatorEvaluator)(GDExtensionConstTypePtr p_left, GDExtensionConstTypePtr p_right, GDExtensionTypePtr r_result); typedef void (*GDExtensionPtrBuiltInMethod)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_return, int p_argument_count); -typedef void (*GDExtensionPtrConstructor)(GDExtensionTypePtr p_base, const GDExtensionConstTypePtr *p_args); +typedef void (*GDExtensionPtrConstructor)(GDExtensionUninitializedTypePtr p_base, const GDExtensionConstTypePtr *p_args); typedef void (*GDExtensionPtrDestructor)(GDExtensionTypePtr p_base); typedef void (*GDExtensionPtrSetter)(GDExtensionTypePtr p_base, GDExtensionConstTypePtr p_value); typedef void (*GDExtensionPtrGetter)(GDExtensionConstTypePtr p_base, GDExtensionTypePtr r_value); @@ -490,6 +490,7 @@ typedef struct { /** * @name get_godot_version + * @since 4.1 * * Gets the Godot version that the GDExtension was loaded into. * @@ -501,6 +502,7 @@ typedef void (*GDExtensionInterfaceGetGodotVersion)(GDExtensionGodotVersion *r_g /** * @name mem_alloc + * @since 4.1 * * Allocates memory. * @@ -512,6 +514,7 @@ typedef void *(*GDExtensionInterfaceMemAlloc)(size_t p_bytes); /** * @name mem_realloc + * @since 4.1 * * Reallocates memory. * @@ -524,6 +527,7 @@ typedef void *(*GDExtensionInterfaceMemRealloc)(void *p_ptr, size_t p_bytes); /** * @name mem_free + * @since 4.1 * * Frees memory. * @@ -535,6 +539,7 @@ typedef void (*GDExtensionInterfaceMemFree)(void *p_ptr); /** * @name print_error + * @since 4.1 * * Logs an error to Godot's built-in debugger and to the OS terminal. * @@ -548,6 +553,7 @@ typedef void (*GDExtensionInterfacePrintError)(const char *p_description, const /** * @name print_error_with_message + * @since 4.1 * * Logs an error with a message to Godot's built-in debugger and to the OS terminal. * @@ -562,6 +568,7 @@ typedef void (*GDExtensionInterfacePrintErrorWithMessage)(const char *p_descript /** * @name print_warning + * @since 4.1 * * Logs a warning to Godot's built-in debugger and to the OS terminal. * @@ -575,6 +582,7 @@ typedef void (*GDExtensionInterfacePrintWarning)(const char *p_description, cons /** * @name print_warning_with_message + * @since 4.1 * * Logs a warning with a message to Godot's built-in debugger and to the OS terminal. * @@ -589,6 +597,7 @@ typedef void (*GDExtensionInterfacePrintWarningWithMessage)(const char *p_descri /** * @name print_script_error + * @since 4.1 * * Logs a script error to Godot's built-in debugger and to the OS terminal. * @@ -602,6 +611,7 @@ typedef void (*GDExtensionInterfacePrintScriptError)(const char *p_description, /** * @name print_script_error_with_message + * @since 4.1 * * Logs a script error with a message to Godot's built-in debugger and to the OS terminal. * @@ -616,6 +626,7 @@ typedef void (*GDExtensionInterfacePrintScriptErrorWithMessage)(const char *p_de /** * @name get_native_struct_size + * @since 4.1 * * Gets the size of a native struct (ex. ObjectID) in bytes. * @@ -629,6 +640,7 @@ typedef uint64_t (*GDExtensionInterfaceGetNativeStructSize)(GDExtensionConstStri /** * @name variant_new_copy + * @since 4.1 * * Copies one Variant into a another. * @@ -639,6 +651,7 @@ typedef void (*GDExtensionInterfaceVariantNewCopy)(GDExtensionUninitializedVaria /** * @name variant_new_nil + * @since 4.1 * * Creates a new Variant containing nil. * @@ -648,6 +661,7 @@ typedef void (*GDExtensionInterfaceVariantNewNil)(GDExtensionUninitializedVarian /** * @name variant_destroy + * @since 4.1 * * Destroys a Variant. * @@ -657,6 +671,7 @@ typedef void (*GDExtensionInterfaceVariantDestroy)(GDExtensionVariantPtr p_self) /** * @name variant_call + * @since 4.1 * * Calls a method on a Variant. * @@ -673,6 +688,7 @@ typedef void (*GDExtensionInterfaceVariantCall)(GDExtensionVariantPtr p_self, GD /** * @name variant_call_static + * @since 4.1 * * Calls a static method on a Variant. * @@ -689,6 +705,7 @@ typedef void (*GDExtensionInterfaceVariantCallStatic)(GDExtensionVariantType p_t /** * @name variant_evaluate + * @since 4.1 * * Evaluate an operator on two Variants. * @@ -704,6 +721,7 @@ typedef void (*GDExtensionInterfaceVariantEvaluate)(GDExtensionVariantOperator p /** * @name variant_set + * @since 4.1 * * Sets a key on a Variant to a value. * @@ -718,6 +736,7 @@ typedef void (*GDExtensionInterfaceVariantSet)(GDExtensionVariantPtr p_self, GDE /** * @name variant_set_named + * @since 4.1 * * Sets a named key on a Variant to a value. * @@ -732,6 +751,7 @@ typedef void (*GDExtensionInterfaceVariantSetNamed)(GDExtensionVariantPtr p_self /** * @name variant_set_keyed + * @since 4.1 * * Sets a keyed property on a Variant to a value. * @@ -746,6 +766,7 @@ typedef void (*GDExtensionInterfaceVariantSetKeyed)(GDExtensionVariantPtr p_self /** * @name variant_set_indexed + * @since 4.1 * * Sets an index on a Variant to a value. * @@ -759,6 +780,7 @@ typedef void (*GDExtensionInterfaceVariantSetIndexed)(GDExtensionVariantPtr p_se /** * @name variant_get + * @since 4.1 * * Gets the value of a key from a Variant. * @@ -771,6 +793,7 @@ typedef void (*GDExtensionInterfaceVariantGet)(GDExtensionConstVariantPtr p_self /** * @name variant_get_named + * @since 4.1 * * Gets the value of a named key from a Variant. * @@ -783,6 +806,7 @@ typedef void (*GDExtensionInterfaceVariantGetNamed)(GDExtensionConstVariantPtr p /** * @name variant_get_keyed + * @since 4.1 * * Gets the value of a keyed property from a Variant. * @@ -795,6 +819,7 @@ typedef void (*GDExtensionInterfaceVariantGetKeyed)(GDExtensionConstVariantPtr p /** * @name variant_get_indexed + * @since 4.1 * * Gets the value of an index from a Variant. * @@ -808,6 +833,7 @@ typedef void (*GDExtensionInterfaceVariantGetIndexed)(GDExtensionConstVariantPtr /** * @name variant_iter_init + * @since 4.1 * * Initializes an iterator over a Variant. * @@ -823,6 +849,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantIterInit)(GDExtensionConstV /** * @name variant_iter_next + * @since 4.1 * * Gets the next value for an iterator over a Variant. * @@ -838,6 +865,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantIterNext)(GDExtensionConstV /** * @name variant_iter_get + * @since 4.1 * * Gets the next value for an iterator over a Variant. * @@ -852,6 +880,7 @@ typedef void (*GDExtensionInterfaceVariantIterGet)(GDExtensionConstVariantPtr p_ /** * @name variant_hash + * @since 4.1 * * Gets the hash of a Variant. * @@ -865,6 +894,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceVariantHash)(GDExtensionConstVarian /** * @name variant_recursive_hash + * @since 4.1 * * Gets the recursive hash of a Variant. * @@ -879,6 +909,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceVariantRecursiveHash)(GDExtensionCo /** * @name variant_hash_compare + * @since 4.1 * * Compares two Variants by their hash. * @@ -893,6 +924,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHashCompare)(GDExtensionCon /** * @name variant_booleanize + * @since 4.1 * * Converts a Variant to a boolean. * @@ -904,6 +936,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantBooleanize)(GDExtensionCons /** * @name variant_duplicate + * @since 4.1 * * Duplicates a Variant. * @@ -915,6 +948,7 @@ typedef void (*GDExtensionInterfaceVariantDuplicate)(GDExtensionConstVariantPtr /** * @name variant_stringify + * @since 4.1 * * Converts a Variant to a string. * @@ -925,6 +959,7 @@ typedef void (*GDExtensionInterfaceVariantStringify)(GDExtensionConstVariantPtr /** * @name variant_get_type + * @since 4.1 * * Gets the type of a Variant. * @@ -936,6 +971,7 @@ typedef GDExtensionVariantType (*GDExtensionInterfaceVariantGetType)(GDExtension /** * @name variant_has_method + * @since 4.1 * * Checks if a Variant has the given method. * @@ -948,6 +984,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMethod)(GDExtensionConst /** * @name variant_has_member + * @since 4.1 * * Checks if a type of Variant has the given member. * @@ -960,6 +997,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasMember)(GDExtensionVaria /** * @name variant_has_key + * @since 4.1 * * Checks if a Variant has a key. * @@ -973,6 +1011,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantHasKey)(GDExtensionConstVar /** * @name variant_get_type_name + * @since 4.1 * * Gets the name of a Variant type. * @@ -983,6 +1022,7 @@ typedef void (*GDExtensionInterfaceVariantGetTypeName)(GDExtensionVariantType p_ /** * @name variant_can_convert + * @since 4.1 * * Checks if Variants can be converted from one type to another. * @@ -995,6 +1035,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantCanConvert)(GDExtensionVari /** * @name variant_can_convert_strict + * @since 4.1 * * Checks if Variant can be converted from one type to another using stricter rules. * @@ -1007,6 +1048,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceVariantCanConvertStrict)(GDExtensi /** * @name get_variant_from_type_constructor + * @since 4.1 * * Gets a pointer to a function that can create a Variant of the given type from a raw value. * @@ -1018,6 +1060,7 @@ typedef GDExtensionVariantFromTypeConstructorFunc (*GDExtensionInterfaceGetVaria /** * @name get_variant_to_type_constructor + * @since 4.1 * * Gets a pointer to a function that can get the raw value from a Variant of the given type. * @@ -1029,6 +1072,7 @@ typedef GDExtensionTypeFromVariantConstructorFunc (*GDExtensionInterfaceGetVaria /** * @name variant_get_ptr_operator_evaluator + * @since 4.1 * * Gets a pointer to a function that can evaluate the given Variant operator on the given Variant types. * @@ -1042,6 +1086,7 @@ typedef GDExtensionPtrOperatorEvaluator (*GDExtensionInterfaceVariantGetPtrOpera /** * @name variant_get_ptr_builtin_method + * @since 4.1 * * Gets a pointer to a function that can call a builtin method on a type of Variant. * @@ -1055,6 +1100,7 @@ typedef GDExtensionPtrBuiltInMethod (*GDExtensionInterfaceVariantGetPtrBuiltinMe /** * @name variant_get_ptr_constructor + * @since 4.1 * * Gets a pointer to a function that can call one of the constructors for a type of Variant. * @@ -1067,6 +1113,7 @@ typedef GDExtensionPtrConstructor (*GDExtensionInterfaceVariantGetPtrConstructor /** * @name variant_get_ptr_destructor + * @since 4.1 * * Gets a pointer to a function than can call the destructor for a type of Variant. * @@ -1078,6 +1125,7 @@ typedef GDExtensionPtrDestructor (*GDExtensionInterfaceVariantGetPtrDestructor)( /** * @name variant_construct + * @since 4.1 * * Constructs a Variant of the given type, using the first constructor that matches the given arguments. * @@ -1091,6 +1139,7 @@ typedef void (*GDExtensionInterfaceVariantConstruct)(GDExtensionVariantType p_ty /** * @name variant_get_ptr_setter + * @since 4.1 * * Gets a pointer to a function that can call a member's setter on the given Variant type. * @@ -1103,6 +1152,7 @@ typedef GDExtensionPtrSetter (*GDExtensionInterfaceVariantGetPtrSetter)(GDExtens /** * @name variant_get_ptr_getter + * @since 4.1 * * Gets a pointer to a function that can call a member's getter on the given Variant type. * @@ -1115,6 +1165,7 @@ typedef GDExtensionPtrGetter (*GDExtensionInterfaceVariantGetPtrGetter)(GDExtens /** * @name variant_get_ptr_indexed_setter + * @since 4.1 * * Gets a pointer to a function that can set an index on the given Variant type. * @@ -1126,6 +1177,7 @@ typedef GDExtensionPtrIndexedSetter (*GDExtensionInterfaceVariantGetPtrIndexedSe /** * @name variant_get_ptr_indexed_getter + * @since 4.1 * * Gets a pointer to a function that can get an index on the given Variant type. * @@ -1137,6 +1189,7 @@ typedef GDExtensionPtrIndexedGetter (*GDExtensionInterfaceVariantGetPtrIndexedGe /** * @name variant_get_ptr_keyed_setter + * @since 4.1 * * Gets a pointer to a function that can set a key on the given Variant type. * @@ -1148,6 +1201,7 @@ typedef GDExtensionPtrKeyedSetter (*GDExtensionInterfaceVariantGetPtrKeyedSetter /** * @name variant_get_ptr_keyed_getter + * @since 4.1 * * Gets a pointer to a function that can get a key on the given Variant type. * @@ -1159,6 +1213,7 @@ typedef GDExtensionPtrKeyedGetter (*GDExtensionInterfaceVariantGetPtrKeyedGetter /** * @name variant_get_ptr_keyed_checker + * @since 4.1 * * Gets a pointer to a function that can check a key on the given Variant type. * @@ -1170,6 +1225,7 @@ typedef GDExtensionPtrKeyedChecker (*GDExtensionInterfaceVariantGetPtrKeyedCheck /** * @name variant_get_constant_value + * @since 4.1 * * Gets the value of a constant from the given Variant type. * @@ -1181,6 +1237,7 @@ typedef void (*GDExtensionInterfaceVariantGetConstantValue)(GDExtensionVariantTy /** * @name variant_get_ptr_utility_function + * @since 4.1 * * Gets a pointer to a function that can call a Variant utility function. * @@ -1195,6 +1252,7 @@ typedef GDExtensionPtrUtilityFunction (*GDExtensionInterfaceVariantGetPtrUtility /** * @name string_new_with_latin1_chars + * @since 4.1 * * Creates a String from a Latin-1 encoded C string. * @@ -1205,6 +1263,7 @@ typedef void (*GDExtensionInterfaceStringNewWithLatin1Chars)(GDExtensionUninitia /** * @name string_new_with_utf8_chars + * @since 4.1 * * Creates a String from a UTF-8 encoded C string. * @@ -1215,6 +1274,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf8Chars)(GDExtensionUninitiali /** * @name string_new_with_utf16_chars + * @since 4.1 * * Creates a String from a UTF-16 encoded C string. * @@ -1225,6 +1285,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf16Chars)(GDExtensionUninitial /** * @name string_new_with_utf32_chars + * @since 4.1 * * Creates a String from a UTF-32 encoded C string. * @@ -1235,6 +1296,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf32Chars)(GDExtensionUninitial /** * @name string_new_with_wide_chars + * @since 4.1 * * Creates a String from a wide C string. * @@ -1245,6 +1307,7 @@ typedef void (*GDExtensionInterfaceStringNewWithWideChars)(GDExtensionUninitiali /** * @name string_new_with_latin1_chars_and_len + * @since 4.1 * * Creates a String from a Latin-1 encoded C string with the given length. * @@ -1256,6 +1319,7 @@ typedef void (*GDExtensionInterfaceStringNewWithLatin1CharsAndLen)(GDExtensionUn /** * @name string_new_with_utf8_chars_and_len + * @since 4.1 * * Creates a String from a UTF-8 encoded C string with the given length. * @@ -1267,6 +1331,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf8CharsAndLen)(GDExtensionUnin /** * @name string_new_with_utf16_chars_and_len + * @since 4.1 * * Creates a String from a UTF-16 encoded C string with the given length. * @@ -1278,6 +1343,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf16CharsAndLen)(GDExtensionUni /** * @name string_new_with_utf32_chars_and_len + * @since 4.1 * * Creates a String from a UTF-32 encoded C string with the given length. * @@ -1289,6 +1355,7 @@ typedef void (*GDExtensionInterfaceStringNewWithUtf32CharsAndLen)(GDExtensionUni /** * @name string_new_with_wide_chars_and_len + * @since 4.1 * * Creates a String from a wide C string with the given length. * @@ -1300,6 +1367,7 @@ typedef void (*GDExtensionInterfaceStringNewWithWideCharsAndLen)(GDExtensionUnin /** * @name string_to_latin1_chars + * @since 4.1 * * Converts a String to a Latin-1 encoded C string. * @@ -1315,6 +1383,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringToLatin1Chars)(GDExtensionCon /** * @name string_to_utf8_chars + * @since 4.1 * * Converts a String to a UTF-8 encoded C string. * @@ -1330,6 +1399,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringToUtf8Chars)(GDExtensionConst /** * @name string_to_utf16_chars + * @since 4.1 * * Converts a String to a UTF-16 encoded C string. * @@ -1345,6 +1415,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringToUtf16Chars)(GDExtensionCons /** * @name string_to_utf32_chars + * @since 4.1 * * Converts a String to a UTF-32 encoded C string. * @@ -1360,6 +1431,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringToUtf32Chars)(GDExtensionCons /** * @name string_to_wide_chars + * @since 4.1 * * Converts a String to a wide C string. * @@ -1375,6 +1447,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceStringToWideChars)(GDExtensionConst /** * @name string_operator_index + * @since 4.1 * * Gets a pointer to the character at the given index from a String. * @@ -1387,6 +1460,7 @@ typedef char32_t *(*GDExtensionInterfaceStringOperatorIndex)(GDExtensionStringPt /** * @name string_operator_index_const + * @since 4.1 * * Gets a const pointer to the character at the given index from a String. * @@ -1399,6 +1473,7 @@ typedef const char32_t *(*GDExtensionInterfaceStringOperatorIndexConst)(GDExtens /** * @name string_operator_plus_eq_string + * @since 4.1 * * Appends another String to a String. * @@ -1409,6 +1484,7 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqString)(GDExtensionString /** * @name string_operator_plus_eq_char + * @since 4.1 * * Appends a character to a String. * @@ -1419,6 +1495,7 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqChar)(GDExtensionStringPt /** * @name string_operator_plus_eq_cstr + * @since 4.1 * * Appends a Latin-1 encoded C string to a String. * @@ -1429,6 +1506,7 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqCstr)(GDExtensionStringPt /** * @name string_operator_plus_eq_wcstr + * @since 4.1 * * Appends a wide C string to a String. * @@ -1439,6 +1517,7 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqWcstr)(GDExtensionStringP /** * @name string_operator_plus_eq_c32str + * @since 4.1 * * Appends a UTF-32 encoded C string to a String. * @@ -1451,6 +1530,7 @@ typedef void (*GDExtensionInterfaceStringOperatorPlusEqC32str)(GDExtensionString /** * @name xml_parser_open_buffer + * @since 4.1 * * Opens a raw XML buffer on an XMLParser instance. * @@ -1468,6 +1548,7 @@ typedef GDExtensionInt (*GDExtensionInterfaceXmlParserOpenBuffer)(GDExtensionObj /** * @name file_access_store_buffer + * @since 4.1 * * Stores the given buffer using an instance of FileAccess. * @@ -1481,6 +1562,7 @@ typedef void (*GDExtensionInterfaceFileAccessStoreBuffer)(GDExtensionObjectPtr p /** * @name file_access_get_buffer + * @since 4.1 * * Reads the next p_length bytes into the given buffer using an instance of FileAccess. * @@ -1496,6 +1578,7 @@ typedef uint64_t (*GDExtensionInterfaceFileAccessGetBuffer)(GDExtensionConstObje /** * @name worker_thread_pool_add_native_group_task + * @since 4.1 * * Adds a group task to an instance of WorkerThreadPool. * @@ -1514,6 +1597,7 @@ typedef int64_t (*GDExtensionInterfaceWorkerThreadPoolAddNativeGroupTask)(GDExte /** * @name worker_thread_pool_add_native_task + * @since 4.1 * * Adds a task to an instance of WorkerThreadPool. * @@ -1531,6 +1615,7 @@ typedef int64_t (*GDExtensionInterfaceWorkerThreadPoolAddNativeTask)(GDExtension /** * @name packed_byte_array_operator_index + * @since 4.1 * * Gets a pointer to a byte in a PackedByteArray. * @@ -1543,6 +1628,7 @@ typedef uint8_t *(*GDExtensionInterfacePackedByteArrayOperatorIndex)(GDExtension /** * @name packed_byte_array_operator_index_const + * @since 4.1 * * Gets a const pointer to a byte in a PackedByteArray. * @@ -1555,6 +1641,7 @@ typedef const uint8_t *(*GDExtensionInterfacePackedByteArrayOperatorIndexConst)( /** * @name packed_color_array_operator_index + * @since 4.1 * * Gets a pointer to a color in a PackedColorArray. * @@ -1567,6 +1654,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedColorArrayOperatorIndex)( /** * @name packed_color_array_operator_index_const + * @since 4.1 * * Gets a const pointer to a color in a PackedColorArray. * @@ -1579,6 +1667,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedColorArrayOperatorIndexCo /** * @name packed_float32_array_operator_index + * @since 4.1 * * Gets a pointer to a 32-bit float in a PackedFloat32Array. * @@ -1591,6 +1680,7 @@ typedef float *(*GDExtensionInterfacePackedFloat32ArrayOperatorIndex)(GDExtensio /** * @name packed_float32_array_operator_index_const + * @since 4.1 * * Gets a const pointer to a 32-bit float in a PackedFloat32Array. * @@ -1603,6 +1693,7 @@ typedef const float *(*GDExtensionInterfacePackedFloat32ArrayOperatorIndexConst) /** * @name packed_float64_array_operator_index + * @since 4.1 * * Gets a pointer to a 64-bit float in a PackedFloat64Array. * @@ -1615,6 +1706,7 @@ typedef double *(*GDExtensionInterfacePackedFloat64ArrayOperatorIndex)(GDExtensi /** * @name packed_float64_array_operator_index_const + * @since 4.1 * * Gets a const pointer to a 64-bit float in a PackedFloat64Array. * @@ -1627,6 +1719,7 @@ typedef const double *(*GDExtensionInterfacePackedFloat64ArrayOperatorIndexConst /** * @name packed_int32_array_operator_index + * @since 4.1 * * Gets a pointer to a 32-bit integer in a PackedInt32Array. * @@ -1639,6 +1732,7 @@ typedef int32_t *(*GDExtensionInterfacePackedInt32ArrayOperatorIndex)(GDExtensio /** * @name packed_int32_array_operator_index_const + * @since 4.1 * * Gets a const pointer to a 32-bit integer in a PackedInt32Array. * @@ -1651,6 +1745,7 @@ typedef const int32_t *(*GDExtensionInterfacePackedInt32ArrayOperatorIndexConst) /** * @name packed_int64_array_operator_index + * @since 4.1 * * Gets a pointer to a 64-bit integer in a PackedInt64Array. * @@ -1663,6 +1758,7 @@ typedef int64_t *(*GDExtensionInterfacePackedInt64ArrayOperatorIndex)(GDExtensio /** * @name packed_int64_array_operator_index_const + * @since 4.1 * * Gets a const pointer to a 64-bit integer in a PackedInt64Array. * @@ -1675,6 +1771,7 @@ typedef const int64_t *(*GDExtensionInterfacePackedInt64ArrayOperatorIndexConst) /** * @name packed_string_array_operator_index + * @since 4.1 * * Gets a pointer to a string in a PackedStringArray. * @@ -1687,6 +1784,7 @@ typedef GDExtensionStringPtr (*GDExtensionInterfacePackedStringArrayOperatorInde /** * @name packed_string_array_operator_index_const + * @since 4.1 * * Gets a const pointer to a string in a PackedStringArray. * @@ -1699,6 +1797,7 @@ typedef GDExtensionStringPtr (*GDExtensionInterfacePackedStringArrayOperatorInde /** * @name packed_vector2_array_operator_index + * @since 4.1 * * Gets a pointer to a Vector2 in a PackedVector2Array. * @@ -1711,6 +1810,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector2ArrayOperatorIndex /** * @name packed_vector2_array_operator_index_const + * @since 4.1 * * Gets a const pointer to a Vector2 in a PackedVector2Array. * @@ -1723,6 +1823,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector2ArrayOperatorIndex /** * @name packed_vector3_array_operator_index + * @since 4.1 * * Gets a pointer to a Vector3 in a PackedVector3Array. * @@ -1735,6 +1836,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector3ArrayOperatorIndex /** * @name packed_vector3_array_operator_index_const + * @since 4.1 * * Gets a const pointer to a Vector3 in a PackedVector3Array. * @@ -1747,6 +1849,7 @@ typedef GDExtensionTypePtr (*GDExtensionInterfacePackedVector3ArrayOperatorIndex /** * @name array_operator_index + * @since 4.1 * * Gets a pointer to a Variant in an Array. * @@ -1759,6 +1862,7 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceArrayOperatorIndex)(GDExtens /** * @name array_operator_index_const + * @since 4.1 * * Gets a const pointer to a Variant in an Array. * @@ -1771,6 +1875,7 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceArrayOperatorIndexConst)(GDE /** * @name array_ref + * @since 4.1 * * Sets an Array to be a reference to another Array object. * @@ -1781,6 +1886,7 @@ typedef void (*GDExtensionInterfaceArrayRef)(GDExtensionTypePtr p_self, GDExtens /** * @name array_set_typed + * @since 4.1 * * Makes an Array into a typed Array. * @@ -1795,6 +1901,7 @@ typedef void (*GDExtensionInterfaceArraySetTyped)(GDExtensionTypePtr p_self, GDE /** * @name dictionary_operator_index + * @since 4.1 * * Gets a pointer to a Variant in a Dictionary with the given key. * @@ -1807,6 +1914,7 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceDictionaryOperatorIndex)(GDE /** * @name dictionary_operator_index_const + * @since 4.1 * * Gets a const pointer to a Variant in a Dictionary with the given key. * @@ -1821,6 +1929,7 @@ typedef GDExtensionVariantPtr (*GDExtensionInterfaceDictionaryOperatorIndexConst /** * @name object_method_bind_call + * @since 4.1 * * Calls a method on an Object. * @@ -1835,6 +1944,7 @@ typedef void (*GDExtensionInterfaceObjectMethodBindCall)(GDExtensionMethodBindPt /** * @name object_method_bind_ptrcall + * @since 4.1 * * Calls a method on an Object (using a "ptrcall"). * @@ -1847,6 +1957,7 @@ typedef void (*GDExtensionInterfaceObjectMethodBindPtrcall)(GDExtensionMethodBin /** * @name object_destroy + * @since 4.1 * * Destroys an Object. * @@ -1856,6 +1967,7 @@ typedef void (*GDExtensionInterfaceObjectDestroy)(GDExtensionObjectPtr p_o); /** * @name global_get_singleton + * @since 4.1 * * Gets a global singleton by name. * @@ -1867,6 +1979,7 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceGlobalGetSingleton)(GDExtensi /** * @name object_get_instance_binding + * @since 4.1 * * Gets a pointer representing an Object's instance binding. * @@ -1880,6 +1993,7 @@ typedef void *(*GDExtensionInterfaceObjectGetInstanceBinding)(GDExtensionObjectP /** * @name object_set_instance_binding + * @since 4.1 * * Sets an Object's instance binding. * @@ -1892,6 +2006,7 @@ typedef void (*GDExtensionInterfaceObjectSetInstanceBinding)(GDExtensionObjectPt /** * @name object_set_instance + * @since 4.1 * * Sets an extension class instance on a Object. * @@ -1903,6 +2018,7 @@ typedef void (*GDExtensionInterfaceObjectSetInstance)(GDExtensionObjectPtr p_o, /** * @name object_get_class_name + * @since 4.1 * * Gets the class name of an Object. * @@ -1916,6 +2032,7 @@ typedef GDExtensionBool (*GDExtensionInterfaceObjectGetClassName)(GDExtensionCon /** * @name object_cast_to + * @since 4.1 * * Casts an Object to a different type. * @@ -1928,6 +2045,7 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceObjectCastTo)(GDExtensionCons /** * @name object_get_instance_from_id + * @since 4.1 * * Gets an Object by its instance ID. * @@ -1939,6 +2057,7 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceObjectGetInstanceFromId)(GDOb /** * @name object_get_instance_id + * @since 4.1 * * Gets the instance ID from an Object. * @@ -1952,6 +2071,7 @@ typedef GDObjectInstanceID (*GDExtensionInterfaceObjectGetInstanceId)(GDExtensio /** * @name ref_get_object + * @since 4.1 * * Gets the Object from a reference. * @@ -1963,6 +2083,7 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceRefGetObject)(GDExtensionCons /** * @name ref_set_object + * @since 4.1 * * Sets the Object referred to by a reference. * @@ -1975,6 +2096,7 @@ typedef void (*GDExtensionInterfaceRefSetObject)(GDExtensionRefPtr p_ref, GDExte /** * @name script_instance_create + * @since 4.1 * * Creates a script instance that contains the given info and instance data. * @@ -1989,6 +2111,7 @@ typedef GDExtensionScriptInstancePtr (*GDExtensionInterfaceScriptInstanceCreate) /** * @name classdb_construct_object + * @since 4.1 * * Constructs an Object of the requested class. * @@ -2002,6 +2125,7 @@ typedef GDExtensionObjectPtr (*GDExtensionInterfaceClassdbConstructObject)(GDExt /** * @name classdb_get_method_bind + * @since 4.1 * * Gets a pointer to the MethodBind in ClassDB for the given class, method and hash. * @@ -2015,6 +2139,7 @@ typedef GDExtensionMethodBindPtr (*GDExtensionInterfaceClassdbGetMethodBind)(GDE /** * @name classdb_get_class_tag + * @since 4.1 * * Gets a pointer uniquely identifying the given built-in class in the ClassDB. * @@ -2028,6 +2153,7 @@ typedef void *(*GDExtensionInterfaceClassdbGetClassTag)(GDExtensionConstStringNa /** * @name classdb_register_extension_class + * @since 4.1 * * Registers an extension class in the ClassDB. * @@ -2042,6 +2168,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass)(GDExtensionCla /** * @name classdb_register_extension_class_method + * @since 4.1 * * Registers a method on an extension class in the ClassDB. * @@ -2055,6 +2182,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassMethod)(GDExtens /** * @name classdb_register_extension_class_integer_constant + * @since 4.1 * * Registers an integer constant on an extension class in the ClassDB. * @@ -2069,6 +2197,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant) /** * @name classdb_register_extension_class_property + * @since 4.1 * * Registers a property on an extension class in the ClassDB. * @@ -2084,6 +2213,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassProperty)(GDExte /** * @name classdb_register_extension_class_property_group + * @since 4.1 * * Registers a property group on an extension class in the ClassDB. * @@ -2096,6 +2226,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassPropertyGroup)(G /** * @name classdb_register_extension_class_property_subgroup + * @since 4.1 * * Registers a property subgroup on an extension class in the ClassDB. * @@ -2108,6 +2239,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassPropertySubgroup /** * @name classdb_register_extension_class_signal + * @since 4.1 * * Registers a signal on an extension class in the ClassDB. * @@ -2123,6 +2255,7 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClassSignal)(GDExtens /** * @name classdb_unregister_extension_class + * @since 4.1 * * Unregisters an extension class in the ClassDB. * @@ -2133,6 +2266,7 @@ typedef void (*GDExtensionInterfaceClassdbUnregisterExtensionClass)(GDExtensionC /** * @name get_library_path + * @since 4.1 * * Gets the path to the current GDExtension library. * @@ -2143,6 +2277,7 @@ typedef void (*GDExtensionInterfaceGetLibraryPath)(GDExtensionClassLibraryPtr p_ /** * @name editor_add_plugin + * @since 4.1 * * Adds an editor plugin. * @@ -2154,6 +2289,7 @@ typedef void (*GDExtensionInterfaceEditorAddPlugin)(GDExtensionConstStringNamePt /** * @name editor_remove_plugin + * @since 4.1 * * Removes an editor plugin. * diff --git a/core/input/input.cpp b/core/input/input.cpp index 1348389481..d481acf005 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -113,6 +113,7 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("get_joy_axis", "device", "axis"), &Input::get_joy_axis); ClassDB::bind_method(D_METHOD("get_joy_name", "device"), &Input::get_joy_name); ClassDB::bind_method(D_METHOD("get_joy_guid", "device"), &Input::get_joy_guid); + ClassDB::bind_method(D_METHOD("should_ignore_device", "vendor_id", "product_id"), &Input::should_ignore_device); ClassDB::bind_method(D_METHOD("get_connected_joypads"), &Input::get_connected_joypads); ClassDB::bind_method(D_METHOD("get_joy_vibration_strength", "device"), &Input::get_joy_vibration_strength); ClassDB::bind_method(D_METHOD("get_joy_vibration_duration", "device"), &Input::get_joy_vibration_duration); @@ -297,10 +298,13 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con return false; } + // Backward compatibility for legacy behavior, only return true if currently pressed. + bool pressed_requirement = legacy_just_pressed_behavior ? E->value.pressed : true; + if (Engine::get_singleton()->is_in_physics_frame()) { - return E->value.pressed && E->value.physics_frame == Engine::get_singleton()->get_physics_frames(); + return pressed_requirement && E->value.pressed_physics_frame == Engine::get_singleton()->get_physics_frames(); } else { - return E->value.pressed && E->value.process_frame == Engine::get_singleton()->get_process_frames(); + return pressed_requirement && E->value.pressed_process_frame == Engine::get_singleton()->get_process_frames(); } } @@ -315,10 +319,13 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co return false; } + // Backward compatibility for legacy behavior, only return true if currently released. + bool released_requirement = legacy_just_pressed_behavior ? !E->value.pressed : true; + if (Engine::get_singleton()->is_in_physics_frame()) { - return !E->value.pressed && E->value.physics_frame == Engine::get_singleton()->get_physics_frames(); + return released_requirement && E->value.released_physics_frame == Engine::get_singleton()->get_physics_frames(); } else { - return !E->value.pressed && E->value.process_frame == Engine::get_singleton()->get_process_frames(); + return released_requirement && E->value.released_process_frame == Engine::get_singleton()->get_process_frames(); } } @@ -686,19 +693,24 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em for (const KeyValue<StringName, InputMap::Action> &E : InputMap::get_singleton()->get_action_map()) { if (InputMap::get_singleton()->event_is_action(p_event, E.key)) { + Action &action = action_state[E.key]; // If not echo and action pressed state has changed if (!p_event->is_echo() && is_action_pressed(E.key, false) != p_event->is_action_pressed(E.key)) { - Action action; - action.physics_frame = Engine::get_singleton()->get_physics_frames(); - action.process_frame = Engine::get_singleton()->get_process_frames(); - action.pressed = p_event->is_action_pressed(E.key); + if (p_event->is_action_pressed(E.key)) { + action.pressed = true; + action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames(); + action.pressed_process_frame = Engine::get_singleton()->get_process_frames(); + } else { + action.pressed = false; + action.released_physics_frame = Engine::get_singleton()->get_physics_frames(); + action.released_process_frame = Engine::get_singleton()->get_process_frames(); + } action.strength = 0.0f; action.raw_strength = 0.0f; action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true); - action_state[E.key] = action; } - action_state[E.key].strength = p_event->get_action_strength(E.key); - action_state[E.key].raw_strength = p_event->get_action_raw_strength(E.key); + action.strength = p_event->get_action_strength(E.key); + action.raw_strength = p_event->get_action_raw_strength(E.key); } } @@ -813,29 +825,27 @@ Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, con } void Input::action_press(const StringName &p_action, float p_strength) { - Action action; + // Create or retrieve existing action. + Action &action = action_state[p_action]; - action.physics_frame = Engine::get_singleton()->get_physics_frames(); - action.process_frame = Engine::get_singleton()->get_process_frames(); + action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames(); + action.pressed_process_frame = Engine::get_singleton()->get_process_frames(); action.pressed = true; action.strength = p_strength; action.raw_strength = p_strength; action.exact = true; - - action_state[p_action] = action; } void Input::action_release(const StringName &p_action) { - Action action; + // Create or retrieve existing action. + Action &action = action_state[p_action]; - action.physics_frame = Engine::get_singleton()->get_physics_frames(); - action.process_frame = Engine::get_singleton()->get_process_frames(); + action.released_physics_frame = Engine::get_singleton()->get_physics_frames(); + action.released_process_frame = Engine::get_singleton()->get_process_frames(); action.pressed = false; - action.strength = 0.f; - action.raw_strength = 0.f; + action.strength = 0.0f; + action.raw_strength = 0.0f; action.exact = true; - - action_state[p_action] = action; } void Input::set_emulate_touch_from_mouse(bool p_emulate) { @@ -1356,8 +1366,9 @@ void Input::parse_mapping(String p_mapping) { String output = entry[idx].get_slice(":", 0).replace(" ", ""); String input = entry[idx].get_slice(":", 1).replace(" ", ""); - ERR_CONTINUE_MSG(output.length() < 1 || input.length() < 2, - vformat("Invalid device mapping entry \"%s\" in mapping:\n%s", entry[idx], p_mapping)); + if (output.length() < 1 || input.length() < 2) { + continue; + } if (output == "platform" || output == "hint") { continue; @@ -1488,6 +1499,11 @@ String Input::get_joy_guid(int p_device) const { return joy_names[p_device].uid; } +bool Input::should_ignore_device(int p_vendor_id, int p_product_id) const { + uint32_t full_id = (((uint32_t)p_vendor_id) << 16) | ((uint16_t)p_product_id); + return ignored_device_ids.has(full_id); +} + TypedArray<int> Input::get_connected_joypads() { TypedArray<int> ret; HashMap<int, Joypad>::Iterator elem = joy_names.begin(); @@ -1531,6 +1547,33 @@ Input::Input() { parse_mapping(entries[i]); } } + + String env_ignore_devices = OS::get_singleton()->get_environment("SDL_GAMECONTROLLER_IGNORE_DEVICES"); + if (!env_ignore_devices.is_empty()) { + Vector<String> entries = env_ignore_devices.split(","); + for (int i = 0; i < entries.size(); i++) { + Vector<String> vid_pid = entries[i].split("/"); + + if (vid_pid.size() < 2) { + continue; + } + + print_verbose(vformat("Device Ignored -- Vendor: %s Product: %s", vid_pid[0], vid_pid[1])); + const uint16_t vid_unswapped = vid_pid[0].hex_to_int(); + const uint16_t pid_unswapped = vid_pid[1].hex_to_int(); + const uint16_t vid = BSWAP16(vid_unswapped); + const uint16_t pid = BSWAP16(pid_unswapped); + + uint32_t full_id = (((uint32_t)vid) << 16) | ((uint16_t)pid); + ignored_device_ids.insert(full_id); + } + } + + legacy_just_pressed_behavior = GLOBAL_DEF("input_devices/compatibility/legacy_just_pressed_behavior", false); + if (Engine::get_singleton()->is_editor_hint()) { + // Always use standard behavior in the editor. + legacy_just_pressed_behavior = false; + } } Input::~Input() { diff --git a/core/input/input.h b/core/input/input.h index c254650ef8..ec16871b72 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -96,14 +96,17 @@ private: Vector3 gyroscope; Vector2 mouse_pos; int64_t mouse_window = 0; + bool legacy_just_pressed_behavior = false; struct Action { - uint64_t physics_frame; - uint64_t process_frame; - bool pressed; - bool exact; - float strength; - float raw_strength; + uint64_t pressed_physics_frame = UINT64_MAX; + uint64_t pressed_process_frame = UINT64_MAX; + uint64_t released_physics_frame = UINT64_MAX; + uint64_t released_process_frame = UINT64_MAX; + bool pressed = false; + bool exact = true; + float strength = 0.0f; + float raw_strength = 0.0f; }; HashMap<StringName, Action> action_state; @@ -151,6 +154,9 @@ private: VelocityTrack mouse_velocity_track; HashMap<int, VelocityTrack> touch_velocity_track; HashMap<int, Joypad> joy_names; + + HashSet<uint32_t> ignored_device_ids; + int fallback_mapping = -1; CursorShape default_shape = CURSOR_ARROW; @@ -325,6 +331,7 @@ public: bool is_joy_known(int p_device); String get_joy_guid(int p_device) const; + bool should_ignore_device(int p_vendor_id, int p_product_id) const; void set_fallback_mapping(String p_guid); void flush_buffered_events(); diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 95be01bc65..e37886cbe9 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -201,7 +201,7 @@ bool InputEventWithModifiers::is_alt_pressed() const { } void InputEventWithModifiers::set_ctrl_pressed(bool p_enabled) { - ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command/Control autoremaping is enabled, cannot set Control directly!"); + ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command or Control autoremapping is enabled, cannot set Control directly!"); ctrl_pressed = p_enabled; emit_changed(); } @@ -211,7 +211,7 @@ bool InputEventWithModifiers::is_ctrl_pressed() const { } void InputEventWithModifiers::set_meta_pressed(bool p_enabled) { - ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command/Control autoremaping is enabled, cannot set Meta directly!"); + ERR_FAIL_COND_MSG(command_or_control_autoremap, "Command or Control autoremapping is enabled, cannot set Meta directly!"); meta_pressed = p_enabled; emit_changed(); } @@ -1109,6 +1109,15 @@ String InputEventJoypadMotion::to_string() { return vformat("InputEventJoypadMotion: axis=%d, axis_value=%.2f", axis, axis_value); } +Ref<InputEventJoypadMotion> InputEventJoypadMotion::create_reference(JoyAxis p_axis, float p_value) { + Ref<InputEventJoypadMotion> ie; + ie.instantiate(); + ie->set_axis(p_axis); + ie->set_axis_value(p_value); + + return ie; +} + void InputEventJoypadMotion::_bind_methods() { ClassDB::bind_method(D_METHOD("set_axis", "axis"), &InputEventJoypadMotion::set_axis); ClassDB::bind_method(D_METHOD("get_axis"), &InputEventJoypadMotion::get_axis); @@ -1183,7 +1192,7 @@ static const char *_joy_button_descriptions[(size_t)JoyButton::SDL_MAX] = { TTRC("Top Action, Sony Triangle, Xbox Y, Nintendo X"), TTRC("Back, Sony Select, Xbox Back, Nintendo -"), TTRC("Guide, Sony PS, Xbox Home"), - TTRC("Start, Nintendo +"), + TTRC("Start, Xbox Menu, Nintendo +"), TTRC("Left Stick, Sony L3, Xbox L/LS"), TTRC("Right Stick, Sony R3, Xbox R/RS"), TTRC("Left Shoulder, Sony L1, Xbox LB"), diff --git a/core/input/input_event.h b/core/input/input_event.h index 59a87239bd..e9d4fb8325 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -319,6 +319,8 @@ public: virtual String as_text() const override; virtual String to_string() override; + static Ref<InputEventJoypadMotion> create_reference(JoyAxis p_axis, float p_value); + InputEventJoypadMotion() {} }; diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 910778324c..ddfde0e7cd 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -399,21 +399,25 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() { inputs = List<Ref<InputEvent>>(); inputs.push_back(InputEventKey::create_reference(Key::LEFT)); inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_LEFT)); + inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_X, -1.0)); default_builtin_cache.insert("ui_left", inputs); inputs = List<Ref<InputEvent>>(); inputs.push_back(InputEventKey::create_reference(Key::RIGHT)); inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_RIGHT)); + inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_X, 1.0)); default_builtin_cache.insert("ui_right", inputs); inputs = List<Ref<InputEvent>>(); inputs.push_back(InputEventKey::create_reference(Key::UP)); inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_UP)); + inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_Y, -1.0)); default_builtin_cache.insert("ui_up", inputs); inputs = List<Ref<InputEvent>>(); inputs.push_back(InputEventKey::create_reference(Key::DOWN)); inputs.push_back(InputEventJoypadButton::create_reference(JoyButton::DPAD_DOWN)); + inputs.push_back(InputEventJoypadMotion::create_reference(JoyAxis::LEFT_Y, 1.0)); default_builtin_cache.insert("ui_down", inputs); inputs = List<Ref<InputEvent>>(); diff --git a/core/io/compression.cpp b/core/io/compression.cpp index ac4a637597..e36fb0afa4 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -35,13 +35,13 @@ #include "thirdparty/misc/fastlz.h" -#ifdef BROTLI_ENABLED -#include "thirdparty/brotli/include/brotli/decode.h" -#endif - #include <zlib.h> #include <zstd.h> +#ifdef BROTLI_ENABLED +#include <brotli/decode.h> +#endif + int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size, Mode p_mode) { switch (p_mode) { case MODE_BROTLI: { diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index a6a1a224b3..b669afdc99 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -441,6 +441,11 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const { current += c; } } + + if (in_quote) { + WARN_PRINT(vformat("Reached end of file before closing '\"' in CSV file '%s'.", get_path())); + } + strings.push_back(current); return strings; diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 88a906a38e..74c5c1c191 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -48,7 +48,8 @@ Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t } void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted) { - PathMD5 pmd5(p_path.md5_buffer()); + String simplified_path = p_path.simplify_path(); + PathMD5 pmd5(simplified_path.md5_buffer()); bool exists = files.has(pmd5); @@ -68,7 +69,7 @@ void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64 if (!exists) { //search for dir - String p = p_path.replace_first("res://", ""); + String p = simplified_path.replace_first("res://", ""); PackedDir *cd = root; if (p.contains("/")) { //in a subdir @@ -87,7 +88,7 @@ void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64 } } } - String filename = p_path.get_file(); + String filename = simplified_path.get_file(); // Don't add as a file if the path points to a directory if (!filename.is_empty()) { cd->files.insert(filename); diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 8bfabc9529..1538b302c2 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -184,7 +184,8 @@ public: }; Ref<FileAccess> PackedData::try_open_path(const String &p_path) { - PathMD5 pmd5(p_path.md5_buffer()); + String simplified_path = p_path.simplify_path(); + PathMD5 pmd5(simplified_path.md5_buffer()); HashMap<PathMD5, PackedFile, PathMD5>::Iterator E = files.find(pmd5); if (!E) { return nullptr; //not found @@ -197,7 +198,7 @@ Ref<FileAccess> PackedData::try_open_path(const String &p_path) { } bool PackedData::has_path(const String &p_path) { - return files.has(PathMD5(p_path.md5_buffer())); + return files.has(PathMD5(p_path.simplify_path().md5_buffer())); } bool PackedData::has_directory(const String &p_path) { diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index 064353476f..c7f1a73f97 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -47,7 +47,7 @@ static void *godot_open(voidpf opaque, const char *p_fname, int mode) { return nullptr; } - Ref<FileAccess> f = FileAccess::open(p_fname, FileAccess::READ); + Ref<FileAccess> f = FileAccess::open(String::utf8(p_fname), FileAccess::READ); ERR_FAIL_COND_V(f.is_null(), nullptr); ZipData *zd = memnew(ZipData); diff --git a/core/io/image.cpp b/core/io/image.cpp index 9bb987b670..7326563f18 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -517,21 +517,31 @@ void Image::convert(Format p_new_format) { return; } + // Includes the main image. + const int mipmap_count = get_mipmap_count() + 1; + if (format > FORMAT_RGBE9995 || p_new_format > FORMAT_RGBE9995) { ERR_FAIL_MSG("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead."); } else if (format > FORMAT_RGBA8 || p_new_format > FORMAT_RGBA8) { //use put/set pixel which is slower but works with non byte formats - Image new_img(width, height, false, p_new_format); + Image new_img(width, height, mipmaps, p_new_format); - for (int i = 0; i < width; i++) { - for (int j = 0; j < height; j++) { - new_img.set_pixel(i, j, get_pixel(i, j)); + for (int mip = 0; mip < mipmap_count; mip++) { + Ref<Image> src_mip = get_image_from_mipmap(mip); + Ref<Image> new_mip = new_img.get_image_from_mipmap(mip); + + for (int y = 0; y < src_mip->height; y++) { + for (int x = 0; x < src_mip->width; x++) { + new_mip->set_pixel(x, y, src_mip->get_pixel(x, y)); + } } - } - if (has_mipmaps()) { - new_img.generate_mipmaps(); + int mip_offset = 0; + int mip_size = 0; + new_img.get_mipmap_offset_and_size(mip, mip_offset, mip_size); + + memcpy(new_img.data.ptrw() + mip_offset, new_mip->data.ptr(), mip_size); } _copy_internals_from(new_img); @@ -539,113 +549,115 @@ void Image::convert(Format p_new_format) { return; } - Image new_img(width, height, false, p_new_format); - - const uint8_t *rptr = data.ptr(); - uint8_t *wptr = new_img.data.ptrw(); + Image new_img(width, height, mipmaps, p_new_format); int conversion_type = format | p_new_format << 8; - switch (conversion_type) { - case FORMAT_L8 | (FORMAT_LA8 << 8): - _convert<1, false, 1, true, true, true>(width, height, rptr, wptr); - break; - case FORMAT_L8 | (FORMAT_R8 << 8): - _convert<1, false, 1, false, true, false>(width, height, rptr, wptr); - break; - case FORMAT_L8 | (FORMAT_RG8 << 8): - _convert<1, false, 2, false, true, false>(width, height, rptr, wptr); - break; - case FORMAT_L8 | (FORMAT_RGB8 << 8): - _convert<1, false, 3, false, true, false>(width, height, rptr, wptr); - break; - case FORMAT_L8 | (FORMAT_RGBA8 << 8): - _convert<1, false, 3, true, true, false>(width, height, rptr, wptr); - break; - case FORMAT_LA8 | (FORMAT_L8 << 8): - _convert<1, true, 1, false, true, true>(width, height, rptr, wptr); - break; - case FORMAT_LA8 | (FORMAT_R8 << 8): - _convert<1, true, 1, false, true, false>(width, height, rptr, wptr); - break; - case FORMAT_LA8 | (FORMAT_RG8 << 8): - _convert<1, true, 2, false, true, false>(width, height, rptr, wptr); - break; - case FORMAT_LA8 | (FORMAT_RGB8 << 8): - _convert<1, true, 3, false, true, false>(width, height, rptr, wptr); - break; - case FORMAT_LA8 | (FORMAT_RGBA8 << 8): - _convert<1, true, 3, true, true, false>(width, height, rptr, wptr); - break; - case FORMAT_R8 | (FORMAT_L8 << 8): - _convert<1, false, 1, false, false, true>(width, height, rptr, wptr); - break; - case FORMAT_R8 | (FORMAT_LA8 << 8): - _convert<1, false, 1, true, false, true>(width, height, rptr, wptr); - break; - case FORMAT_R8 | (FORMAT_RG8 << 8): - _convert<1, false, 2, false, false, false>(width, height, rptr, wptr); - break; - case FORMAT_R8 | (FORMAT_RGB8 << 8): - _convert<1, false, 3, false, false, false>(width, height, rptr, wptr); - break; - case FORMAT_R8 | (FORMAT_RGBA8 << 8): - _convert<1, false, 3, true, false, false>(width, height, rptr, wptr); - break; - case FORMAT_RG8 | (FORMAT_L8 << 8): - _convert<2, false, 1, false, false, true>(width, height, rptr, wptr); - break; - case FORMAT_RG8 | (FORMAT_LA8 << 8): - _convert<2, false, 1, true, false, true>(width, height, rptr, wptr); - break; - case FORMAT_RG8 | (FORMAT_R8 << 8): - _convert<2, false, 1, false, false, false>(width, height, rptr, wptr); - break; - case FORMAT_RG8 | (FORMAT_RGB8 << 8): - _convert<2, false, 3, false, false, false>(width, height, rptr, wptr); - break; - case FORMAT_RG8 | (FORMAT_RGBA8 << 8): - _convert<2, false, 3, true, false, false>(width, height, rptr, wptr); - break; - case FORMAT_RGB8 | (FORMAT_L8 << 8): - _convert<3, false, 1, false, false, true>(width, height, rptr, wptr); - break; - case FORMAT_RGB8 | (FORMAT_LA8 << 8): - _convert<3, false, 1, true, false, true>(width, height, rptr, wptr); - break; - case FORMAT_RGB8 | (FORMAT_R8 << 8): - _convert<3, false, 1, false, false, false>(width, height, rptr, wptr); - break; - case FORMAT_RGB8 | (FORMAT_RG8 << 8): - _convert<3, false, 2, false, false, false>(width, height, rptr, wptr); - break; - case FORMAT_RGB8 | (FORMAT_RGBA8 << 8): - _convert<3, false, 3, true, false, false>(width, height, rptr, wptr); - break; - case FORMAT_RGBA8 | (FORMAT_L8 << 8): - _convert<3, true, 1, false, false, true>(width, height, rptr, wptr); - break; - case FORMAT_RGBA8 | (FORMAT_LA8 << 8): - _convert<3, true, 1, true, false, true>(width, height, rptr, wptr); - break; - case FORMAT_RGBA8 | (FORMAT_R8 << 8): - _convert<3, true, 1, false, false, false>(width, height, rptr, wptr); - break; - case FORMAT_RGBA8 | (FORMAT_RG8 << 8): - _convert<3, true, 2, false, false, false>(width, height, rptr, wptr); - break; - case FORMAT_RGBA8 | (FORMAT_RGB8 << 8): - _convert<3, true, 3, false, false, false>(width, height, rptr, wptr); - break; - } - - bool gen_mipmaps = mipmaps; + for (int mip = 0; mip < mipmap_count; mip++) { + int mip_offset = 0; + int mip_size = 0; + int mip_width = 0; + int mip_height = 0; + get_mipmap_offset_size_and_dimensions(mip, mip_offset, mip_size, mip_width, mip_height); - _copy_internals_from(new_img); + const uint8_t *rptr = data.ptr() + mip_offset; + uint8_t *wptr = new_img.data.ptrw() + new_img.get_mipmap_offset(mip); - if (gen_mipmaps) { - generate_mipmaps(); + switch (conversion_type) { + case FORMAT_L8 | (FORMAT_LA8 << 8): + _convert<1, false, 1, true, true, true>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_L8 | (FORMAT_R8 << 8): + _convert<1, false, 1, false, true, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_L8 | (FORMAT_RG8 << 8): + _convert<1, false, 2, false, true, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_L8 | (FORMAT_RGB8 << 8): + _convert<1, false, 3, false, true, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_L8 | (FORMAT_RGBA8 << 8): + _convert<1, false, 3, true, true, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_LA8 | (FORMAT_L8 << 8): + _convert<1, true, 1, false, true, true>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_LA8 | (FORMAT_R8 << 8): + _convert<1, true, 1, false, true, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_LA8 | (FORMAT_RG8 << 8): + _convert<1, true, 2, false, true, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_LA8 | (FORMAT_RGB8 << 8): + _convert<1, true, 3, false, true, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_LA8 | (FORMAT_RGBA8 << 8): + _convert<1, true, 3, true, true, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_R8 | (FORMAT_L8 << 8): + _convert<1, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_R8 | (FORMAT_LA8 << 8): + _convert<1, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_R8 | (FORMAT_RG8 << 8): + _convert<1, false, 2, false, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_R8 | (FORMAT_RGB8 << 8): + _convert<1, false, 3, false, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_R8 | (FORMAT_RGBA8 << 8): + _convert<1, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RG8 | (FORMAT_L8 << 8): + _convert<2, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RG8 | (FORMAT_LA8 << 8): + _convert<2, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RG8 | (FORMAT_R8 << 8): + _convert<2, false, 1, false, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RG8 | (FORMAT_RGB8 << 8): + _convert<2, false, 3, false, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RG8 | (FORMAT_RGBA8 << 8): + _convert<2, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RGB8 | (FORMAT_L8 << 8): + _convert<3, false, 1, false, false, true>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RGB8 | (FORMAT_LA8 << 8): + _convert<3, false, 1, true, false, true>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RGB8 | (FORMAT_R8 << 8): + _convert<3, false, 1, false, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RGB8 | (FORMAT_RG8 << 8): + _convert<3, false, 2, false, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RGB8 | (FORMAT_RGBA8 << 8): + _convert<3, false, 3, true, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RGBA8 | (FORMAT_L8 << 8): + _convert<3, true, 1, false, false, true>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RGBA8 | (FORMAT_LA8 << 8): + _convert<3, true, 1, true, false, true>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RGBA8 | (FORMAT_R8 << 8): + _convert<3, true, 1, false, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RGBA8 | (FORMAT_RG8 << 8): + _convert<3, true, 2, false, false, false>(mip_width, mip_height, rptr, wptr); + break; + case FORMAT_RGBA8 | (FORMAT_RGB8 << 8): + _convert<3, true, 3, false, false, false>(mip_width, mip_height, rptr, wptr); + break; + } } + + _copy_internals_from(new_img); } Image::Format Image::get_format() const { @@ -3004,6 +3016,7 @@ ImageMemLoadFunc Image::_jpg_mem_loader_func = nullptr; ImageMemLoadFunc Image::_webp_mem_loader_func = nullptr; ImageMemLoadFunc Image::_tga_mem_loader_func = nullptr; ImageMemLoadFunc Image::_bmp_mem_loader_func = nullptr; +ScalableImageMemLoadFunc Image::_svg_scalable_mem_loader_func = nullptr; void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr; void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels) = nullptr; @@ -3476,6 +3489,9 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("load_tga_from_buffer", "buffer"), &Image::load_tga_from_buffer); ClassDB::bind_method(D_METHOD("load_bmp_from_buffer", "buffer"), &Image::load_bmp_from_buffer); + ClassDB::bind_method(D_METHOD("load_svg_from_buffer", "buffer", "scale"), &Image::load_svg_from_buffer, DEFVAL(1.0)); + ClassDB::bind_method(D_METHOD("load_svg_from_string", "svg_str", "scale"), &Image::load_svg_from_string, DEFVAL(1.0)); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "_set_data", "_get_data"); BIND_CONSTANT(MAX_WIDTH); @@ -3825,6 +3841,28 @@ Error Image::load_bmp_from_buffer(const Vector<uint8_t> &p_array) { return _load_from_buffer(p_array, _bmp_mem_loader_func); } +Error Image::load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale) { + ERR_FAIL_NULL_V_MSG( + _svg_scalable_mem_loader_func, + ERR_UNAVAILABLE, + "The SVG module isn't enabled. Recompile the Godot editor or export template binary with the `module_svg_enabled=yes` SCons option."); + + int buffer_size = p_array.size(); + + ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER); + + Ref<Image> image = _svg_scalable_mem_loader_func(p_array.ptr(), buffer_size, scale); + ERR_FAIL_COND_V(!image.is_valid(), ERR_PARSE_ERROR); + + copy_internals_from(image); + + return OK; +} + +Error Image::load_svg_from_string(const String &p_svg_str, float scale) { + return load_svg_from_buffer(p_svg_str.to_utf8_buffer(), scale); +} + void Image::convert_rg_to_ra_rgba8() { ERR_FAIL_COND(format != FORMAT_RGBA8); ERR_FAIL_COND(!data.size()); diff --git a/core/io/image.h b/core/io/image.h index 8e353a8bb7..f877b00ee6 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -48,6 +48,7 @@ typedef Vector<uint8_t> (*SavePNGBufferFunc)(const Ref<Image> &p_img); typedef Error (*SaveJPGFunc)(const String &p_path, const Ref<Image> &p_img, float p_quality); typedef Vector<uint8_t> (*SaveJPGBufferFunc)(const Ref<Image> &p_img, float p_quality); typedef Ref<Image> (*ImageMemLoadFunc)(const uint8_t *p_png, int p_size); +typedef Ref<Image> (*ScalableImageMemLoadFunc)(const uint8_t *p_data, int p_size, float p_scale); typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, const bool p_lossy, const float p_quality); typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality); @@ -148,6 +149,7 @@ public: static ImageMemLoadFunc _webp_mem_loader_func; static ImageMemLoadFunc _tga_mem_loader_func; static ImageMemLoadFunc _bmp_mem_loader_func; + static ScalableImageMemLoadFunc _svg_scalable_mem_loader_func; static void (*_image_compress_bc_func)(Image *, UsedChannels p_channels); static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels); @@ -401,6 +403,9 @@ public: Error load_tga_from_buffer(const Vector<uint8_t> &p_array); Error load_bmp_from_buffer(const Vector<uint8_t> &p_array); + Error load_svg_from_buffer(const Vector<uint8_t> &p_array, float scale = 1.0); + Error load_svg_from_string(const String &p_svg_str, float scale = 1.0); + void convert_rg_to_ra_rgba8(); void convert_ra_rgba8_to_rg(); void convert_rgba8_to_bgra8(); diff --git a/core/io/ip.cpp b/core/io/ip.cpp index 65728f34f6..772f700916 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -35,8 +35,6 @@ #include "core/templates/hash_map.h" #include "core/variant/typed_array.h" -VARIANT_ENUM_CAST(IP::ResolverStatus); - /************* RESOLVER ******************/ struct _IP_ResolverPrivate { diff --git a/core/io/ip.h b/core/io/ip.h index b768f0b9d4..4816d59ac2 100644 --- a/core/io/ip.h +++ b/core/io/ip.h @@ -109,5 +109,6 @@ public: }; VARIANT_ENUM_CAST(IP::Type); +VARIANT_ENUM_CAST(IP::ResolverStatus); #endif // IP_H diff --git a/core/io/json.cpp b/core/io/json.cpp index a6e054a9fe..496400a5ea 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -299,9 +299,15 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to } } break; - default: { + case '"': + case '\\': + case '/': { res = next; } break; + default: { + r_err_str = "Invalid escape sequence."; + return ERR_PARSE_ERROR; + } } str += res; diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index e7f4980e94..9b49cc3d8c 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -115,7 +115,9 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encr } File pf; - pf.path = p_file; + // Simplify path here and on every 'files' access so that paths that have extra '/' + // symbols in them still match to the MD5 hash for the saved path. + pf.path = p_file.simplify_path(); pf.src_path = p_src; pf.ofs = ofs; pf.size = f->get_length(); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index b4da314e96..3037f603c4 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -920,8 +920,11 @@ void ResourceLoaderBinary::get_dependencies(Ref<FileAccess> p_f, List<String> *p for (int i = 0; i < external_resources.size(); i++) { String dep; + String fallback_path; + if (external_resources[i].uid != ResourceUID::INVALID_ID) { dep = ResourceUID::get_singleton()->id_to_text(external_resources[i].uid); + fallback_path = external_resources[i].path; // Used by Dependency Editor, in case uid path fails. } else { dep = external_resources[i].path; } @@ -929,6 +932,12 @@ void ResourceLoaderBinary::get_dependencies(Ref<FileAccess> p_f, List<String> *p if (p_add_types && !external_resources[i].type.is_empty()) { dep += "::" + external_resources[i].type; } + if (!fallback_path.is_empty()) { + if (!p_add_types) { + dep += "::"; // Ensure that path comes third, even if there is no type. + } + dep += "::" + fallback_path; + } p_dependencies->push_back(dep); } @@ -1766,9 +1775,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V case Variant::OBJECT: { f->store_32(VARIANT_OBJECT); Ref<Resource> res = p_property; - if (res.is_null()) { + if (res.is_null() || res->get_meta(SNAME("_skip_save_"), false)) { f->store_32(OBJECT_EMPTY); - return; // don't save it + return; // Don't save it. } if (!res->is_built_in()) { @@ -1933,7 +1942,7 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant case Variant::OBJECT: { Ref<Resource> res = p_variant; - if (res.is_null() || external_resources.has(res)) { + if (res.is_null() || external_resources.has(res) || res->get_meta(SNAME("_skip_save_"), false)) { return; } diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index dc1de6b9ce..fcf4a727ca 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -394,6 +394,15 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_name(const String return Ref<ResourceImporter>(); } +void ResourceFormatImporter::add_importer(const Ref<ResourceImporter> &p_importer, bool p_first_priority) { + ERR_FAIL_COND(p_importer.is_null()); + if (p_first_priority) { + importers.insert(0, p_importer); + } else { + importers.push_back(p_importer); + } +} + void ResourceFormatImporter::get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter>> *r_importers) { for (int i = 0; i < importers.size(); i++) { List<String> local_exts; @@ -472,20 +481,13 @@ ResourceFormatImporter::ResourceFormatImporter() { singleton = this; } +////////////// + void ResourceImporter::_bind_methods() { BIND_ENUM_CONSTANT(IMPORT_ORDER_DEFAULT); BIND_ENUM_CONSTANT(IMPORT_ORDER_SCENE); } -void ResourceFormatImporter::add_importer(const Ref<ResourceImporter> &p_importer, bool p_first_priority) { - ERR_FAIL_COND(p_importer.is_null()); - if (p_first_priority) { - importers.insert(0, p_importer); - } else { - importers.push_back(p_importer); - } -} - ///// Error ResourceFormatImporterSaver::set_uid(const String &p_path, ResourceUID::ID p_uid) { diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index ac1870fe88..1fe662b1fa 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -239,15 +239,15 @@ 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) { load_nesting++; - if (load_paths_stack.size()) { + if (load_paths_stack->size()) { thread_load_mutex.lock(); - HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(load_paths_stack[load_paths_stack.size() - 1]); + HashMap<String, ThreadLoadTask>::Iterator E = thread_load_tasks.find(load_paths_stack->get(load_paths_stack->size() - 1)); if (E) { E->value.sub_tasks.insert(p_path); } thread_load_mutex.unlock(); } - load_paths_stack.push_back(p_path); + load_paths_stack->push_back(p_path); // Try all loaders and pick the first match for the type hint bool found = false; @@ -263,7 +263,7 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin } } - load_paths_stack.resize(load_paths_stack.size() - 1); + load_paths_stack->resize(load_paths_stack->size() - 1); load_nesting--; if (!res.is_null()) { @@ -296,8 +296,10 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { // Thread-safe either if it's the current thread or a brand new one. CallQueue *mq_override = nullptr; if (load_nesting == 0) { + load_paths_stack = memnew(Vector<String>); + if (!load_task.dependent_path.is_empty()) { - load_paths_stack.push_back(load_task.dependent_path); + load_paths_stack->push_back(load_task.dependent_path); } if (!Thread::is_main_thread()) { mq_override = memnew(CallQueue); @@ -309,6 +311,10 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { } // -- + if (!Thread::is_main_thread()) { + set_current_thread_safe_for_nodes(true); + } + Ref<Resource> res = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, load_task.cache_mode, &load_task.error, load_task.use_sub_threads, &load_task.progress); if (mq_override) { mq_override->flush(); @@ -356,9 +362,11 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { thread_load_mutex.unlock(); - if (load_nesting == 0 && mq_override) { - memdelete(mq_override); - set_current_thread_safe_for_nodes(false); + if (load_nesting == 0) { + if (mq_override) { + memdelete(mq_override); + } + memdelete(load_paths_stack); } } @@ -1167,7 +1175,7 @@ bool ResourceLoader::timestamp_on_load = false; thread_local int ResourceLoader::load_nesting = 0; thread_local WorkerThreadPool::TaskID ResourceLoader::caller_task_id = 0; -thread_local Vector<String> ResourceLoader::load_paths_stack; +thread_local Vector<String> *ResourceLoader::load_paths_stack; template <> thread_local uint32_t SafeBinaryMutex<ResourceLoader::BINARY_MUTEX_TAG>::count = 0; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 592befb603..2701caa3f4 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -182,7 +182,7 @@ private: static thread_local int load_nesting; static thread_local WorkerThreadPool::TaskID caller_task_id; - static thread_local Vector<String> load_paths_stack; + static thread_local Vector<String> *load_paths_stack; // A pointer to avoid broken TLS implementations from double-running the destructor. static SafeBinaryMutex<BINARY_MUTEX_TAG> thread_load_mutex; static HashMap<String, ThreadLoadTask> thread_load_tasks; static bool cleaning_tasks; diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index 5c0a017bfc..958734addf 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -34,8 +34,6 @@ //#define DEBUG_XML -VARIANT_ENUM_CAST(XMLParser::NodeType); - static inline bool _is_white_space(char c) { return (c == ' ' || c == '\t' || c == '\n' || c == '\r'); } diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h index b96478c7a5..77df99a881 100644 --- a/core/io/xml_parser.h +++ b/core/io/xml_parser.h @@ -126,4 +126,6 @@ public: ~XMLParser(); }; +VARIANT_ENUM_CAST(XMLParser::NodeType); + #endif // XML_PARSER_H diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 1481dbc32e..6b0ecadc7f 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -397,7 +397,7 @@ void Basis::rotate_to_align(Vector3 p_start_direction, Vector3 p_end_direction) real_t dot = p_start_direction.dot(p_end_direction); dot = CLAMP(dot, -1.0f, 1.0f); const real_t angle_rads = Math::acos(dot); - set_axis_angle(axis, angle_rads); + *this = Basis(axis, angle_rads) * (*this); } } diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp index 76b3062944..f8456ec998 100644 --- a/core/math/convex_hull.cpp +++ b/core/math/convex_hull.cpp @@ -658,7 +658,7 @@ private: Vector3 get_gd_normal(Face *p_face); - bool shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> p_stack); + bool shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> &p_stack); public: ~ConvexHullInternal() { @@ -1775,7 +1775,7 @@ real_t ConvexHullInternal::shrink(real_t p_amount, real_t p_clamp_amount) { return p_amount; } -bool ConvexHullInternal::shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> p_stack) { +bool ConvexHullInternal::shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> &p_stack) { Vector3 orig_shift = get_gd_normal(p_face) * -p_amount; if (scaling[0] != 0) { orig_shift[0] /= scaling[0]; diff --git a/core/math/delaunay_2d.h b/core/math/delaunay_2d.h index cf7ba8d48e..fc70724308 100644 --- a/core/math/delaunay_2d.h +++ b/core/math/delaunay_2d.h @@ -145,7 +145,7 @@ public: // Filter out the triangles containing vertices of the bounding triangle. int preserved_count = 0; Triangle *triangles_ptrw = triangles.ptrw(); - for (int i = 0; i < triangles.size() - 1; i++) { + for (int i = 0; i < triangles.size(); i++) { if (!(triangles[i].points[0] >= point_count || triangles[i].points[1] >= point_count || triangles[i].points[2] >= point_count)) { triangles_ptrw[preserved_count] = triangles[i]; preserved_count++; diff --git a/core/math/plane.cpp b/core/math/plane.cpp index 99694d7871..6b9bcea081 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -98,13 +98,11 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 Vector3 segment = p_dir; real_t den = normal.dot(segment); - //printf("den is %i\n",den); if (Math::is_zero_approx(den)) { return false; } real_t dist = (normal.dot(p_from) - d) / den; - //printf("dist is %i\n",dist); if (dist > (real_t)CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist @@ -121,13 +119,11 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec Vector3 segment = p_begin - p_end; real_t den = normal.dot(segment); - //printf("den is %i\n",den); if (Math::is_zero_approx(den)) { return false; } real_t dist = (normal.dot(p_begin) - d) / den; - //printf("dist is %i\n",dist); if (dist < (real_t)-CMP_EPSILON || dist > (1.0f + (real_t)CMP_EPSILON)) { return false; diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py index 18f27ae4a4..5be9650b32 100644 --- a/core/object/make_virtuals.py +++ b/core/object/make_virtuals.py @@ -154,7 +154,6 @@ def generate_version(argcount, const=False, returns=False): def run(target, source, env): - max_versions = 12 txt = """ @@ -165,7 +164,6 @@ def run(target, source, env): """ for i in range(max_versions + 1): - txt += "/* " + str(i) + " Arguments */\n\n" txt += generate_version(i, False, False) txt += generate_version(i, False, True) diff --git a/core/object/object.cpp b/core/object/object.cpp index d6937539c7..4d19a2c75b 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -836,14 +836,16 @@ void Object::set_script(const Variant &p_script) { return; } + Ref<Script> s = p_script; + ERR_FAIL_COND_MSG(s.is_null() && !p_script.is_null(), "Invalid parameter, it should be a reference to a valid script (or null)."); + + script = p_script; + if (script_instance) { memdelete(script_instance); script_instance = nullptr; } - script = p_script; - Ref<Script> s = script; - if (!s.is_null()) { if (s->can_instantiate()) { OBJ_DEBUG_LOCK @@ -1719,6 +1721,30 @@ uint32_t Object::get_edited_version() const { } #endif +StringName Object::get_class_name_for_extension(const GDExtension *p_library) const { + // Only return the class name per the extension if it matches the given p_library. + if (_extension && _extension->library == p_library) { + return _extension->class_name; + } + + // Extensions only have wrapper classes for classes exposed in ClassDB. + const StringName *class_name = _get_class_namev(); + if (ClassDB::is_class_exposed(*class_name)) { + return *class_name; + } + + // Find the nearest parent class that's exposed. + StringName parent_class = ClassDB::get_parent_class(*class_name); + while (parent_class != StringName()) { + if (ClassDB::is_class_exposed(parent_class)) { + return parent_class; + } + parent_class = ClassDB::get_parent_class(parent_class); + } + + return SNAME("Object"); +} + void Object::set_instance_binding(void *p_token, void *p_binding, const GDExtensionInstanceBindingCallbacks *p_callbacks) { // This is only meant to be used on creation by the binder. ERR_FAIL_COND(_instance_bindings != nullptr); diff --git a/core/object/object.h b/core/object/object.h index 6f626b0ed0..a3e9d025ea 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -800,17 +800,7 @@ public: return *_class_name_ptr; } - _FORCE_INLINE_ const StringName &get_class_name_for_extension(const GDExtension *p_library) const { - // Only return the class name per the extension if it matches the given p_library. - if (_extension && _extension->library == p_library) { - return _extension->class_name; - } - // Otherwise, return the name of the built-in class. - if (unlikely(!_class_name_ptr)) { - return *_get_class_namev(); - } - return *_class_name_ptr; - } + StringName get_class_name_for_extension(const GDExtension *p_library) const; /* IAPI */ diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h index 58706fb9a9..3386514706 100644 --- a/core/object/ref_counted.h +++ b/core/object/ref_counted.h @@ -242,8 +242,11 @@ public: template <class T> struct PtrToArg<Ref<T>> { _FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) { + if (p_ptr == nullptr) { + return Ref<T>(); + } // p_ptr points to a RefCounted object - return Ref<T>(const_cast<T *>(reinterpret_cast<const T *>(p_ptr))); + return Ref<T>(const_cast<T *>(*reinterpret_cast<T *const *>(p_ptr))); } typedef Ref<T> EncodeT; @@ -259,8 +262,11 @@ struct PtrToArg<const Ref<T> &> { typedef Ref<T> EncodeT; _FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) { + if (p_ptr == nullptr) { + return Ref<T>(); + } // p_ptr points to a RefCounted object - return Ref<T>((T *)p_ptr); + return Ref<T>(*((T *const *)p_ptr)); } }; diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 71f40660f4..a8b0e426ae 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -34,7 +34,6 @@ #include "core/core_string_names.h" #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" -#include "core/variant/typed_array.h" #include <stdint.h> @@ -43,7 +42,7 @@ int ScriptServer::_language_count = 0; bool ScriptServer::scripting_enabled = true; bool ScriptServer::reload_scripts_on_save = false; -bool ScriptServer::languages_finished = false; +SafeFlag ScriptServer::languages_finished; // Used until GH-76581 is fixed properly. ScriptEditRequestFunction ScriptServer::edit_request_func = nullptr; void Script::_notification(int p_what) { @@ -229,7 +228,7 @@ void ScriptServer::finish_languages() { _languages[i]->finish(); } global_classes_clear(); - languages_finished = true; + languages_finished.set(); } void ScriptServer::set_reload_scripts_on_save(bool p_enable) { @@ -241,12 +240,18 @@ bool ScriptServer::is_reload_scripts_on_save_enabled() { } void ScriptServer::thread_enter() { + if (!languages_finished.is_set()) { + return; + } for (int i = 0; i < _language_count; i++) { _languages[i]->thread_enter(); } } void ScriptServer::thread_exit() { + if (!languages_finished.is_set()) { + return; + } for (int i = 0; i < _language_count; i++) { _languages[i]->thread_exit(); } @@ -461,6 +466,52 @@ void ScriptLanguage::get_core_type_words(List<String> *p_core_type_words) const void ScriptLanguage::frame() { } +TypedArray<int> ScriptLanguage::CodeCompletionOption::get_option_characteristics(const String &p_base) { + // Return characacteristics of the match found by order of importance. + // Matches will be ranked by a lexicographical order on the vector returned by this function. + // The lower values indicate better matches and that they should go before in the order of appearance. + if (last_matches == matches) { + return charac; + } + charac.clear(); + // Ensure base is not empty and at the same time that matches is not empty too. + if (p_base.length() == 0) { + last_matches = matches; + charac.push_back(location); + return charac; + } + charac.push_back(matches.size()); + charac.push_back((matches[0].first == 0) ? 0 : 1); + charac.push_back(location); + const char32_t *target_char = &p_base[0]; + int bad_case = 0; + for (const Pair<int, int> &match_segment : matches) { + const char32_t *string_to_complete_char = &display[match_segment.first]; + for (int j = 0; j < match_segment.second; j++, string_to_complete_char++, target_char++) { + if (*string_to_complete_char != *target_char) { + bad_case++; + } + } + } + charac.push_back(bad_case); + charac.push_back(matches[0].first); + last_matches = matches; + return charac; +} + +void ScriptLanguage::CodeCompletionOption::clear_characteristics() { + charac = TypedArray<int>(); +} + +TypedArray<int> ScriptLanguage::CodeCompletionOption::get_option_cached_characteristics() const { + // Only returns the cached value and warns if it was not updated since the last change of matches. + if (last_matches != matches) { + WARN_PRINT("Characteristics are not up to date."); + } + + return charac; +} + bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) { if (script->is_placeholder_fallback_enabled()) { return false; diff --git a/core/object/script_language.h b/core/object/script_language.h index 696c9a94a5..2b685c77a3 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -35,6 +35,8 @@ #include "core/io/resource.h" #include "core/templates/pair.h" #include "core/templates/rb_map.h" +#include "core/templates/safe_refcount.h" +#include "core/variant/typed_array.h" class ScriptLanguage; template <typename T> @@ -51,7 +53,7 @@ class ScriptServer { static int _language_count; static bool scripting_enabled; static bool reload_scripts_on_save; - static bool languages_finished; + static SafeFlag languages_finished; // Used until GH-76581 is fixed properly. struct GlobalScriptClass { StringName language; @@ -96,7 +98,7 @@ public: static void init_languages(); static void finish_languages(); - static bool are_languages_finished() { return languages_finished; } + static bool are_languages_finished() { return languages_finished.is_set(); } }; class ScriptInstance; @@ -305,8 +307,8 @@ public: virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; } virtual bool overrides_external_editor() { return false; } - /* Keep enum in Sync with: */ - /* /scene/gui/code_edit.h - CodeEdit::CodeCompletionKind */ + // Keep enums in sync with: + // scene/gui/code_edit.h - CodeEdit::CodeCompletionKind enum CodeCompletionKind { CODE_COMPLETION_KIND_CLASS, CODE_COMPLETION_KIND_FUNCTION, @@ -321,6 +323,7 @@ public: CODE_COMPLETION_KIND_MAX }; + // scene/gui/code_edit.h - CodeEdit::CodeCompletionLocation enum CodeCompletionLocation { LOCATION_LOCAL = 0, LOCATION_PARENT_MASK = 1 << 8, @@ -336,6 +339,7 @@ public: Ref<Resource> icon; Variant default_value; Vector<Pair<int, int>> matches; + Vector<Pair<int, int>> last_matches = { { -1, -1 } }; // This value correspond to an impossible match int location = LOCATION_OTHER; CodeCompletionOption() {} @@ -346,6 +350,13 @@ public: kind = p_kind; location = p_location; } + + TypedArray<int> get_option_characteristics(const String &p_base); + void clear_characteristics(); + TypedArray<int> get_option_cached_characteristics() const; + + private: + TypedArray<int> charac; }; virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<CodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; } diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index 79cf712119..1a0ec29479 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -651,7 +651,7 @@ public: #ifdef TOOLS_ENABLED Ref<Script> script = get_script(); - if (script->is_valid() && pcount > 0) { + if (script.is_valid() && pcount > 0) { p_list->push_back(script->get_class_category()); } #endif // TOOLS_ENABLED diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index 077929351e..f04961c760 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -80,14 +80,14 @@ bool UndoRedo::_redo(bool p_execute) { return true; } -void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { +void UndoRedo::create_action(const String &p_name, MergeMode p_mode, bool p_backward_undo_ops) { uint64_t ticks = OS::get_singleton()->get_ticks_msec(); if (action_level == 0) { _discard_redo(); // Check if the merge operation is valid - if (p_mode != MERGE_DISABLE && actions.size() && actions[actions.size() - 1].name == p_name && actions[actions.size() - 1].last_tick + 800 > ticks) { + if (p_mode != MERGE_DISABLE && actions.size() && actions[actions.size() - 1].name == p_name && actions[actions.size() - 1].backward_undo_ops == p_backward_undo_ops && actions[actions.size() - 1].last_tick + 800 > ticks) { current_action = actions.size() - 2; if (p_mode == MERGE_ENDS) { @@ -108,12 +108,18 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { actions.write[actions.size() - 1].last_tick = ticks; + // Revert reverse from previous commit. + if (actions[actions.size() - 1].backward_undo_ops) { + actions.write[actions.size() - 1].undo_ops.reverse(); + } + merge_mode = p_mode; merging = true; } else { Action new_action; new_action.name = p_name; new_action.last_tick = ticks; + new_action.backward_undo_ops = p_backward_undo_ops; actions.push_back(new_action); merge_mode = MERGE_DISABLE; @@ -292,6 +298,10 @@ void UndoRedo::commit_action(bool p_execute) { merging = false; } + if (actions[actions.size() - 1].backward_undo_ops) { + actions.write[actions.size() - 1].undo_ops.reverse(); + } + committing++; _redo(p_execute); // perform action committing--; @@ -302,6 +312,11 @@ void UndoRedo::commit_action(bool p_execute) { } void UndoRedo::_process_operation_list(List<Operation>::Element *E) { + const int PREALLOCATE_ARGS_COUNT = 16; + + LocalVector<const Variant *> args; + args.reserve(PREALLOCATE_ARGS_COUNT); + for (; E; E = E->next()) { Operation &op = E->get(); @@ -337,12 +352,13 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) { if (binds.is_empty()) { method_callback(method_callback_ud, obj, op.name, nullptr, 0); } else { - const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * binds.size()); + args.clear(); + for (int i = 0; i < binds.size(); i++) { - args[i] = (const Variant *)&binds[i]; + args.push_back(&binds[i]); } - method_callback(method_callback_ud, obj, op.name, args, binds.size()); + method_callback(method_callback_ud, obj, op.name, args.ptr(), binds.size()); } } } break; @@ -458,7 +474,7 @@ UndoRedo::~UndoRedo() { } void UndoRedo::_bind_methods() { - ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE)); + ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode", "backward_undo_ops"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE), DEFVAL(false)); ClassDB::bind_method(D_METHOD("commit_action", "execute"), &UndoRedo::commit_action, DEFVAL(true)); ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action); diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index 5dc9f2966c..389d8714f7 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -58,7 +58,7 @@ private: TYPE_REFERENCE } type; - bool force_keep_in_merge_ends; + bool force_keep_in_merge_ends = false; Ref<RefCounted> ref; ObjectID object; StringName name; @@ -72,7 +72,8 @@ private: String name; List<Operation> do_ops; List<Operation> undo_ops; - uint64_t last_tick; + uint64_t last_tick = 0; + bool backward_undo_ops = false; }; Vector<Action> actions; @@ -102,7 +103,7 @@ protected: static void _bind_methods(); public: - void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE); + void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE, bool p_backward_undo_ops = false); void add_do_method(const Callable &p_callable); void add_undo_method(const Callable &p_callable); diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp index afe6ecd1b3..5ec3e1a1a8 100644 --- a/core/object/worker_thread_pool.cpp +++ b/core/object/worker_thread_pool.cpp @@ -31,6 +31,7 @@ #include "worker_thread_pool.h" #include "core/os/os.h" +#include "core/os/thread_safe.h" void WorkerThreadPool::Task::free_template_userdata() { ERR_FAIL_COND(!template_userdata); @@ -55,6 +56,8 @@ void WorkerThreadPool::_process_task(Task *p_task) { Task *prev_low_prio_task = nullptr; // In case this is recursively called. if (!use_native_low_priority_threads) { + // Tasks must start with this unset. They are free to set-and-forget otherwise. + set_current_thread_safe_for_nodes(false); pool_thread_index = thread_ids[Thread::get_caller_id()]; ThreadData &curr_thread = threads[pool_thread_index]; task_mutex.lock(); @@ -367,7 +370,9 @@ Error WorkerThreadPool::wait_for_task_completion(TaskID p_task_id) { must_exit = true; } else { // Solve tasks while they are around. + bool safe_for_nodes_backup = is_current_thread_safe_for_nodes(); _process_task_queue(); + set_current_thread_safe_for_nodes(safe_for_nodes_backup); continue; } } else if (!use_native_low_priority_threads && task->low_priority) { @@ -411,7 +416,7 @@ Error WorkerThreadPool::wait_for_task_completion(TaskID p_task_id) { WorkerThreadPool::GroupID WorkerThreadPool::_add_group_task(const Callable &p_callable, void (*p_func)(void *, uint32_t), void *p_userdata, BaseTemplateUserdata *p_template_userdata, int p_elements, int p_tasks, bool p_high_priority, const String &p_description) { ERR_FAIL_COND_V(p_elements < 0, INVALID_TASK_ID); if (p_tasks < 0) { - p_tasks = threads.size(); + p_tasks = MAX(1u, threads.size()); } task_mutex.lock(); diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index 1e32e6e096..1a51624030 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -400,17 +400,38 @@ String keycode_get_string(Key p_code) { return codestr; } -Key find_keycode(const String &p_code) { +Key find_keycode(const String &p_codestr) { + Key keycode = Key::NONE; + Vector<String> code_parts = p_codestr.split("+"); + if (code_parts.size() < 1) { + return keycode; + } + + String last_part = code_parts[code_parts.size() - 1]; const _KeyCodeText *kct = &_keycodes[0]; while (kct->text) { - if (p_code.nocasecmp_to(kct->text) == 0) { - return kct->code; + if (last_part.nocasecmp_to(kct->text) == 0) { + keycode = kct->code; + break; } kct++; } - return Key::NONE; + for (int part = 0; part < code_parts.size() - 1; part++) { + String code_part = code_parts[part]; + if (code_part.nocasecmp_to(find_keycode_name(Key::SHIFT)) == 0) { + keycode |= KeyModifierMask::SHIFT; + } else if (code_part.nocasecmp_to(find_keycode_name(Key::CTRL)) == 0) { + keycode |= KeyModifierMask::CTRL; + } else if (code_part.nocasecmp_to(find_keycode_name(Key::META)) == 0) { + keycode |= KeyModifierMask::META; + } else if (code_part.nocasecmp_to(find_keycode_name(Key::ALT)) == 0) { + keycode |= KeyModifierMask::ALT; + } + } + + return keycode; } const char *find_keycode_name(Key p_keycode) { diff --git a/core/os/keyboard.h b/core/os/keyboard.h index 84017e89a6..cf276dc49f 100644 --- a/core/os/keyboard.h +++ b/core/os/keyboard.h @@ -330,7 +330,7 @@ constexpr KeyModifierMask operator|(KeyModifierMask a, KeyModifierMask b) { String keycode_get_string(Key p_code); bool keycode_has_unicode(Key p_keycode); -Key find_keycode(const String &p_code); +Key find_keycode(const String &p_codestr); const char *find_keycode_name(Key p_keycode); int keycode_get_count(); int keycode_get_value_by_index(int p_index); diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index b908b64d73..5e21490164 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -52,15 +52,7 @@ void MainLoop::_bind_methods() { GDVIRTUAL_BIND(_finalize); } -void MainLoop::set_initialize_script(const Ref<Script> &p_initialize_script) { - initialize_script = p_initialize_script; -} - void MainLoop::initialize() { - if (initialize_script.is_valid()) { - set_script(initialize_script); - } - GDVIRTUAL_CALL(_initialize); } diff --git a/core/os/main_loop.h b/core/os/main_loop.h index 36eeb35aad..90cad009b1 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -39,8 +39,6 @@ class MainLoop : public Object { GDCLASS(MainLoop, Object); - Ref<Script> initialize_script; - protected: static void _bind_methods(); @@ -69,8 +67,6 @@ public: virtual bool process(double p_time); virtual void finalize(); - void set_initialize_script(const Ref<Script> &p_initialize_script); - MainLoop() {} virtual ~MainLoop() {} }; diff --git a/core/os/os.cpp b/core/os/os.cpp index 5704ef7a40..67423128a3 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -295,12 +295,14 @@ Error OS::shell_open(String p_uri) { } Error OS::shell_show_in_file_manager(String p_path, bool p_open_folder) { - if (!p_path.begins_with("file://")) { - p_path = String("file://") + p_path; - } - if (!p_path.ends_with("/")) { + p_path = p_path.trim_prefix("file://"); + + if (!DirAccess::dir_exists_absolute(p_path)) { p_path = p_path.get_base_dir(); } + + p_path = String("file://") + p_path; + return shell_open(p_path); } // implement these with the canvas? diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h deleted file mode 100644 index 34b417ae57..0000000000 --- a/core/os/threaded_array_processor.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************/ -/* threaded_array_processor.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 THREADED_ARRAY_PROCESSOR_H -#define THREADED_ARRAY_PROCESSOR_H - -#include "core/os/os.h" -#include "core/os/thread.h" -#include "core/os/thread_safe.h" -#include "core/templates/safe_refcount.h" - -template <class C, class U> -struct ThreadArrayProcessData { - uint32_t elements; - SafeNumeric<uint32_t> index; - C *instance; - U userdata; - void (C::*method)(uint32_t, U); - - void process(uint32_t p_index) { - (instance->*method)(p_index, userdata); - } -}; - -template <class T> -void process_array_thread(void *ud) { - T &data = *(T *)ud; - while (true) { - uint32_t index = data.index.increment(); - if (index >= data.elements) { - break; - } - data.process(index); - } -} - -template <class C, class M, class U> -void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) { - ThreadArrayProcessData<C, U> data; - data.method = p_method; - data.instance = p_instance; - data.userdata = p_userdata; - data.index.set(0); - data.elements = p_elements; - data.process(0); //process first, let threads increment for next - - int thread_count = OS::get_singleton()->get_processor_count(); - Thread *threads = memnew_arr(Thread, thread_count); - - for (int i = 0; i < thread_count; i++) { - threads[i].start(process_array_thread<ThreadArrayProcessData<C, U>>, &data); - } - - for (int i = 0; i < thread_count; i++) { - threads[i].wait_to_finish(); - } - memdelete_arr(threads); -} - -#endif // THREADED_ARRAY_PROCESSOR_H diff --git a/core/os/time.cpp b/core/os/time.cpp index 038e4adc03..bad5cc2e4f 100644 --- a/core/os/time.cpp +++ b/core/os/time.cpp @@ -52,9 +52,6 @@ static const uint8_t MONTH_DAYS_TABLE[2][12] = { { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } }; -VARIANT_ENUM_CAST(Month); -VARIANT_ENUM_CAST(Weekday); - #define UNIX_TIME_TO_HMS \ uint8_t hour, minute, second; \ { \ diff --git a/core/os/time.h b/core/os/time.h index 19bc900aee..ccd2d92b8b 100644 --- a/core/os/time.h +++ b/core/os/time.h @@ -81,4 +81,7 @@ public: virtual ~Time(); }; +VARIANT_ENUM_CAST(Month); +VARIANT_ENUM_CAST(Weekday); + #endif // TIME_H diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index c276f20f99..12e6423724 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -62,6 +62,7 @@ static _FORCE_INLINE_ char32_t lower_case(char32_t c) { const char CharString::_null = 0; const char16_t Char16String::_null = 0; const char32_t String::_null = 0; +const char32_t String::_replacement_char = 0xfffd; bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end) { const String &s = p_s; @@ -307,7 +308,7 @@ void String::copy_from(const char *p_cstr) { uint8_t c = p_cstr[i] >= 0 ? p_cstr[i] : uint8_t(256 + p_cstr[i]); if (c == 0 && i < len) { print_unicode_error("NUL character", true); - dst[i] = 0x20; + dst[i] = _replacement_char; } else { dst[i] = c; } @@ -340,7 +341,7 @@ void String::copy_from(const char *p_cstr, const int p_clip_to) { uint8_t c = p_cstr[i] >= 0 ? p_cstr[i] : uint8_t(256 + p_cstr[i]); if (c == 0) { print_unicode_error("NUL character", true); - dst[i] = 0x20; + dst[i] = _replacement_char; } else { dst[i] = c; } @@ -373,17 +374,21 @@ void String::copy_from(const char32_t &p_char) { print_unicode_error("NUL character", true); return; } + + resize(2); + + char32_t *dst = ptrw(); + if ((p_char & 0xfffff800) == 0xd800) { print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)p_char)); - } - if (p_char > 0x10ffff) { + dst[0] = _replacement_char; + } else if (p_char > 0x10ffff) { print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_t)p_char)); + dst[0] = _replacement_char; + } else { + dst[0] = p_char; } - resize(2); - - char32_t *dst = ptrw(); - dst[0] = p_char; dst[1] = 0; } @@ -439,14 +444,18 @@ void String::copy_from_unchecked(const char32_t *p_char, const int p_length) { for (int i = 0; i < p_length; i++) { if (p_char[i] == 0) { print_unicode_error("NUL character", true); - dst[i] = 0x20; + dst[i] = _replacement_char; continue; } if ((p_char[i] & 0xfffff800) == 0xd800) { print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)p_char[i])); + dst[i] = _replacement_char; + continue; } if (p_char[i] > 0x10ffff) { print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_t)p_char[i])); + dst[i] = _replacement_char; + continue; } dst[i] = p_char[i]; } @@ -538,7 +547,7 @@ String &String::operator+=(const char *p_str) { uint8_t c = p_str[i] >= 0 ? p_str[i] : uint8_t(256 + p_str[i]); if (c == 0 && i < rhs_len) { print_unicode_error("NUL character", true); - dst[i] = 0x20; + dst[i] = _replacement_char; } else { dst[i] = c; } @@ -568,17 +577,21 @@ String &String::operator+=(char32_t p_char) { print_unicode_error("NUL character", true); return *this; } + + const int lhs_len = length(); + resize(lhs_len + 2); + char32_t *dst = ptrw(); + if ((p_char & 0xfffff800) == 0xd800) { print_unicode_error(vformat("Unpaired surrogate (%x)", (uint32_t)p_char)); - } - if (p_char > 0x10ffff) { + dst[lhs_len] = _replacement_char; + } else if (p_char > 0x10ffff) { print_unicode_error(vformat("Invalid unicode codepoint (%x)", (uint32_t)p_char)); + dst[lhs_len] = _replacement_char; + } else { + dst[lhs_len] = p_char; } - const int lhs_len = length(); - resize(lhs_len + 2); - char32_t *dst = ptrw(); - dst[lhs_len] = p_char; dst[lhs_len + 1] = 0; return *this; @@ -1737,7 +1750,7 @@ Vector<uint8_t> String::hex_decode() const { void String::print_unicode_error(const String &p_message, bool p_critical) const { if (p_critical) { - print_error(vformat("Unicode parsing error, some characters were replaced with spaces: %s", p_message)); + print_error(vformat("Unicode parsing error, some characters were replaced with � (U+FFFD): %s", p_message)); } else { print_error(vformat("Unicode parsing error: %s", p_message)); } @@ -1757,7 +1770,7 @@ CharString String::ascii(bool p_allow_extended) const { cs[i] = c; } else { print_unicode_error(vformat("Invalid unicode codepoint (%x), cannot represent as ASCII/Latin-1", (uint32_t)c)); - cs[i] = 0x20; + cs[i] = 0x20; // ascii doesn't have a replacement character like unicode, 0x1a is sometimes used but is kinda arcane } } @@ -1897,13 +1910,13 @@ Error String::parse_utf8(const char *p_utf8, int p_len, bool p_skip_cr) { unichar = (0xff >> 7) & c; skip = 5; } else { - *(dst++) = 0x20; + *(dst++) = _replacement_char; unichar = 0; skip = 0; } } else { if (c < 0x80 || c > 0xbf) { - *(dst++) = 0x20; + *(dst++) = _replacement_char; skip = 0; } else { unichar = (unichar << 6) | (c & 0x3f); @@ -1912,15 +1925,15 @@ Error String::parse_utf8(const char *p_utf8, int p_len, bool p_skip_cr) { if (unichar == 0) { print_unicode_error("NUL character", true); decode_failed = true; - unichar = 0x20; - } - if ((unichar & 0xfffff800) == 0xd800) { - print_unicode_error(vformat("Unpaired surrogate (%x)", unichar)); - decode_error = true; - } - if (unichar > 0x10ffff) { - print_unicode_error(vformat("Invalid unicode codepoint (%x)", unichar)); - decode_error = true; + unichar = _replacement_char; + } else if ((unichar & 0xfffff800) == 0xd800) { + print_unicode_error(vformat("Unpaired surrogate (%x)", unichar), true); + decode_failed = true; + unichar = _replacement_char; + } else if (unichar > 0x10ffff) { + print_unicode_error(vformat("Invalid unicode codepoint (%x)", unichar), true); + decode_failed = true; + unichar = _replacement_char; } *(dst++) = unichar; } @@ -2014,7 +2027,11 @@ CharString String::utf8() const { APPEND_CHAR(uint32_t(0x80 | ((c >> 6) & 0x3f))); // Lower lower middle 6 bits. APPEND_CHAR(uint32_t(0x80 | (c & 0x3f))); // Bottom 6 bits. } else { - APPEND_CHAR(0x20); + // the string is a valid UTF32, so it should never happen ... + print_unicode_error(vformat("Non scalar value (%x)", c), true); + APPEND_CHAR(uint32_t(0xe0 | ((_replacement_char >> 12) & 0x0f))); // Top 4 bits. + APPEND_CHAR(uint32_t(0x80 | ((_replacement_char >> 6) & 0x3f))); // Middle 6 bits. + APPEND_CHAR(uint32_t(0x80 | (_replacement_char & 0x3f))); // Bottom 6 bits. } } #undef APPEND_CHAR @@ -2187,7 +2204,9 @@ Char16String String::utf16() const { APPEND_CHAR(uint32_t((c >> 10) + 0xd7c0)); // lead surrogate. APPEND_CHAR(uint32_t((c & 0x3ff) | 0xdc00)); // trail surrogate. } else { - APPEND_CHAR(0x20); + // the string is a valid UTF32, so it should never happen ... + APPEND_CHAR(uint32_t((_replacement_char >> 10) + 0xd7c0)); + APPEND_CHAR(uint32_t((_replacement_char & 0x3ff) | 0xdc00)); } } #undef APPEND_CHAR @@ -4262,12 +4281,13 @@ String String::pad_zeros(int p_digits) const { begin++; } - if (begin >= end) { + int zeros_to_add = p_digits - (end - begin); + + if (zeros_to_add <= 0) { return s; + } else { + return s.insert(begin, String("0").repeat(zeros_to_add)); } - - int zeros_to_add = p_digits - (end - begin); - return s.insert(begin, String("0").repeat(zeros_to_add)); } String String::trim_prefix(const String &p_prefix) const { diff --git a/core/string/ustring.h b/core/string/ustring.h index 782ca47507..295625395d 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -183,6 +183,7 @@ struct StrRange { class String { CowData<char32_t> _cowdata; static const char32_t _null; + static const char32_t _replacement_char; void copy_from(const char *p_cstr); void copy_from(const char *p_cstr, const int p_clip_to); diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h index 9ccd7bb0bf..e2ffabdaf0 100644 --- a/core/templates/rid_owner.h +++ b/core/templates/rid_owner.h @@ -117,6 +117,7 @@ class RID_Alloc : public RID_AllocBase { uint32_t free_element = free_index % elements_in_chunk; uint32_t validator = (uint32_t)(_gen_id() & 0x7FFFFFFF); + CRASH_COND_MSG(validator == 0x7FFFFFFF, "Overflow in RID validator"); uint64_t id = validator; id <<= 32; id |= free_index; @@ -238,7 +239,7 @@ public: uint32_t validator = uint32_t(id >> 32); - bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator; + bool owned = (validator != 0x7FFFFFFF) && (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator; if (THREAD_SAFE) { spin_lock.unlock(); diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp index 378d1ff618..e493e50467 100644 --- a/core/variant/callable_bind.cpp +++ b/core/variant/callable_bind.cpp @@ -144,6 +144,18 @@ void CallableCustomBind::call(const Variant **p_arguments, int p_argcount, Varia callable.callp(args, p_argcount + binds.size(), r_return_value, r_call_error); } +Error CallableCustomBind::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const { + const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * (binds.size() + p_argcount)); + for (int i = 0; i < p_argcount; i++) { + args[i] = (const Variant *)p_arguments[i]; + } + for (int i = 0; i < binds.size(); i++) { + args[i + p_argcount] = (const Variant *)&binds[i]; + } + + return callable.rpcp(p_peer_id, args, p_argcount + binds.size(), r_call_error); +} + CallableCustomBind::CallableCustomBind(const Callable &p_callable, const Vector<Variant> &p_binds) { callable = p_callable; binds = p_binds; @@ -242,6 +254,16 @@ void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Var callable.callp(p_arguments, p_argcount - argcount, r_return_value, r_call_error); } +Error CallableCustomUnbind::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const { + if (argcount > p_argcount) { + r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; + r_call_error.argument = 0; + r_call_error.expected = argcount; + return ERR_UNCONFIGURED; + } + return callable.rpcp(p_peer_id, p_arguments, p_argcount - argcount, r_call_error); +} + CallableCustomUnbind::CallableCustomUnbind(const Callable &p_callable, int p_argcount) { callable = p_callable; argcount = p_argcount; diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h index b51076ad0f..5798797a3d 100644 --- a/core/variant/callable_bind.h +++ b/core/variant/callable_bind.h @@ -51,6 +51,7 @@ public: virtual StringName get_method() const override; virtual ObjectID get_object() const override; virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override; + virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override; virtual const Callable *get_base_comparator() const override; virtual int get_bound_arguments_count() const override; virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override; @@ -78,6 +79,7 @@ public: virtual StringName get_method() const override; virtual ObjectID get_object() const override; virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override; + virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const override; virtual const Callable *get_base_comparator() const override; virtual int get_bound_arguments_count() const override; virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override; diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp index 0429508cc5..f019273735 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -83,9 +83,16 @@ Variant &Dictionary::operator[](const Variant &p_key) { if (unlikely(_p->read_only)) { if (p_key.get_type() == Variant::STRING_NAME) { const StringName *sn = VariantInternal::get_string_name(&p_key); - *_p->read_only = _p->variant_map[sn->operator String()]; - } else { + const String &key = sn->operator String(); + if (likely(_p->variant_map.has(key))) { + *_p->read_only = _p->variant_map[key]; + } else { + *_p->read_only = Variant(); + } + } else if (likely(_p->variant_map.has(p_key))) { *_p->read_only = _p->variant_map[p_key]; + } else { + *_p->read_only = Variant(); } return *_p->read_only; diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h index df1e524494..cbfb9cc257 100644 --- a/core/variant/method_ptrcall.h +++ b/core/variant/method_ptrcall.h @@ -159,7 +159,10 @@ MAKE_PTRARG_BY_REFERENCE(Variant); template <class T> struct PtrToArg<T *> { _FORCE_INLINE_ static T *convert(const void *p_ptr) { - return const_cast<T *>(reinterpret_cast<const T *>(p_ptr)); + if (p_ptr == nullptr) { + return nullptr; + } + return const_cast<T *>(*reinterpret_cast<T *const *>(p_ptr)); } typedef Object *EncodeT; _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { @@ -170,7 +173,10 @@ struct PtrToArg<T *> { template <class T> struct PtrToArg<const T *> { _FORCE_INLINE_ static const T *convert(const void *p_ptr) { - return reinterpret_cast<const T *>(p_ptr); + if (p_ptr == nullptr) { + return nullptr; + } + return *reinterpret_cast<T *const *>(p_ptr); } typedef const Object *EncodeT; _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { diff --git a/core/variant/native_ptr.h b/core/variant/native_ptr.h index ea811daabf..9199b12845 100644 --- a/core/variant/native_ptr.h +++ b/core/variant/native_ptr.h @@ -53,36 +53,46 @@ struct GDExtensionPtr { operator Variant() const { return uint64_t(data); } }; -#define GDVIRTUAL_NATIVE_PTR(m_type) \ - template <> \ - struct GDExtensionConstPtr<const m_type> { \ - const m_type *data = nullptr; \ - GDExtensionConstPtr() {} \ - GDExtensionConstPtr(const m_type *p_assign) { data = p_assign; } \ - static const char *get_name() { return "const " #m_type; } \ - operator const m_type *() const { return data; } \ - operator Variant() const { return uint64_t(data); } \ - }; \ - template <> \ - struct VariantCaster<GDExtensionConstPtr<const m_type>> { \ - static _FORCE_INLINE_ GDExtensionConstPtr<const m_type> cast(const Variant &p_variant) { \ - return GDExtensionConstPtr<const m_type>((const m_type *)p_variant.operator uint64_t()); \ - } \ - }; \ - template <> \ - struct GDExtensionPtr<m_type> { \ - m_type *data = nullptr; \ - GDExtensionPtr() {} \ - GDExtensionPtr(m_type *p_assign) { data = p_assign; } \ - static const char *get_name() { return #m_type; } \ - operator m_type *() const { return data; } \ - operator Variant() const { return uint64_t(data); } \ - }; \ - template <> \ - struct VariantCaster<GDExtensionPtr<m_type>> { \ - static _FORCE_INLINE_ GDExtensionPtr<m_type> cast(const Variant &p_variant) { \ - return GDExtensionPtr<m_type>((m_type *)p_variant.operator uint64_t()); \ - } \ +#define GDVIRTUAL_NATIVE_PTR(m_type) \ + template <> \ + struct GDExtensionConstPtr<const m_type> { \ + const m_type *data = nullptr; \ + GDExtensionConstPtr() {} \ + GDExtensionConstPtr(const m_type *p_assign) { data = p_assign; } \ + static const char *get_name() { return "const " #m_type; } \ + operator const m_type *() const { return data; } \ + operator Variant() const { return uint64_t(data); } \ + }; \ + template <> \ + struct VariantCaster<GDExtensionConstPtr<const m_type>> { \ + static _FORCE_INLINE_ GDExtensionConstPtr<const m_type> cast(const Variant &p_variant) { \ + return GDExtensionConstPtr<const m_type>((const m_type *)p_variant.operator uint64_t()); \ + } \ + }; \ + template <> \ + struct VariantInternalAccessor<GDExtensionConstPtr<const m_type>> { \ + static _FORCE_INLINE_ const GDExtensionConstPtr<const m_type> &get(const Variant *v) { return *reinterpret_cast<const GDExtensionConstPtr<const m_type> *>(VariantInternal::get_int(v)); } \ + static _FORCE_INLINE_ void set(Variant *v, const GDExtensionConstPtr<const m_type> &p_value) { *VariantInternal::get_int(v) = uint64_t(p_value.data); } \ + }; \ + template <> \ + struct GDExtensionPtr<m_type> { \ + m_type *data = nullptr; \ + GDExtensionPtr() {} \ + GDExtensionPtr(m_type *p_assign) { data = p_assign; } \ + static const char *get_name() { return #m_type; } \ + operator m_type *() const { return data; } \ + operator Variant() const { return uint64_t(data); } \ + }; \ + template <> \ + struct VariantCaster<GDExtensionPtr<m_type>> { \ + static _FORCE_INLINE_ GDExtensionPtr<m_type> cast(const Variant &p_variant) { \ + return GDExtensionPtr<m_type>((m_type *)p_variant.operator uint64_t()); \ + } \ + }; \ + template <> \ + struct VariantInternalAccessor<GDExtensionPtr<m_type>> { \ + static _FORCE_INLINE_ const GDExtensionPtr<m_type> &get(const Variant *v) { return *reinterpret_cast<const GDExtensionPtr<m_type> *>(VariantInternal::get_int(v)); } \ + static _FORCE_INLINE_ void set(Variant *v, const GDExtensionPtr<m_type> &p_value) { *VariantInternal::get_int(v) = uint64_t(p_value.data); } \ }; template <class T> diff --git a/core/variant/variant.h b/core/variant/variant.h index f694e59051..04c2fe2012 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -488,7 +488,7 @@ public: Variant(const IPAddress &p_address); #define VARIANT_ENUM_CLASS_CONSTRUCTOR(m_enum) \ - Variant(const m_enum &p_value) { \ + Variant(m_enum p_value) { \ type = INT; \ _data._int = (int64_t)p_value; \ } diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 8013c1a32a..782053b613 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -502,7 +502,7 @@ public: case Variant::PACKED_COLOR_ARRAY: return get_color_array(v); case Variant::OBJECT: - return v->_get_obj().obj; + return get_object(v); case Variant::VARIANT_MAX: ERR_FAIL_V(nullptr); } @@ -1541,7 +1541,7 @@ struct VariantTypeConstructor { _FORCE_INLINE_ static void type_from_variant(void *r_value, void *p_variant) { // r_value is provided by caller as uninitialized memory - memnew_placement(r_value, T(VariantInternalAccessor<T>::get(reinterpret_cast<Variant *>(p_variant)))); + memnew_placement(r_value, T(*reinterpret_cast<Variant *>(p_variant))); } }; diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index 33c285dc6d..aed83ac010 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -900,6 +900,39 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNotInt>(Variant::OP_NOT, Variant::INT, Variant::NIL); register_op<OperatorEvaluatorNotFloat>(Variant::OP_NOT, Variant::FLOAT, Variant::NIL); register_op<OperatorEvaluatorNotObject>(Variant::OP_NOT, Variant::OBJECT, Variant::NIL); + register_op<OperatorEvaluatorNot<String>>(Variant::OP_NOT, Variant::STRING, Variant::NIL); + register_op<OperatorEvaluatorNot<Vector2>>(Variant::OP_NOT, Variant::VECTOR2, Variant::NIL); + register_op<OperatorEvaluatorNot<Vector2i>>(Variant::OP_NOT, Variant::VECTOR2I, Variant::NIL); + register_op<OperatorEvaluatorNot<Rect2>>(Variant::OP_NOT, Variant::RECT2, Variant::NIL); + register_op<OperatorEvaluatorNot<Rect2i>>(Variant::OP_NOT, Variant::RECT2I, Variant::NIL); + register_op<OperatorEvaluatorNot<Vector3>>(Variant::OP_NOT, Variant::VECTOR3, Variant::NIL); + register_op<OperatorEvaluatorNot<Vector3i>>(Variant::OP_NOT, Variant::VECTOR3I, Variant::NIL); + register_op<OperatorEvaluatorNot<Transform2D>>(Variant::OP_NOT, Variant::TRANSFORM2D, Variant::NIL); + register_op<OperatorEvaluatorNot<Vector4>>(Variant::OP_NOT, Variant::VECTOR4, Variant::NIL); + register_op<OperatorEvaluatorNot<Vector4i>>(Variant::OP_NOT, Variant::VECTOR4I, Variant::NIL); + register_op<OperatorEvaluatorNot<Plane>>(Variant::OP_NOT, Variant::PLANE, Variant::NIL); + register_op<OperatorEvaluatorNot<Quaternion>>(Variant::OP_NOT, Variant::QUATERNION, Variant::NIL); + register_op<OperatorEvaluatorNot<::AABB>>(Variant::OP_NOT, Variant::AABB, Variant::NIL); + register_op<OperatorEvaluatorNot<Basis>>(Variant::OP_NOT, Variant::BASIS, Variant::NIL); + register_op<OperatorEvaluatorNot<Transform3D>>(Variant::OP_NOT, Variant::TRANSFORM3D, Variant::NIL); + register_op<OperatorEvaluatorNot<Projection>>(Variant::OP_NOT, Variant::PROJECTION, Variant::NIL); + register_op<OperatorEvaluatorNot<Color>>(Variant::OP_NOT, Variant::COLOR, Variant::NIL); + register_op<OperatorEvaluatorNot<StringName>>(Variant::OP_NOT, Variant::STRING_NAME, Variant::NIL); + register_op<OperatorEvaluatorNot<NodePath>>(Variant::OP_NOT, Variant::NODE_PATH, Variant::NIL); + register_op<OperatorEvaluatorNot<::RID>>(Variant::OP_NOT, Variant::RID, Variant::NIL); + register_op<OperatorEvaluatorNot<Callable>>(Variant::OP_NOT, Variant::CALLABLE, Variant::NIL); + register_op<OperatorEvaluatorNot<Signal>>(Variant::OP_NOT, Variant::SIGNAL, Variant::NIL); + register_op<OperatorEvaluatorNot<Dictionary>>(Variant::OP_NOT, Variant::DICTIONARY, Variant::NIL); + register_op<OperatorEvaluatorNot<Array>>(Variant::OP_NOT, Variant::ARRAY, Variant::NIL); + register_op<OperatorEvaluatorNot<PackedByteArray>>(Variant::OP_NOT, Variant::PACKED_BYTE_ARRAY, Variant::NIL); + register_op<OperatorEvaluatorNot<PackedInt32Array>>(Variant::OP_NOT, Variant::PACKED_INT32_ARRAY, Variant::NIL); + register_op<OperatorEvaluatorNot<PackedInt64Array>>(Variant::OP_NOT, Variant::PACKED_INT64_ARRAY, Variant::NIL); + register_op<OperatorEvaluatorNot<PackedFloat32Array>>(Variant::OP_NOT, Variant::PACKED_FLOAT32_ARRAY, Variant::NIL); + register_op<OperatorEvaluatorNot<PackedFloat64Array>>(Variant::OP_NOT, Variant::PACKED_FLOAT64_ARRAY, Variant::NIL); + register_op<OperatorEvaluatorNot<PackedStringArray>>(Variant::OP_NOT, Variant::PACKED_STRING_ARRAY, Variant::NIL); + register_op<OperatorEvaluatorNot<PackedVector2Array>>(Variant::OP_NOT, Variant::PACKED_VECTOR2_ARRAY, Variant::NIL); + register_op<OperatorEvaluatorNot<PackedVector3Array>>(Variant::OP_NOT, Variant::PACKED_VECTOR3_ARRAY, Variant::NIL); + register_op<OperatorEvaluatorNot<PackedColorArray>>(Variant::OP_NOT, Variant::PACKED_COLOR_ARRAY, Variant::NIL); register_string_op(OperatorEvaluatorInStringFind, Variant::OP_IN); diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h index d2163cf92d..c11f726402 100644 --- a/core/variant/variant_op.h +++ b/core/variant/variant_op.h @@ -805,14 +805,14 @@ class OperatorEvaluatorNot { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - *r_ret = !a; + *r_ret = a == A(); r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<A>::get_ptr(left); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) == A(); } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(!PtrToArg<A>::convert(left)); + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) == A(), r_ret); } static Variant::Type get_return_type() { return Variant::BOOL; } }; @@ -824,6 +824,11 @@ public: _FORCE_INLINE_ static void _add_arrays(Array &sum, const Array &array_a, const Array &array_b) { int asize = array_a.size(); int bsize = array_b.size(); + + if (array_a.is_typed() && array_a.is_same_typed(array_b)) { + sum.set_typed(array_a.get_typed_builtin(), array_a.get_typed_class_name(), array_a.get_typed_script()); + } + sum.resize(asize + bsize); for (int i = 0; i < asize; i++) { sum[i] = array_a[i]; diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index a40fcfbd47..3320750994 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -865,12 +865,46 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } get_token(p_stream, token, line, r_err_str); - if (token.type != TK_NUMBER) { - r_err_str = "Expected number as argument"; + // Permit empty RID. + if (token.type == TK_PARENTHESIS_CLOSE) { + value = RID(); + return OK; + } else if (token.type != TK_NUMBER) { + r_err_str = "Expected number as argument or ')'"; return ERR_PARSE_ERROR; } - value = token.value; + value = RID::from_uint64(token.value); + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_PARENTHESIS_CLOSE) { + r_err_str = "Expected ')'"; + return ERR_PARSE_ERROR; + } + } else if (id == "Signal") { + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_PARENTHESIS_OPEN) { + r_err_str = "Expected '('"; + return ERR_PARSE_ERROR; + } + + // Load as empty. + value = Signal(); + + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_PARENTHESIS_CLOSE) { + r_err_str = "Expected ')'"; + return ERR_PARSE_ERROR; + } + } else if (id == "Callable") { + get_token(p_stream, token, line, r_err_str); + if (token.type != TK_PARENTHESIS_OPEN) { + r_err_str = "Expected '('"; + return ERR_PARSE_ERROR; + } + + // Load as empty. + value = Callable(); get_token(p_stream, token, line, r_err_str); if (token.type != TK_PARENTHESIS_CLOSE) { @@ -1832,6 +1866,24 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; + case Variant::RID: { + RID rid = p_variant; + + if (rid == RID()) { + p_store_string_func(p_store_string_ud, "RID()"); + } else { + p_store_string_func(p_store_string_ud, "RID(" + itos(rid.get_id()) + ")"); + } + } break; + + // Do not really store these, but ensure that assignments are not empty. + case Variant::SIGNAL: { + p_store_string_func(p_store_string_ud, "Signal()"); + } break; + case Variant::CALLABLE: { + p_store_string_func(p_store_string_ud, "Callable()"); + } break; + case Variant::OBJECT: { Object *obj = p_variant.get_validated_object(); @@ -2129,6 +2181,8 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; default: { + ERR_PRINT("Unknown variant type"); + return ERR_BUG; } } |