diff options
Diffstat (limited to 'core')
28 files changed, 254 insertions, 78 deletions
diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 2bb8837849..d714ec42c2 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -114,6 +114,8 @@ Dictionary Engine::get_version_info() const { String hash = String(VERSION_HASH); dict["hash"] = hash.is_empty() ? String("unknown") : hash; + dict["timestamp"] = VERSION_TIMESTAMP; + String stringver = String(dict["major"]) + "." + String(dict["minor"]); if ((int)dict["patch"] != 0) { stringver += "." + String(dict["patch"]); diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index d9a5a5094a..d1c90ed7e6 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1514,6 +1514,7 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray()); GLOBAL_DEF_INTERNAL("internationalization/locale/translations", PackedStringArray()); GLOBAL_DEF_INTERNAL("internationalization/locale/translations_pot_files", PackedStringArray()); + GLOBAL_DEF_INTERNAL("internationalization/locale/translation_add_builtin_strings_to_pot", false); ProjectSettings::get_singleton()->add_hidden_prefix("input/"); } diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 6dbb0996eb..b5098fc4d2 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -145,6 +145,8 @@ void ResourceLoader::_bind_methods() { BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE); BIND_ENUM_CONSTANT(CACHE_MODE_REUSE); BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE); + BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE_DEEP); + BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE_DEEP); } ////// ResourceSaver ////// diff --git a/core/core_bind.h b/core/core_bind.h index 7b7eb46fd9..d5b8151f1e 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -63,9 +63,11 @@ public: }; enum CacheMode { - CACHE_MODE_IGNORE, // Resource and subresources do not use path cache, no path is set into resource. - CACHE_MODE_REUSE, // Resource and subresources use patch cache, reuse existing loaded resources instead of loading from disk when available. - CACHE_MODE_REPLACE, // Resource and subresource use path cache, but replace existing loaded resources when available with information from disk. + CACHE_MODE_IGNORE, + CACHE_MODE_REUSE, + CACHE_MODE_REPLACE, + CACHE_MODE_IGNORE_DEEP, + CACHE_MODE_REPLACE_DEEP, }; static ResourceLoader *get_singleton() { return singleton; } diff --git a/core/core_builders.py b/core/core_builders.py index 8b6b87ad83..61b7bd695c 100644 --- a/core/core_builders.py +++ b/core/core_builders.py @@ -2,6 +2,7 @@ All such functions are invoked in a subprocess on Windows to prevent build flakiness. """ + import zlib from platform_methods import subprocess_main diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp index 0c96c32187..f96a8873ca 100644 --- a/core/extension/gdextension_interface.cpp +++ b/core/extension/gdextension_interface.cpp @@ -1415,7 +1415,7 @@ static void gdextension_editor_help_load_xml_from_utf8_chars(const char *p_data) #endif } -#define REGISTER_INTERFACE_FUNC(m_name) GDExtension::register_interface_function(#m_name, (GDExtensionInterfaceFunctionPtr)&gdextension_##m_name) +#define REGISTER_INTERFACE_FUNC(m_name) GDExtension::register_interface_function(#m_name, (GDExtensionInterfaceFunctionPtr) & gdextension_##m_name) void gdextension_setup_interface() { REGISTER_INTERFACE_FUNC(get_godot_version); diff --git a/core/io/resource.cpp b/core/io/resource.cpp index daa57be76f..7e8d0b43cd 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -41,7 +41,12 @@ #include <stdio.h> void Resource::emit_changed() { - emit_signal(CoreStringNames::get_singleton()->changed); + if (ResourceLoader::is_within_load() && !Thread::is_main_thread()) { + // Let the connection happen on the main thread, later, since signals are not thread-safe. + call_deferred("emit_signal", CoreStringNames::get_singleton()->changed); + } else { + emit_signal(CoreStringNames::get_singleton()->changed); + } } void Resource::_resource_path_changed() { @@ -152,12 +157,22 @@ bool Resource::editor_can_reload_from_file() { } void Resource::connect_changed(const Callable &p_callable, uint32_t p_flags) { + if (ResourceLoader::is_within_load() && !Thread::is_main_thread()) { + // Let the check and connection happen on the main thread, later, since signals are not thread-safe. + callable_mp(this, &Resource::connect_changed).call_deferred(p_callable, p_flags); + return; + } if (!is_connected(CoreStringNames::get_singleton()->changed, p_callable) || p_flags & CONNECT_REFERENCE_COUNTED) { connect(CoreStringNames::get_singleton()->changed, p_callable, p_flags); } } void Resource::disconnect_changed(const Callable &p_callable) { + if (ResourceLoader::is_within_load() && !Thread::is_main_thread()) { + // Let the check and disconnection happen on the main thread, later, since signals are not thread-safe. + callable_mp(this, &Resource::disconnect_changed).call_deferred(p_callable); + return; + } if (is_connected(CoreStringNames::get_singleton()->changed, p_callable)) { disconnect(CoreStringNames::get_singleton()->changed, p_callable); } diff --git a/core/io/resource.h b/core/io/resource.h index b885b773ac..f0f686af57 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -106,7 +106,7 @@ public: virtual void set_path(const String &p_path, bool p_take_over = false); String get_path() const; - void set_path_cache(const String &p_path); // Set raw path without involving resource cache. + virtual void set_path_cache(const String &p_path); // Set raw path without involving resource cache. _FORCE_INLINE_ bool is_built_in() const { return path_cache.is_empty() || path_cache.contains("::") || path_cache.begins_with("local://"); } static String generate_scene_unique_id(); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 20c494516b..17cffb878e 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -430,7 +430,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { path = remaps[path]; } - Ref<Resource> res = ResourceLoader::load(path, exttype); + Ref<Resource> res = ResourceLoader::load(path, exttype, cache_mode_for_external); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data()); @@ -683,7 +683,7 @@ Error ResourceLoaderBinary::load() { } external_resources.write[i].path = path; //remap happens here, not on load because on load it can actually be used for filesystem dock resource remap - external_resources.write[i].load_token = ResourceLoader::_load_start(path, external_resources[i].type, use_sub_threads ? ResourceLoader::LOAD_THREAD_DISTRIBUTE : ResourceLoader::LOAD_THREAD_FROM_CURRENT, ResourceFormatLoader::CACHE_MODE_REUSE); + external_resources.write[i].load_token = ResourceLoader::_load_start(path, external_resources[i].type, use_sub_threads ? ResourceLoader::LOAD_THREAD_DISTRIBUTE : ResourceLoader::LOAD_THREAD_FROM_CURRENT, cache_mode_for_external); if (!external_resources[i].load_token.is_valid()) { if (!ResourceLoader::get_abort_on_missing_resources()) { ResourceLoader::notify_dependency_error(local_path, path, external_resources[i].type); @@ -772,10 +772,12 @@ Error ResourceLoaderBinary::load() { } res = Ref<Resource>(r); - if (!path.is_empty() && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { - r->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); //if got here because the resource with same path has different type, replace it - } else if (!path.is_resource_file()) { - r->set_path_cache(path); + if (!path.is_empty()) { + if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { + r->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); // If got here because the resource with same path has different type, replace it. + } else { + r->set_path_cache(path); + } } r->set_scene_unique_id(id); } @@ -1187,7 +1189,22 @@ Ref<Resource> ResourceFormatLoaderBinary::load(const String &p_path, const Strin ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot open file '" + p_path + "'."); ResourceLoaderBinary loader; - loader.cache_mode = p_cache_mode; + switch (p_cache_mode) { + case CACHE_MODE_IGNORE: + case CACHE_MODE_REUSE: + case CACHE_MODE_REPLACE: + loader.cache_mode = p_cache_mode; + loader.cache_mode_for_external = CACHE_MODE_REUSE; + break; + case CACHE_MODE_IGNORE_DEEP: + loader.cache_mode = CACHE_MODE_IGNORE; + loader.cache_mode_for_external = p_cache_mode; + break; + case CACHE_MODE_REPLACE_DEEP: + loader.cache_mode = CACHE_MODE_REPLACE; + loader.cache_mode_for_external = p_cache_mode; + break; + } loader.use_sub_threads = p_use_sub_threads; loader.progress = r_progress; String path = !p_original_path.is_empty() ? p_original_path : p_path; diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index e64485d404..e01c5fa467 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -85,6 +85,7 @@ class ResourceLoaderBinary { Error error = OK; ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE; + ResourceFormatLoader::CacheMode cache_mode_for_external = ResourceFormatLoader::CACHE_MODE_REUSE; friend class ResourceFormatLoaderBinary; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index a3fc7bc370..ff563a35b2 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -188,6 +188,8 @@ void ResourceFormatLoader::_bind_methods() { BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE); BIND_ENUM_CONSTANT(CACHE_MODE_REUSE); BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE); + BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE_DEEP); + BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE_DEEP); GDVIRTUAL_BIND(_get_recognized_extensions); GDVIRTUAL_BIND(_recognize_path, "path", "type"); @@ -339,9 +341,11 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { load_task.cond_var = nullptr; } + bool ignoring = load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE || load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP; + bool replacing = load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE || load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP; if (load_task.resource.is_valid()) { - if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { - if (load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE) { + if (!ignoring) { + if (replacing) { Ref<Resource> old_res = ResourceCache::get_ref(load_task.local_path); if (old_res.is_valid() && old_res != load_task.resource) { // If resource is already loaded, only replace its data, to avoid existing invalidating instances. @@ -349,8 +353,8 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { load_task.resource = old_res; } } - load_task.resource->set_path(load_task.local_path, load_task.cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); - } else if (!load_task.local_path.is_resource_file()) { + load_task.resource->set_path(load_task.local_path, replacing); + } else { load_task.resource->set_path_cache(load_task.local_path); } @@ -370,7 +374,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) { if (_loaded_callback) { _loaded_callback(load_task.resource, load_task.local_path); } - } else if (load_task.cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { + } else if (!ignoring) { Ref<Resource> existing = ResourceCache::get_ref(load_task.local_path); if (existing.is_valid()) { load_task.resource = existing; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 1f79b83f11..5caf699d32 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -47,9 +47,11 @@ class ResourceFormatLoader : public RefCounted { public: enum CacheMode { - CACHE_MODE_IGNORE, // Resource and subresources do not use path cache, no path is set into resource. - CACHE_MODE_REUSE, // Resource and subresources use patch cache, reuse existing loaded resources instead of loading from disk when available. - CACHE_MODE_REPLACE, // Resource and subresource use path cache, but replace existing loaded resources when available with information from disk. + CACHE_MODE_IGNORE, + CACHE_MODE_REUSE, + CACHE_MODE_REPLACE, + CACHE_MODE_IGNORE_DEEP, + CACHE_MODE_REPLACE_DEEP, }; protected: diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp index e2edf8b23e..4d55455166 100644 --- a/core/math/geometry_3d.cpp +++ b/core/math/geometry_3d.cpp @@ -393,7 +393,7 @@ static inline void _build_faces(uint8_t ***p_cell_status, int x, int y, int z, i return; } -#define vert(m_idx) Vector3(((m_idx)&4) >> 2, ((m_idx)&2) >> 1, (m_idx)&1) +#define vert(m_idx) Vector3(((m_idx) & 4) >> 2, ((m_idx) & 2) >> 1, (m_idx) & 1) static const uint8_t indices[6][4] = { { 7, 6, 4, 5 }, diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 63adc5b502..231a8e4d68 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -599,7 +599,9 @@ ObjectGDExtension *ClassDB::get_placeholder_extension(const StringName &p_class) placeholder_extension->property_can_revert = &PlaceholderExtensionInstance::placeholder_instance_property_can_revert; placeholder_extension->property_get_revert = &PlaceholderExtensionInstance::placeholder_instance_property_get_revert; placeholder_extension->validate_property = &PlaceholderExtensionInstance::placeholder_instance_validate_property; +#ifndef DISABLE_DEPRECATED placeholder_extension->notification = nullptr; +#endif // DISABLE_DEPRECATED placeholder_extension->notification2 = &PlaceholderExtensionInstance::placeholder_instance_notification; placeholder_extension->to_string = &PlaceholderExtensionInstance::placeholder_instance_to_string; placeholder_extension->reference = &PlaceholderExtensionInstance::placeholder_instance_reference; diff --git a/core/object/method_bind.h b/core/object/method_bind.h index a1723adb9a..88b867a1ca 100644 --- a/core/object/method_bind.h +++ b/core/object/method_bind.h @@ -226,7 +226,7 @@ class MethodBindVarArgT : public MethodBindVarArgBase<MethodBindVarArgT<T>, T, v public: virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == MethodBind::get_instance_class(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgT<T>, T, void, false>::method)(p_args, p_arg_count, r_error); return {}; @@ -265,7 +265,7 @@ public: #endif virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == MethodBind::get_instance_class(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif return (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)(p_args, p_arg_count, r_error); } @@ -336,7 +336,7 @@ public: #endif virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_variant_args_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments()); @@ -348,7 +348,7 @@ public: virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_validated_object_instance_args(static_cast<T *>(p_object), method, p_args); @@ -359,7 +359,7 @@ public: virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_ptr_args<T, P...>(static_cast<T *>(p_object), method, p_args); @@ -420,7 +420,7 @@ public: #endif virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), Variant(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_variant_argsc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, r_error, get_default_arguments()); @@ -432,7 +432,7 @@ public: virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_validated_object_instance_argsc(static_cast<T *>(p_object), method, p_args); @@ -443,7 +443,7 @@ public: virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_ptr_argsc<T, P...>(static_cast<T *>(p_object), method, p_args); @@ -515,7 +515,7 @@ public: virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { Variant ret; #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), ret, vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), ret, vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_variant_args_ret_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments()); @@ -527,7 +527,7 @@ public: virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_validated_object_instance_args_ret(static_cast<T *>(p_object), method, p_args, r_ret); @@ -538,7 +538,7 @@ public: virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_ptr_args_ret<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret); @@ -611,7 +611,7 @@ public: virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) const override { Variant ret; #ifdef TOOLS_ENABLED - ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder(), ret, vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_V_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), ret, vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_variant_args_retc_dv(static_cast<T *>(p_object), method, p_args, p_arg_count, ret, r_error, get_default_arguments()); @@ -623,7 +623,7 @@ public: virtual void validated_call(Object *p_object, const Variant **p_args, Variant *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_validated_object_instance_args_retc(static_cast<T *>(p_object), method, p_args, r_ret); @@ -634,7 +634,7 @@ public: virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) const override { #ifdef TOOLS_ENABLED - ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); + ERR_FAIL_COND_MSG(p_object && p_object->is_extension_placeholder() && p_object->get_class_name() == get_instance_class(), vformat("Cannot call method bind '%s' on placeholder instance.", MethodBind::get_name())); #endif #ifdef TYPED_METHOD_BIND call_with_ptr_args_retc<T, R, P...>(static_cast<T *>(p_object), method, p_args, r_ret); diff --git a/core/object/object.cpp b/core/object/object.cpp index 5d5a721811..b34182cdaa 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1483,10 +1483,15 @@ String Object::tr(const StringName &p_message, const StringName &p_context) cons } if (Engine::get_singleton()->is_editor_hint()) { + String tr_msg = TranslationServer::get_singleton()->extractable_translate(p_message, p_context); + if (!tr_msg.is_empty()) { + return tr_msg; + } + return TranslationServer::get_singleton()->tool_translate(p_message, p_context); - } else { - return TranslationServer::get_singleton()->translate(p_message, p_context); } + + return TranslationServer::get_singleton()->translate(p_message, p_context); } String Object::tr_n(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { @@ -1499,10 +1504,15 @@ String Object::tr_n(const StringName &p_message, const StringName &p_message_plu } if (Engine::get_singleton()->is_editor_hint()) { + String tr_msg = TranslationServer::get_singleton()->extractable_translate_plural(p_message, p_message_plural, p_n, p_context); + if (!tr_msg.is_empty()) { + return tr_msg; + } + return TranslationServer::get_singleton()->tool_translate_plural(p_message, p_message_plural, p_n, p_context); - } else { - return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context); } + + return TranslationServer::get_singleton()->translate_plural(p_message, p_message_plural, p_n, p_context); } void Object::_clear_internal_resource_paths(const Variant &p_var) { diff --git a/core/string/node_path.cpp b/core/string/node_path.cpp index 32e4564c5e..8ae2efb787 100644 --- a/core/string/node_path.cpp +++ b/core/string/node_path.cpp @@ -92,6 +92,14 @@ StringName NodePath::get_subname(int p_idx) const { return data->subpath[p_idx]; } +int NodePath::get_total_name_count() const { + if (!data) { + return 0; + } + + return data->path.size() + data->subpath.size(); +} + void NodePath::unref() { if (data && data->refcount.unref()) { memdelete(data); @@ -229,6 +237,27 @@ StringName NodePath::get_concatenated_subnames() const { return data->concatenated_subpath; } +NodePath NodePath::slice(int p_begin, int p_end) const { + const int name_count = get_name_count(); + const int total_count = get_total_name_count(); + + int begin = CLAMP(p_begin, -total_count, total_count); + if (begin < 0) { + begin += total_count; + } + int end = CLAMP(p_end, -total_count, total_count); + if (end < 0) { + end += total_count; + } + const int sub_begin = MAX(begin - name_count - 1, 0); + const int sub_end = MAX(end - name_count, 0); + + const Vector<StringName> names = get_names().slice(begin, end); + const Vector<StringName> sub_names = get_subnames().slice(sub_begin, sub_end); + const bool absolute = is_absolute() && (begin == 0); + return NodePath(names, sub_names, absolute); +} + NodePath NodePath::rel_path_to(const NodePath &p_np) const { ERR_FAIL_COND_V(!is_absolute(), NodePath()); ERR_FAIL_COND_V(!p_np.is_absolute(), NodePath()); @@ -331,7 +360,7 @@ NodePath NodePath::simplified() const { } NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) { - if (p_path.size() == 0) { + if (p_path.size() == 0 && !p_absolute) { return; } @@ -343,7 +372,7 @@ NodePath::NodePath(const Vector<StringName> &p_path, bool p_absolute) { } NodePath::NodePath(const Vector<StringName> &p_path, const Vector<StringName> &p_subpath, bool p_absolute) { - if (p_path.size() == 0 && p_subpath.size() == 0) { + if (p_path.size() == 0 && p_subpath.size() == 0 && !p_absolute) { return; } diff --git a/core/string/node_path.h b/core/string/node_path.h index 876d69924e..56799839d7 100644 --- a/core/string/node_path.h +++ b/core/string/node_path.h @@ -57,10 +57,12 @@ public: StringName get_name(int p_idx) const; int get_subname_count() const; StringName get_subname(int p_idx) const; + int get_total_name_count() const; Vector<StringName> get_names() const; Vector<StringName> get_subnames() const; StringName get_concatenated_names() const; StringName get_concatenated_subnames() const; + NodePath slice(int p_begin, int p_end = INT_MAX) const; NodePath rel_path_to(const NodePath &p_np) const; NodePath get_as_property_path() const; diff --git a/core/string/translation.cpp b/core/string/translation.cpp index db0c3f6006..2f25f56eac 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -772,6 +772,20 @@ StringName TranslationServer::tool_translate_plural(const StringName &p_message, return p_message_plural; } +void TranslationServer::set_property_translation(const Ref<Translation> &p_translation) { + property_translation = p_translation; +} + +StringName TranslationServer::property_translate(const StringName &p_message) const { + if (property_translation.is_valid()) { + StringName r = property_translation->get_message(p_message); + if (r) { + return r; + } + } + return p_message; +} + void TranslationServer::set_doc_translation(const Ref<Translation> &p_translation) { doc_translation = p_translation; } @@ -800,13 +814,13 @@ StringName TranslationServer::doc_translate_plural(const StringName &p_message, return p_message_plural; } -void TranslationServer::set_property_translation(const Ref<Translation> &p_translation) { - property_translation = p_translation; +void TranslationServer::set_extractable_translation(const Ref<Translation> &p_translation) { + extractable_translation = p_translation; } -StringName TranslationServer::property_translate(const StringName &p_message) const { - if (property_translation.is_valid()) { - StringName r = property_translation->get_message(p_message); +StringName TranslationServer::extractable_translate(const StringName &p_message, const StringName &p_context) const { + if (extractable_translation.is_valid()) { + StringName r = extractable_translation->get_message(p_message, p_context); if (r) { return r; } @@ -814,6 +828,20 @@ StringName TranslationServer::property_translate(const StringName &p_message) co return p_message; } +StringName TranslationServer::extractable_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { + if (extractable_translation.is_valid()) { + StringName r = extractable_translation->get_plural_message(p_message, p_message_plural, p_n, p_context); + if (r) { + return r; + } + } + + if (p_n == 1) { + return p_message; + } + return p_message_plural; +} + bool TranslationServer::is_pseudolocalization_enabled() const { return pseudolocalization_enabled; } diff --git a/core/string/translation.h b/core/string/translation.h index 4eca37f6be..bd7082dc9d 100644 --- a/core/string/translation.h +++ b/core/string/translation.h @@ -82,8 +82,9 @@ class TranslationServer : public Object { HashSet<Ref<Translation>> translations; Ref<Translation> tool_translation; - Ref<Translation> doc_translation; Ref<Translation> property_translation; + Ref<Translation> doc_translation; + Ref<Translation> extractable_translation; bool enabled = true; @@ -181,11 +182,14 @@ public: Ref<Translation> get_tool_translation() const; StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const; StringName tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; + void set_property_translation(const Ref<Translation> &p_translation); + StringName property_translate(const StringName &p_message) const; void set_doc_translation(const Ref<Translation> &p_translation); StringName doc_translate(const StringName &p_message, const StringName &p_context = "") const; StringName doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; - void set_property_translation(const Ref<Translation> &p_translation); - StringName property_translate(const StringName &p_message) const; + void set_extractable_translation(const Ref<Translation> &p_translation); + StringName extractable_translate(const StringName &p_message, const StringName &p_context = "") const; + StringName extractable_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; void setup(); diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index a8a96e6e3f..f4b00255a1 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -5391,9 +5391,7 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St /** * "Run-time TRanslate". Performs string replacement for internationalization - * within a running project. The translation string must be supplied by the - * project, as Godot does not provide built-in translations for `RTR()` strings - * to keep binary size low. A translation context can optionally be specified to + * without the editor. A translation context can optionally be specified to * disambiguate between identical source strings in translations. When * placeholders are desired, use `vformat(RTR("Example: %s"), some_string)`. * If a string mentions a quantity (and may therefore need a dynamic plural form), @@ -5407,9 +5405,8 @@ String RTR(const String &p_text, const String &p_context) { String rtr = TranslationServer::get_singleton()->tool_translate(p_text, p_context); if (rtr.is_empty() || rtr == p_text) { return TranslationServer::get_singleton()->translate(p_text, p_context); - } else { - return rtr; } + return rtr; } return p_text; @@ -5417,13 +5414,10 @@ String RTR(const String &p_text, const String &p_context) { /** * "Run-time TRanslate for N items". Performs string replacement for - * internationalization within a running project. The translation string must be - * supplied by the project, as Godot does not provide built-in translations for - * `RTRN()` strings to keep binary size low. A translation context can - * optionally be specified to disambiguate between identical source strings in - * translations. Use `RTR()` if the string doesn't need dynamic plural form. - * When placeholders are desired, use - * `vformat(RTRN("%d item", "%d items", some_integer), some_integer)`. + * internationalization without the editor. A translation context can optionally + * be specified to disambiguate between identical source strings in translations. + * Use `RTR()` if the string doesn't need dynamic plural form. When placeholders + * are desired, use `vformat(RTRN("%d item", "%d items", some_integer), some_integer)`. * The placeholder must be present in both strings to avoid run-time warnings in `vformat()`. * * NOTE: Do not use `RTRN()` in editor-only code (typically within the `editor/` @@ -5434,9 +5428,8 @@ String RTRN(const String &p_text, const String &p_text_plural, int p_n, const St String rtr = TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context); if (rtr.is_empty() || rtr == p_text || rtr == p_text_plural) { return TranslationServer::get_singleton()->translate_plural(p_text, p_text_plural, p_n, p_context); - } else { - return rtr; } + return rtr; } // Return message based on English plural rule if translation is not possible. diff --git a/core/string/ustring.h b/core/string/ustring.h index b1348ceb48..468a015302 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -556,6 +556,43 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St String RTR(const String &p_text, const String &p_context = ""); String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = ""); +/** + * "Extractable TRanslate". Used for strings that can appear inside an exported + * project (such as the ones in nodes like `FileDialog`), which are made possible + * to add in the POT generator. A translation context can optionally be specified + * to disambiguate between identical source strings in translations. + * When placeholders are desired, use vformat(ETR("Example: %s"), some_string)`. + * If a string mentions a quantity (and may therefore need a dynamic plural form), + * use `ETRN()` instead of `ETR()`. + * + * NOTE: This function is for string extraction only, and will just return the + * string it was given. The translation itself should be done internally by nodes + * with `atr()` instead. + */ +_FORCE_INLINE_ String ETR(const String &p_text, const String &p_context = "") { + return p_text; +} + +/** + * "Extractable TRanslate for N items". Used for strings that can appear inside an + * exported project (such as the ones in nodes like `FileDialog`), which are made + * possible to add in the POT generator. A translation context can optionally be + * specified to disambiguate between identical source strings in translations. + * Use `ETR()` if the string doesn't need dynamic plural form. When placeholders + * are desired, use `vformat(ETRN("%d item", "%d items", some_integer), some_integer)`. + * The placeholder must be present in both strings to avoid run-time warnings in `vformat()`. + * + * NOTE: This function is for string extraction only, and will just return the + * string it was given. The translation itself should be done internally by nodes + * with `atr()` instead. + */ +_FORCE_INLINE_ String ETRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context = "") { + if (p_n == 1) { + return p_text; + } + return p_text_plural; +} + bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end); _FORCE_INLINE_ void sarray_add_str(Vector<String> &arr) { diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index 55f687bdf9..6bad6f5a5b 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -30,10 +30,11 @@ #include "callable.h" -#include "callable_bind.h" #include "core/object/object.h" #include "core/object/ref_counted.h" #include "core/object/script_language.h" +#include "core/variant/callable_bind.h" +#include "core/variant/variant_callable.h" void Callable::call_deferredp(const Variant **p_arguments, int p_argcount) const { MessageQueue::get_singleton()->push_callablep(*this, p_arguments, p_argcount, true); @@ -327,14 +328,27 @@ Callable::operator String() const { } } +Callable Callable::create(const Variant &p_variant, const StringName &p_method) { + ERR_FAIL_COND_V_MSG(p_method == StringName(), Callable(), "Method argument to Callable::create method must be a non-empty string."); + + switch (p_variant.get_type()) { + case Variant::NIL: + return Callable(ObjectID(), p_method); + case Variant::OBJECT: + return Callable(p_variant.operator ObjectID(), p_method); + default: + return Callable(memnew(VariantCallable(p_variant, p_method))); + } +} + Callable::Callable(const Object *p_object, const StringName &p_method) { - if (p_method == StringName()) { + if (unlikely(p_method == StringName())) { object = 0; - ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string"); + ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string."); } - if (p_object == nullptr) { + if (unlikely(p_object == nullptr)) { object = 0; - ERR_FAIL_MSG("Object argument to Callable constructor must be non-null"); + ERR_FAIL_MSG("Object argument to Callable constructor must be non-null."); } object = p_object->get_instance_id(); @@ -342,9 +356,9 @@ Callable::Callable(const Object *p_object, const StringName &p_method) { } Callable::Callable(ObjectID p_object, const StringName &p_method) { - if (p_method == StringName()) { + if (unlikely(p_method == StringName())) { object = 0; - ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string"); + ERR_FAIL_MSG("Method argument to Callable constructor must be a non-empty string."); } object = p_object; @@ -352,9 +366,9 @@ Callable::Callable(ObjectID p_object, const StringName &p_method) { } Callable::Callable(CallableCustom *p_custom) { - if (p_custom->referenced) { + if (unlikely(p_custom->referenced)) { object = 0; - ERR_FAIL_MSG("Callable custom is already referenced"); + ERR_FAIL_MSG("Callable custom is already referenced."); } p_custom->referenced = true; object = 0; //ensure object is all zero, since pointer may be 32 bits diff --git a/core/variant/callable.h b/core/variant/callable.h index 38872b71ef..bba69d453e 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -125,6 +125,8 @@ public: operator String() const; + static Callable create(const Variant &p_variant, const StringName &p_method); + Callable(const Object *p_object, const StringName &p_method); Callable(ObjectID p_object, const StringName &p_method); Callable(CallableCustom *p_custom); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index b551a7059e..543ee1135f 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -2033,11 +2033,13 @@ static void _register_variant_builtin_methods() { bind_method(NodePath, get_subname, sarray("idx"), varray()); bind_method(NodePath, get_concatenated_names, sarray(), varray()); bind_method(NodePath, get_concatenated_subnames, sarray(), varray()); + bind_method(NodePath, slice, sarray("begin", "end"), varray(INT_MAX)); bind_method(NodePath, get_as_property_path, sarray(), varray()); bind_method(NodePath, is_empty, sarray(), varray()); /* Callable */ + bind_static_method(Callable, create, sarray("variant", "method"), varray()); bind_method(Callable, callv, sarray("arguments"), varray()); bind_method(Callable, is_null, sarray(), varray()); bind_method(Callable, is_custom, sarray(), varray()); diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 171074188f..79bed9be33 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -810,7 +810,7 @@ struct VariantInternalAccessor<bool> { #define VARIANT_ACCESSOR_NUMBER(m_type) \ template <> \ struct VariantInternalAccessor<m_type> { \ - static _FORCE_INLINE_ m_type get(const Variant *v) { return (m_type)*VariantInternal::get_int(v); } \ + static _FORCE_INLINE_ m_type get(const Variant *v) { return (m_type) * VariantInternal::get_int(v); } \ static _FORCE_INLINE_ void set(Variant *v, m_type p_value) { *VariantInternal::get_int(v) = p_value; } \ }; diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 50c9c10987..20941b944f 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -433,9 +433,9 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { } \ m_assign_type num; \ if (value->get_type() == Variant::INT) { \ - num = (m_assign_type)*VariantGetInternalPtr<int64_t>::get_ptr(value); \ + num = (m_assign_type) * VariantGetInternalPtr<int64_t>::get_ptr(value); \ } else if (value->get_type() == Variant::FLOAT) { \ - num = (m_assign_type)*VariantGetInternalPtr<double>::get_ptr(value); \ + num = (m_assign_type) * VariantGetInternalPtr<double>::get_ptr(value); \ } else { \ *oob = false; \ *valid = false; \ @@ -495,9 +495,9 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const { } \ m_assign_type num; \ if (value->get_type() == Variant::INT) { \ - num = (m_assign_type)*VariantGetInternalPtr<int64_t>::get_ptr(value); \ + num = (m_assign_type) * VariantGetInternalPtr<int64_t>::get_ptr(value); \ } else if (value->get_type() == Variant::FLOAT) { \ - num = (m_assign_type)*VariantGetInternalPtr<double>::get_ptr(value); \ + num = (m_assign_type) * VariantGetInternalPtr<double>::get_ptr(value); \ } else { \ *oob = false; \ *valid = false; \ diff --git a/core/version.h b/core/version.h index abb81312ac..18a97cadf0 100644 --- a/core/version.h +++ b/core/version.h @@ -33,6 +33,8 @@ #include "core/version_generated.gen.h" +#include <stdint.h> + // Copied from typedefs.h to stay lean. #ifndef _STR #define _STR(m_x) #m_x @@ -77,4 +79,8 @@ // Git commit hash, generated at build time in `core/version_hash.gen.cpp`. extern const char *const VERSION_HASH; +// Git commit date UNIX timestamp (in seconds), generated at build time in `core/version_hash.gen.cpp`. +// Set to 0 if unknown. +extern const uint64_t VERSION_TIMESTAMP; + #endif // VERSION_H |