From 6426f2e9c79e5dd653458f3cb07da80c09ec1fe4 Mon Sep 17 00:00:00 2001 From: SnailRhymer Date: Sun, 17 Jul 2022 17:38:51 +0100 Subject: [PATCH 01/48] Change code folding behavior to include terminal indented comments Previously, when folding a block of code that finished with an indented comment (i.e. one indented as much as or more than the starting indent of the code), that comment would be left out of the fold. Change the behavior to include such comments, but still leave less-indented ones out. (cherry picked from commit efed5087ae75a13e58cc06da5323f6f6448819a4) --- scene/gui/text_edit.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 5d092e6c0dfa..3477e69b61c4 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -6341,7 +6341,8 @@ void TextEdit::fold_line(int p_line) { int last_line = start_indent; for (int i = p_line + 1; i < text.size(); i++) { if (text[i].strip_edges().size() != 0) { - if (is_line_comment(i)) { + if (is_line_comment(i) && get_indent_level(i) <= start_indent) { + // Checked indent to make sure indented comments that finish a code block are folded. continue; } else if (get_indent_level(i) > start_indent) { last_line = i; From 81fa7abb4038ae72988bc739c2634081b843620e Mon Sep 17 00:00:00 2001 From: David Snopek Date: Fri, 29 Jul 2022 09:30:29 -0500 Subject: [PATCH 02/48] Fix locale resource remapping with binary conversion on export (cherry picked from commit 0cf4ba0d846831dc2cfc5bcbbe85bc4c048ec3d5) --- core/io/resource_loader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 035052272044..9560eb4dec8e 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -724,6 +724,8 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem // We also fall back in case of regional locales as done in TranslationServer::translate // (e.g. 'ru_RU' -> 'ru' if the former has no specific mapping). + // An extra remap may still be necessary afterwards due to the text -> binary converter on export. + String locale = TranslationServer::get_singleton()->get_locale(); ERR_FAIL_COND_V_MSG(locale.length() < 2, p_path, "Could not remap path '" + p_path + "' for translation as configured locale '" + locale + "' is invalid."); String lang = TranslationServer::get_language_code(locale); @@ -763,12 +765,10 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem if (path_remaps.has(new_path)) { new_path = path_remaps[new_path]; - } - - if (new_path == p_path) { // Did not remap. + } else { // Try file remap. Error err; - FileAccess *f = FileAccess::open(p_path + ".remap", FileAccess::READ, &err); + FileAccess *f = FileAccess::open(new_path + ".remap", FileAccess::READ, &err); if (f) { VariantParser::StreamFile stream; From f0d7931de611822161467b9f6fd0239a5ec221da Mon Sep 17 00:00:00 2001 From: Ryan Roden-Corrent Date: Tue, 19 Jul 2022 07:57:43 -0400 Subject: [PATCH 03/48] Don't process input in hidden EditorProperty. This causes EditorProperty nodes to intercept input events even when the Editor Properties dialog is not visible. This means that after closing the dialog, ctrl+shift+c will still copy the last selected property path. Fixes #62866. (cherry picked from commit 26223fe8553c1c623be8b5aaad2ccf31ee5948d3) --- editor/editor_inspector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 4b1eac1f3938..179ac61fccba 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -569,7 +569,7 @@ void EditorProperty::_gui_input(const Ref &p_event) { } void EditorProperty::_unhandled_key_input(const Ref &p_event) { - if (!selected) { + if (!selected || !is_visible_in_tree()) { return; } From e8a9d77e4b444c8262cc6251915ca6abbf81359f Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Tue, 9 Aug 2022 17:07:53 +0800 Subject: [PATCH 04/48] Tree: Don't draw selection background of individual cells in Row mode (cherry picked from commit 4c47c6ab7545f2660d21deb0ec2c9cc57fc3596e) --- scene/gui/tree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 888afd7e46d7..e544dd10d770 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1177,7 +1177,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } p_item->set_meta("__focus_rect", Rect2(r.position, r.size)); - if (p_item->cells[i].selected) { + if (select_mode != SELECT_ROW && p_item->cells[i].selected) { if (has_focus()) { cache.selected_focus->draw(ci, r); } else { From 59061dc619895e8fea41dc1dd096505dc400d8b8 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Fri, 12 Aug 2022 10:15:46 +0800 Subject: [PATCH 05/48] Document `outline` parameter of `Font.draw_char()` (cherry picked from commit 93493843b04ecacd1508d056af8ec3a0abb729d6) --- doc/classes/Font.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml index db7b207cfc4c..939a753421b3 100644 --- a/doc/classes/Font.xml +++ b/doc/classes/Font.xml @@ -35,6 +35,7 @@ Draw character [code]char[/code] into a canvas item using the font at a given position, with [code]modulate[/code] color, and optionally kerning if [code]next[/code] is passed. clipping the width. [code]position[/code] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis. The width used by the character is returned, making this function useful for drawing strings character by character. + If [code]outline[/code] is [code]true[/code], the outline of the character is drawn instead of the character itself. From 7c349574d7c813e9c79685e4109db2fa56502db0 Mon Sep 17 00:00:00 2001 From: kobewi Date: Thu, 11 Aug 2022 18:10:07 +0200 Subject: [PATCH 06/48] Optimize theme usage in editor log (cherry picked from commit c65360eed1842d1f337e094113f472798131b8f7) --- editor/editor_log.cpp | 35 ++++++++++++++++++++--------------- editor/editor_log.h | 10 ++++++++++ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 0e43b15c8fd3..95f73444d1d2 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -58,18 +58,23 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f } void EditorLog::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - //button->set_icon(get_icon("Console","EditorIcons")); - log->add_font_override("normal_font", get_font("output_source", "EditorFonts")); - log->add_color_override("selection_color", get_color("accent_color", "Editor") * Color(1, 1, 1, 0.4)); - } else if (p_what == NOTIFICATION_THEME_CHANGED) { - Ref df_output_code = get_font("output_source", "EditorFonts"); - if (df_output_code.is_valid()) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { if (log != nullptr) { - log->add_font_override("normal_font", get_font("output_source", "EditorFonts")); - log->add_color_override("selection_color", get_color("accent_color", "Editor") * Color(1, 1, 1, 0.4)); + Ref df_output_code = get_font("output_source", "EditorFonts"); + if (df_output_code.is_valid()) { + log->add_font_override("normal_font", get_font("output_source", "EditorFonts")); + log->add_color_override("selection_color", get_color("accent_color", "Editor") * Color(1, 1, 1, 0.4)); + } } - } + + theme_cache.error_color = get_color("error_color", "Editor"); + theme_cache.error_icon = get_icon("Error", "EditorIcons"); + theme_cache.warning_color = get_color("warning_color", "Editor"); + theme_cache.warning_icon = get_icon("Warning", "EditorIcons"); + theme_cache.message_color = get_color("font_color", "Editor") * Color(1, 1, 1, 0.6); + } break; } } @@ -104,22 +109,22 @@ void EditorLog::add_message(const String &p_msg, MessageType p_type) { case MSG_TYPE_STD: { } break; case MSG_TYPE_ERROR: { - log->push_color(get_color("error_color", "Editor")); - Ref icon = get_icon("Error", "EditorIcons"); + log->push_color(theme_cache.error_color); + Ref icon = theme_cache.error_icon; log->add_image(icon); log->add_text(" "); tool_button->set_icon(icon); } break; case MSG_TYPE_WARNING: { - log->push_color(get_color("warning_color", "Editor")); - Ref icon = get_icon("Warning", "EditorIcons"); + log->push_color(theme_cache.warning_color); + Ref icon = theme_cache.warning_icon; log->add_image(icon); log->add_text(" "); tool_button->set_icon(icon); } break; case MSG_TYPE_EDITOR: { // Distinguish editor messages from messages printed by the project - log->push_color(get_color("font_color", "Editor") * Color(1, 1, 1, 0.6)); + log->push_color(theme_cache.message_color); } break; } diff --git a/editor/editor_log.h b/editor/editor_log.h index 1dfe7895fb9b..e0d6910ea842 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -46,6 +46,16 @@ class EditorLog : public VBoxContainer { GDCLASS(EditorLog, VBoxContainer); + struct { + Color error_color; + Ref error_icon; + + Color warning_color; + Ref warning_icon; + + Color message_color; + } theme_cache; + Button *clearbutton; Button *copybutton; Label *title; From a7a8f9c85d8ad7140c96f957a34821db0600c02f Mon Sep 17 00:00:00 2001 From: Fredia Huya-Kouadio Date: Mon, 15 Aug 2022 00:35:21 -0700 Subject: [PATCH 07/48] Fix issue preventing the Android Editor from displaying the project content The issue was causing by a bug within the logic for `FileAccessFilesystemJAndroid#eof_reached()` causing that value to remain false after the eof was reached. This in turn caused an infinite loop in the file scanner preventing the project's content from showing up. (cherry picked from commit 30479543b07d5869eb024663c6588e608bee3c1b) --- .../android/file_access_filesystem_jandroid.cpp | 13 +++++++++++++ platform/android/file_access_filesystem_jandroid.h | 3 +++ .../src/org/godotengine/godot/io/file/DataAccess.kt | 8 ++------ .../godotengine/godot/io/file/FileAccessHandler.kt | 5 +++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp index ec9ce759c5f1..df23ffc46d29 100644 --- a/platform/android/file_access_filesystem_jandroid.cpp +++ b/platform/android/file_access_filesystem_jandroid.cpp @@ -45,6 +45,7 @@ jmethodID FileAccessFilesystemJAndroid::_file_seek_end = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_read = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_tell = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_eof = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_set_eof = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_close = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_write = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_flush = nullptr; @@ -161,6 +162,16 @@ bool FileAccessFilesystemJAndroid::eof_reached() const { } } +void FileAccessFilesystemJAndroid::_set_eof(bool eof) { + if (_file_set_eof) { + ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use."); + + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND(env == nullptr); + env->CallVoidMethod(file_access_handler, _file_set_eof, id, eof); + } +} + uint8_t FileAccessFilesystemJAndroid::get_8() const { ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use."); uint8_t byte; @@ -183,6 +194,7 @@ String FileAccessFilesystemJAndroid::get_line() const { while (true) { size_t line_buffer_size = MIN(buffer_size_limit, file_size - get_position()); if (line_buffer_size <= 0) { + const_cast(this)->_set_eof(true); break; } @@ -309,6 +321,7 @@ void FileAccessFilesystemJAndroid::setup(jobject p_file_access_handler) { _file_get_size = env->GetMethodID(cls, "fileGetSize", "(I)J"); _file_tell = env->GetMethodID(cls, "fileGetPosition", "(I)J"); _file_eof = env->GetMethodID(cls, "isFileEof", "(I)Z"); + _file_set_eof = env->GetMethodID(cls, "setFileEof", "(IZ)V"); _file_seek = env->GetMethodID(cls, "fileSeek", "(IJ)V"); _file_seek_end = env->GetMethodID(cls, "fileSeekFromEnd", "(IJ)V"); _file_read = env->GetMethodID(cls, "fileRead", "(ILjava/nio/ByteBuffer;)I"); diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h index 3bf654a0302f..177df87dc142 100644 --- a/platform/android/file_access_filesystem_jandroid.h +++ b/platform/android/file_access_filesystem_jandroid.h @@ -44,6 +44,7 @@ class FileAccessFilesystemJAndroid : public FileAccess { static jmethodID _file_seek_end; static jmethodID _file_tell; static jmethodID _file_eof; + static jmethodID _file_set_eof; static jmethodID _file_read; static jmethodID _file_write; static jmethodID _file_flush; @@ -55,6 +56,8 @@ class FileAccessFilesystemJAndroid : public FileAccess { String absolute_path; String path_src; + void _set_eof(bool eof); + public: virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file virtual void close() override; ///< close a file diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt index 463dabfb232b..f23537a29e49 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt @@ -104,7 +104,6 @@ internal abstract class DataAccess(private val filePath: String) { protected abstract val fileChannel: FileChannel internal var endOfFile = false - private set fun close() { try { @@ -125,9 +124,7 @@ internal abstract class DataAccess(private val filePath: String) { fun seek(position: Long) { try { fileChannel.position(position) - if (position <= size()) { - endOfFile = false - } + endOfFile = position >= fileChannel.size() } catch (e: Exception) { Log.w(TAG, "Exception when seeking file $filePath.", e) } @@ -161,8 +158,7 @@ internal abstract class DataAccess(private val filePath: String) { fun read(buffer: ByteBuffer): Int { return try { val readBytes = fileChannel.read(buffer) - endOfFile = readBytes == -1 - || (fileChannel.position() >= fileChannel.size() && fileChannel.size() > 0) + endOfFile = readBytes == -1 || (fileChannel.position() >= fileChannel.size()) if (readBytes == -1) { 0 } else { diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt index 04b6772c4508..83da3a24b3b5 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt @@ -194,6 +194,11 @@ class FileAccessHandler(val context: Context) { return files[fileId].endOfFile } + fun setFileEof(fileId: Int, eof: Boolean) { + val file = files[fileId] ?: return + file.endOfFile = eof + } + fun fileClose(fileId: Int) { if (hasFileId(fileId)) { files[fileId].close() From ea8fa93809454d997b3e1bfb1d9615ecc5836dc1 Mon Sep 17 00:00:00 2001 From: Fredia Huya-Kouadio Date: Mon, 15 Aug 2022 02:30:08 -0700 Subject: [PATCH 08/48] Disable threads used to check on plugins to load The functionality is unavailable on Android (requires export capability) and unnecessarily consumes resources (cherry picked from commit 3ac6b6a596dad2f57390a8d7926604e349d2d281) --- platform/android/export/export_plugin.cpp | 10 ++++++---- platform/android/export/export_plugin.h | 2 ++ platform/iphone/export/export.cpp | 8 ++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 9eaad034f8e6..a4e24d124285 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -228,6 +228,7 @@ static const char *AAB_ASSETS_DIRECTORY = "res://android/build/assetPacks/instal static const int DEFAULT_MIN_SDK_VERSION = 19; // Should match the value in 'platform/android/java/app/config.gradle#minSdk' static const int DEFAULT_TARGET_SDK_VERSION = 32; // Should match the value in 'platform/android/java/app/config.gradle#targetSdk' +#ifndef ANDROID_ENABLED void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud; @@ -259,7 +260,6 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { } } -#ifndef ANDROID_ENABLED // Check for devices updates String adb = get_adb_path(); if (FileAccess::exists(adb)) { @@ -373,7 +373,6 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { ea->device_lock.unlock(); } -#endif uint64_t sleep = 300'000; uint64_t wait = 3'000'000; @@ -386,7 +385,6 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { } } -#ifndef ANDROID_ENABLED if (EditorSettings::get_singleton()->get("export/android/shutdown_adb_on_exit")) { String adb = get_adb_path(); if (!FileAccess::exists(adb)) { @@ -397,8 +395,8 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) { args.push_back("kill-server"); OS::get_singleton()->execute(adb, args, true); } -#endif } +#endif String EditorExportPlatformAndroid::get_project_name(const String &p_name) const { String aname; @@ -3438,10 +3436,14 @@ EditorExportPlatformAndroid::EditorExportPlatformAndroid() { devices_changed.set(); plugins_changed.set(); +#ifndef ANDROID_ENABLED check_for_changes_thread.start(_check_for_changes_poll_thread, this); +#endif } EditorExportPlatformAndroid::~EditorExportPlatformAndroid() { +#ifndef ANDROID_ENABLED quit_request.set(); check_for_changes_thread.wait_to_finish(); +#endif } diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index 8898cf695520..22a56db948d5 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -98,10 +98,12 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { Vector devices; SafeFlag devices_changed; Mutex device_lock; +#ifndef ANDROID_ENABLED Thread check_for_changes_thread; SafeFlag quit_request; static void _check_for_changes_poll_thread(void *ud); +#endif String get_project_name(const String &p_name) const; diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index ded574d4d27a..aeb325d07e74 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -57,8 +57,10 @@ class EditorExportPlatformIOS : public EditorExportPlatform { // Plugins SafeFlag plugins_changed; +#ifndef ANDROID_ENABLED Thread check_for_changes_thread; SafeFlag quit_request; +#endif Mutex plugins_lock; Vector plugins; @@ -141,6 +143,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { return true; } +#ifndef ANDROID_ENABLED static void _check_for_changes_poll_thread(void *ud) { EditorExportPlatformIOS *ea = (EditorExportPlatformIOS *)ud; @@ -176,6 +179,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { } } } +#endif protected: virtual void get_preset_features(const Ref &p_preset, List *r_features); @@ -2124,12 +2128,16 @@ EditorExportPlatformIOS::EditorExportPlatformIOS() { plugins_changed.set(); +#ifndef ANDROID_ENABLED check_for_changes_thread.start(_check_for_changes_poll_thread, this); +#endif } EditorExportPlatformIOS::~EditorExportPlatformIOS() { +#ifndef ANDROID_ENABLED quit_request.set(); check_for_changes_thread.wait_to_finish(); +#endif } void register_iphone_exporter() { From cd6764611c2f65b9a6953a38168e014b0286d7f2 Mon Sep 17 00:00:00 2001 From: Olivier Bombardier Date: Thu, 18 Aug 2022 01:33:15 -0400 Subject: [PATCH 09/48] Fix has_filter of AnimationNode not being called in scripts (cherry picked from commit c988deb3b126b4e4d1ff61949f419fd31cea651d) --- doc/classes/AnimationNode.xml | 2 +- scene/animation/animation_tree.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index d0c4dc0b9ca7..96776325d5f9 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -107,7 +107,7 @@ - + Returns [code]true[/code] whether you want the blend tree editor to display filter editing on this node. diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index d2f4cd37f243..f371824c0292 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -357,6 +357,9 @@ bool AnimationNode::is_path_filtered(const NodePath &p_path) const { } bool AnimationNode::has_filter() const { + if (get_script_instance()) { + return get_script_instance()->call("has_filter"); + } return false; } @@ -427,7 +430,7 @@ void AnimationNode::_bind_methods() { } BIND_VMETHOD(MethodInfo("process", PropertyInfo(Variant::REAL, "time"), PropertyInfo(Variant::BOOL, "seek"))); BIND_VMETHOD(MethodInfo(Variant::STRING, "get_caption")); - BIND_VMETHOD(MethodInfo(Variant::STRING, "has_filter")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_filter")); ADD_SIGNAL(MethodInfo("removed_from_graph")); From 465a6569e43d5dd13be47db1a039ff3664d42c0f Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Mon, 15 Aug 2022 18:51:50 +0200 Subject: [PATCH 10/48] C#: Use custom project setting for C# project files name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The setting is initially assigned the name of the Godot project, but it's kept freezed to prevent issues when renaming the Godot project. The user can always rename the C# project and solution manually and change the setting to the new name. Co-authored-by: Ignacio Roldán Etcheverry (cherry picked from commit 31d09a807efc973222016a47f832f590c51949ef) --- modules/mono/csharp_script.cpp | 17 +++++++---- .../GodotTools/Export/AotBuilder.cs | 2 +- .../GodotTools/Export/ExportPlugin.cs | 2 +- .../GodotTools/GodotTools/GodotSharpEditor.cs | 19 +++--------- .../GodotTools/Internals/GodotSharpDirs.cs | 4 +++ modules/mono/editor/editor_internal_calls.cpp | 9 ++++++ modules/mono/godotsharp_dirs.cpp | 30 +++++++++++++++++-- modules/mono/godotsharp_dirs.h | 1 + modules/mono/mono_gd/gd_mono.cpp | 12 ++++---- 9 files changed, 65 insertions(+), 31 deletions(-) diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index c492a8c24a37..44e6733024f5 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -722,19 +722,24 @@ bool CSharpLanguage::is_assembly_reloading_needed() { GDMonoAssembly *proj_assembly = gdmono->get_project_assembly(); String appname = ProjectSettings::get_singleton()->get("application/config/name"); - String appname_safe = OS::get_singleton()->get_safe_dir_name(appname); - if (appname_safe.empty()) { - appname_safe = "UnnamedProject"; + String assembly_name = ProjectSettings::get_singleton()->get_setting("mono/project/assembly_name"); + + if (assembly_name.empty()) { + String appname_safe = OS::get_singleton()->get_safe_dir_name(appname); + if (appname_safe.empty()) { + appname_safe = "UnnamedProject"; + } + assembly_name = appname_safe; } - appname_safe += ".dll"; + assembly_name += ".dll"; if (proj_assembly) { String proj_asm_path = proj_assembly->get_path(); if (!FileAccess::exists(proj_asm_path)) { // Maybe it wasn't loaded from the default path, so check this as well - proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(appname_safe); + proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(assembly_name); if (!FileAccess::exists(proj_asm_path)) return false; // No assembly to load } @@ -742,7 +747,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() { if (FileAccess::get_modified_time(proj_asm_path) <= proj_assembly->get_modified_time()) return false; // Already up to date } else { - if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(appname_safe))) + if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(assembly_name))) return false; // No assembly to load } diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs index e7af27fa3d40..20927893fc24 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs @@ -231,7 +231,7 @@ string CompileForArch(string arch) RunLipo(new[] {CompileForArch("arm64"), CompileForArch("x86_64")}, libFilePath); } - string projectAssemblyName = GodotSharpEditor.ProjectAssemblyName; + string projectAssemblyName = GodotSharpDirs.ProjectAssemblyName; string libAotName = $"lib-aot-{projectAssemblyName}"; string libAotXcFrameworkPath = Path.Combine(aotTempDir, $"{libAotName}.xcframework"); diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index a8ec8a75760d..ba56c7312a46 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -167,7 +167,7 @@ private void _ExportBeginImpl(string[] features, bool isDebug, string path, int var assemblies = new Godot.Collections.Dictionary(); - string projectDllName = GodotSharpEditor.ProjectAssemblyName; + string projectDllName = GodotSharpDirs.ProjectAssemblyName; string projectDllSrcDir = Path.Combine(GodotSharpDirs.ResTempAssembliesBaseDir, buildConfig); string projectDllSrcPath = Path.Combine(projectDllSrcDir, $"{projectDllName}.dll"); diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 852855c3bb0e..0df2785ce2a7 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -39,18 +39,6 @@ public class GodotSharpEditor : EditorPlugin, ISerializationListener public bool SkipBuildBeforePlaying { get; set; } = false; - public static string ProjectAssemblyName - { - get - { - string projectAssemblyName = (string)ProjectSettings.GetSetting("application/config/name"); - projectAssemblyName = projectAssemblyName.ToSafeDirName(); - if (string.IsNullOrEmpty(projectAssemblyName)) - projectAssemblyName = "UnnamedProject"; - return projectAssemblyName; - } - } - private bool CreateProjectSolution() { using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 3)) @@ -60,7 +48,7 @@ private bool CreateProjectSolution() string resourceDir = ProjectSettings.GlobalizePath("res://"); string path = resourceDir; - string name = ProjectAssemblyName; + string name = GodotSharpDirs.ProjectAssemblyName; string guid = CsProjOperations.GenerateGameProject(path, name); @@ -375,7 +363,8 @@ public Error OpenInExternalEditor(Script script, int line, int col) [UsedImplicitly] public bool OverridesExternalEditor() { - return (ExternalEditorId)_editorSettings.GetSetting("mono/editor/external_editor") != ExternalEditorId.None; + return (ExternalEditorId)_editorSettings.GetSetting("mono/editor/external_editor") != + ExternalEditorId.None; } public override bool Build() @@ -396,7 +385,7 @@ private void ApplyNecessaryChangesToSolution() // NOTE: The order in which changes are made to the project is important // Migrate to MSBuild project Sdks style if using the old style - ProjectUtils.MigrateToProjectSdksStyle(msbuildProject, ProjectAssemblyName); + ProjectUtils.MigrateToProjectSdksStyle(msbuildProject, GodotSharpDirs.ProjectAssemblyName); ProjectUtils.EnsureGodotSdkIsUpToDate(msbuildProject); diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs index 5e70c399b28a..0356bb12a779 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs @@ -20,6 +20,7 @@ public static class GodotSharpDirs public static string MonoSolutionsDir => internal_MonoSolutionsDir(); public static string BuildLogsDirs => internal_BuildLogsDirs(); + public static string ProjectAssemblyName => internal_ProjectAssemblyName(); public static string ProjectSlnPath => internal_ProjectSlnPath(); public static string ProjectCsProjPath => internal_ProjectCsProjPath(); @@ -74,6 +75,9 @@ public static class GodotSharpDirs [MethodImpl(MethodImplOptions.InternalCall)] private static extern string internal_BuildLogsDirs(); + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern string internal_ProjectAssemblyName(); + [MethodImpl(MethodImplOptions.InternalCall)] private static extern string internal_ProjectSlnPath(); diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index fac1a0aa1631..d10c60982690 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/modules/mono/editor/editor_internal_calls.cpp @@ -107,6 +107,14 @@ MonoString *godot_icall_GodotSharpDirs_BuildLogsDirs() { #endif } +MonoString *godot_icall_GodotSharpDirs_ProjectAssemblyName() { +#ifdef TOOLS_ENABLED + return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_project_assembly_name()); +#else + return NULL; +#endif +} + MonoString *godot_icall_GodotSharpDirs_ProjectSlnPath() { #ifdef TOOLS_ENABLED return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_project_sln_path()); @@ -388,6 +396,7 @@ void register_editor_internal_calls() { GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoLogsDir", godot_icall_GodotSharpDirs_MonoLogsDir); GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoSolutionsDir", godot_icall_GodotSharpDirs_MonoSolutionsDir); GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", godot_icall_GodotSharpDirs_BuildLogsDirs); + GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectAssemblyName", godot_icall_GodotSharpDirs_ProjectAssemblyName); GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", godot_icall_GodotSharpDirs_ProjectSlnPath); GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", godot_icall_GodotSharpDirs_ProjectCsProjPath); GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", godot_icall_GodotSharpDirs_DataEditorToolsDir); diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index d8363a3368d4..a6edbdc516e0 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -102,6 +102,7 @@ class _GodotSharpDirs { String mono_solutions_dir; String build_logs_dir; + String project_assembly_name; String sln_filepath; String csproj_filepath; @@ -144,16 +145,35 @@ class _GodotSharpDirs { mono_solutions_dir = mono_user_dir.plus_file("solutions"); build_logs_dir = mono_user_dir.plus_file("build_logs"); + GLOBAL_DEF("mono/project/assembly_name", ""); + GLOBAL_DEF("mono/project/solution_directory", ""); + GLOBAL_DEF("mono/project/c#_project_directory", ""); + String appname = ProjectSettings::get_singleton()->get("application/config/name"); String appname_safe = OS::get_singleton()->get_safe_dir_name(appname); if (appname_safe.empty()) { appname_safe = "UnnamedProject"; } - String base_path = ProjectSettings::get_singleton()->globalize_path("res://"); + project_assembly_name = ProjectSettings::get_singleton()->get("mono/project/assembly_name"); + if (project_assembly_name.empty()) { + project_assembly_name = appname_safe; + ProjectSettings::get_singleton()->set("mono/project/assembly_name", project_assembly_name); + } - sln_filepath = base_path.plus_file(appname_safe + ".sln"); - csproj_filepath = base_path.plus_file(appname_safe + ".csproj"); + String sln_parent_dir = ProjectSettings::get_singleton()->get("mono/project/solution_directory"); + if (sln_parent_dir.empty()) { + sln_parent_dir = "res://"; + } + + String csproj_parent_dir = ProjectSettings::get_singleton()->get("mono/project/c#_project_directory"); + if (csproj_parent_dir.empty()) { + csproj_parent_dir = "res://"; + } + + sln_filepath = ProjectSettings::get_singleton()->globalize_path(sln_parent_dir).plus_file(project_assembly_name + ".sln"); + + csproj_filepath = ProjectSettings::get_singleton()->globalize_path(csproj_parent_dir).plus_file(project_assembly_name + ".csproj"); #endif String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir(); @@ -288,6 +308,10 @@ String get_build_logs_dir() { return _GodotSharpDirs::get_singleton().build_logs_dir; } +String get_project_assembly_name() { + return _GodotSharpDirs::get_singleton().project_assembly_name; +} + String get_project_sln_path() { return _GodotSharpDirs::get_singleton().sln_filepath; } diff --git a/modules/mono/godotsharp_dirs.h b/modules/mono/godotsharp_dirs.h index b48176cc6d5f..6ca0aff5b400 100644 --- a/modules/mono/godotsharp_dirs.h +++ b/modules/mono/godotsharp_dirs.h @@ -51,6 +51,7 @@ String get_mono_logs_dir(); String get_mono_solutions_dir(); String get_build_logs_dir(); +String get_project_assembly_name(); String get_project_sln_path(); String get_project_csproj_path(); diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 3860c53b249d..40051110c43f 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -987,13 +987,15 @@ bool GDMono::_load_project_assembly() { if (project_assembly) return true; - String appname = ProjectSettings::get_singleton()->get("application/config/name"); - String appname_safe = OS::get_singleton()->get_safe_dir_name(appname); - if (appname_safe.empty()) { - appname_safe = "UnnamedProject"; + String assembly_name = ProjectSettings::get_singleton()->get("mono/project/assembly_name"); + + if (assembly_name.empty()) { + String appname = ProjectSettings::get_singleton()->get("application/config/name"); + String appname_safe = OS::get_singleton()->get_safe_dir_name(appname); + assembly_name = appname_safe; } - bool success = load_assembly(appname_safe, &project_assembly); + bool success = load_assembly(assembly_name, &project_assembly); if (success) { mono_assembly_set_main(project_assembly->get_assembly()); From 2678fd8202be2bee41fa28a641df8ca3edefc2ed Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Mon, 22 Aug 2022 20:39:18 +0300 Subject: [PATCH 11/48] Fix color modulation of the grayscale glyphs in font with mixed color / grayscale data. (cherry picked from commit 4d0c0f3ffac92a7239d321001650367730ef8667) --- scene/resources/dynamic_font.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index 2fd1f3bfcb3e..e29c834e4824 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -523,7 +523,7 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT cpos.y -= font->get_ascent(); cpos.y += ch->v_align; Color modulate = p_modulate; - if (FT_HAS_COLOR(font->face)) { + if (font->textures[ch->texture_idx].texture->get_format() == Image::FORMAT_RGBA8) { modulate.r = modulate.g = modulate.b = 1.0; } RID texture = font->textures[ch->texture_idx].texture->get_rid(); From e237bdf37c785b08af88e843d83c14d9e987d069 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Mon, 22 Aug 2022 18:40:40 +0200 Subject: [PATCH 12/48] Improve documentation related to anisotropic filtering (cherry picked from commit d2ef3bf8a6bfd01dc327fc0fb7ef631fc7457a8d) --- doc/classes/ProjectSettings.xml | 4 +++- doc/classes/SpatialMaterial.xml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 2a978c5a48a7..16d19c1da3d8 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1660,7 +1660,9 @@ [b]Note:[/b] The two video drivers are not drop-in replacements for each other, so a game designed for GLES3 might not work properly when falling back to GLES2. In particular, some features of the GLES3 backend are not available in GLES2. Enabling this setting also means that both ETC and ETC2 VRAM-compressed textures will be exported on Android and iOS, increasing the data pack's size. - Maximum anisotropic filter level used for textures with anisotropy enabled. Higher values will result in sharper textures when viewed from oblique angles, at the cost of performance. Only power-of-two values are valid (2, 4, 8, 16). + Maximum anisotropic filter level used for textures with anisotropy enabled. Higher values will result in sharper textures when viewed from oblique angles, at the cost of performance. With the exception of [code]1[/code], only power-of-two values are valid ([code]2[/code], [code]4[/code], [code]8[/code], [code]16[/code]). A value of [code]1[/code] forcibly disables anisotropic filtering, even on textures where it is enabled. + [b]Note:[/b] For performance reasons, anisotropic filtering [i]is not enabled by default[/i] on textures. For this setting to have an effect, anisotropic texture filtering can be enabled by selecting a texture in the FileSystem dock, going to the Import dock, checking the [b]Anisotropic[/b] checkbox then clicking [b]Reimport[/b]. However, anisotropic filtering is rarely useful in 2D, so only enable it for textures in 2D if it makes a meaningful visual difference. + [b]Note:[/b] This property is only read when the project starts. There is currently no way to change this setting at run-time. Sets the number of MSAA samples to use. MSAA is used to reduce aliasing around the edges of polygons. A higher MSAA value results in smoother edges but can be significantly slower on some hardware. diff --git a/doc/classes/SpatialMaterial.xml b/doc/classes/SpatialMaterial.xml index 5fd1c381f71f..182e53224aad 100644 --- a/doc/classes/SpatialMaterial.xml +++ b/doc/classes/SpatialMaterial.xml @@ -69,7 +69,7 @@ If [code]true[/code], anisotropy is enabled. Anisotropy changes the shape of the specular blob and aligns it to tangent space. This is useful for brushed aluminium and hair reflections. [b]Note:[/b] Mesh tangents are needed for anisotropy to work. If the mesh does not contain tangents, the anisotropy effect will appear broken. - [b]Note:[/b] Material anisotropy should not to be confused with anisotropic texture filtering. Anisotropic texture filtering can be enabled by selecting a texture in the FileSystem dock, going to the Import dock, checking the [b]Anisotropic[/b] checkbox then clicking [b]Reimport[/b]. + [b]Note:[/b] Material anisotropy should not to be confused with anisotropic texture filtering. Anisotropic texture filtering can be enabled by selecting a texture in the FileSystem dock, going to the Import dock, checking the [b]Anisotropic[/b] checkbox then clicking [b]Reimport[/b]. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/quality/filters/anisotropic_filter_level]. Texture that offsets the tangent map for anisotropy calculations and optionally controls the anisotropy effect (if an alpha channel is present). The flowmap texture is expected to be a derivative map, with the red channel representing distortion on the X axis and green channel representing distortion on the Y axis. Values below 0.5 will result in negative distortion, whereas values above 0.5 will result in positive distortion. From f96f8ddfc7268f3e0d2ef0ed6ae84e1a6af8dcb0 Mon Sep 17 00:00:00 2001 From: Fredia Huya-Kouadio Date: Sun, 14 Aug 2022 19:26:06 -0700 Subject: [PATCH 13/48] Fix issue with `get_current_dir()` returning the wrong path on Android (cherry picked from commit b5e1096c61b8976f193328628b6099ff2830e9c4) --- platform/android/dir_access_jandroid.cpp | 14 ++++++++++++++ platform/android/dir_access_jandroid.h | 1 + 2 files changed, 15 insertions(+) diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 2f5fc5f1aecf..94841d51788b 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -134,6 +134,20 @@ String DirAccessJAndroid::get_drive(int p_drive) { } } +String DirAccessJAndroid::get_current_dir() { + String base = _get_root_path(); + String bd = current_dir; + if (base != "") { + bd = current_dir.replace_first(base, ""); + } + + if (bd.begins_with("/")) { + return _get_root_string() + bd.substr(1, bd.length()); + } else { + return _get_root_string() + bd; + } +} + Error DirAccessJAndroid::change_dir(String p_dir) { String new_dir = get_absolute_path(p_dir); if (new_dir == current_dir) { diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h index 539fa4d7945b..5cde19d3d8d2 100644 --- a/platform/android/dir_access_jandroid.h +++ b/platform/android/dir_access_jandroid.h @@ -69,6 +69,7 @@ class DirAccessJAndroid : public DirAccessUnix { virtual String get_drive(int p_drive) override; virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success + virtual String get_current_dir() override; ///< return current dir location virtual bool file_exists(String p_file) override; virtual bool dir_exists(String p_dir) override; From 07af8a971aa53c50c67e87cbc67fa96e3024cad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 23 Aug 2022 16:57:31 +0200 Subject: [PATCH 14/48] nanosvg: Sync with upstream bd16c4e (cherry picked from commit 052257e9b7dd3473a4456e4e775b008d7456202f) --- thirdparty/README.md | 2 +- thirdparty/nanosvg/nanosvg.h | 67 ++++++++++++++++++++++++++------ thirdparty/nanosvg/nanosvgrast.h | 8 ++-- 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/thirdparty/README.md b/thirdparty/README.md index fe3e25528093..ea86b8bb6dc9 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -399,7 +399,7 @@ Collection of single-file libraries used in Godot components. ## nanosvg - Upstream: https://github.com/memononen/nanosvg -- Version: git (4c8f0139b62c6e7faa3b67ce1fbe6e63590ed148, 2022) +- Version: git (bd16c4e6b2842e1f0286dc374d21f85c659862e5, 2022) - License: zlib Files extracted from the upstream source: diff --git a/thirdparty/nanosvg/nanosvg.h b/thirdparty/nanosvg/nanosvg.h index 0c5861616095..bd90d05a737c 100644 --- a/thirdparty/nanosvg/nanosvg.h +++ b/thirdparty/nanosvg/nanosvg.h @@ -181,8 +181,6 @@ void nsvgDelete(NSVGimage* image); #endif #endif -#endif // NANOSVG_H - #ifdef NANOSVG_IMPLEMENTATION #include @@ -1224,15 +1222,58 @@ static unsigned int nsvg__parseColorHex(const char* str) return NSVG_RGB(128, 128, 128); } +// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters). +// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors +// for backwards compatibility. Note: other image viewers return black instead. + static unsigned int nsvg__parseColorRGB(const char* str) { - unsigned int r=0, g=0, b=0; - float rf=0, gf=0, bf=0; - if (sscanf(str, "rgb(%u, %u, %u)", &r, &g, &b) == 3) // decimal integers - return NSVG_RGB(r, g, b); - if (sscanf(str, "rgb(%f%%, %f%%, %f%%)", &rf, &gf, &bf) == 3) // decimal integer percentage - return NSVG_RGB(roundf(rf*2.55f), roundf(gf*2.55f), roundf(bf*2.55f)); // (255 / 100.0f) - return NSVG_RGB(128, 128, 128); + int i; + unsigned int rgbi[3]; + float rgbf[3]; + // try decimal integers first + if (sscanf(str, "rgb(%u, %u, %u)", &rgbi[0], &rgbi[1], &rgbi[2]) != 3) { + // integers failed, try percent values (float, locale independent) + const char delimiter[3] = {',', ',', ')'}; + str += 4; // skip "rgb(" + for (i = 0; i < 3; i++) { + while (*str && (nsvg__isspace(*str))) str++; // skip leading spaces + if (*str == '+') str++; // skip '+' (don't allow '-') + if (!*str) break; + rgbf[i] = nsvg__atof(str); + + // Note 1: it would be great if nsvg__atof() returned how many + // bytes it consumed but it doesn't. We need to skip the number, + // the '%' character, spaces, and the delimiter ',' or ')'. + + // Note 2: The following code does not allow values like "33.%", + // i.e. a decimal point w/o fractional part, but this is consistent + // with other image viewers, e.g. firefox, chrome, eog, gimp. + + while (*str && nsvg__isdigit(*str)) str++; // skip integer part + if (*str == '.') { + str++; + if (!nsvg__isdigit(*str)) break; // error: no digit after '.' + while (*str && nsvg__isdigit(*str)) str++; // skip fractional part + } + if (*str == '%') str++; else break; + while (nsvg__isspace(*str)) str++; + if (*str == delimiter[i]) str++; + else break; + } + if (i == 3) { + rgbi[0] = roundf(rgbf[0] * 2.55f); + rgbi[1] = roundf(rgbf[1] * 2.55f); + rgbi[2] = roundf(rgbf[2] * 2.55f); + } else { + rgbi[0] = rgbi[1] = rgbi[2] = 128; + } + } + // clip values as the CSS spec requires + for (i = 0; i < 3; i++) { + if (rgbi[i] > 255) rgbi[i] = 255; + } + return NSVG_RGB(rgbi[0], rgbi[1], rgbi[2]); } typedef struct NSVGNamedColor { @@ -1640,9 +1681,9 @@ static void nsvg__parseUrl(char* id, const char* str) { int i = 0; str += 4; // "url("; - if (*str == '#') + if (*str && *str == '#') str++; - while (i < 63 && *str != ')') { + while (i < 63 && *str && *str != ')') { id[i] = *str++; i++; } @@ -3007,4 +3048,6 @@ void nsvgDelete(NSVGimage* image) free(image); } -#endif +#endif // NANOSVG_IMPLEMENTATION + +#endif // NANOSVG_H diff --git a/thirdparty/nanosvg/nanosvgrast.h b/thirdparty/nanosvg/nanosvgrast.h index 029043e6eb39..ffa913a89475 100644 --- a/thirdparty/nanosvg/nanosvgrast.h +++ b/thirdparty/nanosvg/nanosvgrast.h @@ -25,6 +25,8 @@ #ifndef NANOSVGRAST_H #define NANOSVGRAST_H +#include "nanosvg.h" + #ifndef NANOSVGRAST_CPLUSPLUS #ifdef __cplusplus extern "C" { @@ -72,8 +74,6 @@ void nsvgDeleteRasterizer(NSVGrasterizer*); #endif #endif -#endif // NANOSVGRAST_H - #ifdef NANOSVGRAST_IMPLEMENTATION #include @@ -1453,4 +1453,6 @@ void nsvgRasterize(NSVGrasterizer* r, r->stride = 0; } -#endif +#endif // NANOSVGRAST_IMPLEMENTATION + +#endif // NANOSVGRAST_H From f93f583c42cb3bc794ce92332dc0464877234aec Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Mon, 8 Aug 2022 23:06:54 +0200 Subject: [PATCH 15/48] Improve InstancePlaceholder documentation (cherry picked from commit 5acf30b5380d71472657fbba84cad8739a5d7c1e) --- doc/classes/InstancePlaceholder.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/classes/InstancePlaceholder.xml b/doc/classes/InstancePlaceholder.xml index 990de441e463..bff716f1d66e 100644 --- a/doc/classes/InstancePlaceholder.xml +++ b/doc/classes/InstancePlaceholder.xml @@ -15,7 +15,8 @@ - Not thread-safe. Use [method Object.call_deferred] if calling from a thread. + Call this method to actually load in the node. The created node will be placed as a sibling [i]above[/i] the [InstancePlaceholder] in the scene tree. The [Node]'s reference is also returned for convenience. + [b]Note:[/b] [method create_instance] is not thread-safe. Use [method Object.call_deferred] if calling from a thread. @@ -28,6 +29,8 @@ + Returns the list of properties that will be applied to the node when [method create_instance] is called. + If [code]with_order[/code] is [code]true[/code], a key named [code].order[/code] (note the leading period) is added to the dictionary. This [code].order[/code] key is an [Array] of [String] property names specifying the order in which properties will be applied (with index 0 being the first). From 98074e1861d03942d71637b9b8f413562138b370 Mon Sep 17 00:00:00 2001 From: Marlin Watts-Woods Date: Mon, 8 Aug 2022 21:08:26 -0700 Subject: [PATCH 16/48] Added to Sprite3D Documentation (cherry picked from commit f8f665b03e2c2b2a10ffcaf815c511cd31a70887) --- doc/classes/Sprite3D.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml index 1973e7bc3fa1..70107a7f59e0 100644 --- a/doc/classes/Sprite3D.xml +++ b/doc/classes/Sprite3D.xml @@ -27,7 +27,7 @@ The region of the atlas texture to display. [member region_enabled] must be [code]true[/code]. - [Texture] object to draw. If [member GeometryInstance.material_override] is used, this will be overridden. + [Texture] object to draw. If [member GeometryInstance.material_override] is used, this will be overridden. The size information is still used. The number of rows in the sprite sheet. From 9a037a072781483d4946dc8f70e04a6a80e13ce3 Mon Sep 17 00:00:00 2001 From: Dan Boorstein Date: Tue, 9 Aug 2022 16:31:12 -0800 Subject: [PATCH 17/48] Add note about using AudioListener2D There was no mention of the effect of AudioListener2D in this documentation, making it unclear if there was a relationship. The new text is copied and modified from the AudioStreamPlayer3D documentation. Use 'an' as article before 'AudioListener3D' (cherry picked from commit a7ebc6fb18bcbcf817895955eed619588b3cd8b8) --- doc/classes/AudioStreamPlayer2D.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml index dc72500b0e4a..1eb98ac391cf 100644 --- a/doc/classes/AudioStreamPlayer2D.xml +++ b/doc/classes/AudioStreamPlayer2D.xml @@ -4,7 +4,8 @@ Plays positional sound in 2D space. - Plays audio that dampens with distance from screen center. + Plays audio that dampens with distance from a given position. + By default, audio is heard from the screen center. This can be changed by adding a [Listener2D] node to the scene and enabling it by calling [method Listener2D.make_current] on it. See also [AudioStreamPlayer] to play a sound non-positionally. [b]Note:[/b] Hiding an [AudioStreamPlayer2D] node does not disable its audio output. To temporarily disable an [AudioStreamPlayer2D]'s audio output, set [member volume_db] to a very low value like [code]-100[/code] (which isn't audible to human hearing). From 62c6fe77b63b559ba63bfcefb98addb938d27b27 Mon Sep 17 00:00:00 2001 From: Michael Alexsander Date: Tue, 9 Aug 2022 19:04:40 -0300 Subject: [PATCH 18/48] Fix error when switching to another `GridMap` with an item with higher index selected (cherry picked from commit fe16aecbacaef37b8a56de34c9cb5a69f7a26644) --- modules/gridmap/grid_map_editor_plugin.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 77818d737d4b..20bcefbe5739 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -904,10 +904,12 @@ void GridMapEditor::update_palette() { } if (selected != -1 && mesh_library_palette->get_item_count() > 0) { - mesh_library_palette->select(selected); + // Make sure that this variable is set correctly. + selected_palette = MIN(selected, mesh_library_palette->get_item_count() - 1); + mesh_library_palette->select(selected_palette); } - last_mesh_library = mesh_library.operator->(); + last_mesh_library = *mesh_library; } void GridMapEditor::edit(GridMap *p_gridmap) { From fc01ed9dbb07ee5417ab1c5a627e81422af3b11f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Wed, 10 Aug 2022 21:42:49 +0200 Subject: [PATCH 19/48] Clean iOS platform config of long gone macro (cherry picked from commit 8c2a577350924d1f4a8e0a98ebf85bea96ea7e63) --- platform/iphone/platform_config.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h index a1b598fe2aba..0f3acb258f5b 100644 --- a/platform/iphone/platform_config.h +++ b/platform/iphone/platform_config.h @@ -33,8 +33,6 @@ #define GLES2_INCLUDE_H #define GLES3_INCLUDE_H -#define PLATFORM_REFCOUNT - #define PTHREAD_RENAME_SELF #define _weakify(var) __weak typeof(var) GDWeak_##var = var; From cbe542f96a5cd0356c8bb22a93d405cc4bd4dce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Fri, 12 Aug 2022 08:01:56 +0200 Subject: [PATCH 20/48] Fix jumbled error output when using Windows spawn fix (cherry picked from commit 4a3cb1447351c2e915f2beb8c34780d2c6fe3e43) --- methods.py | 1 + 1 file changed, 1 insertion(+) diff --git a/methods.py b/methods.py index efcfdbe15a09..91135a1b9100 100644 --- a/methods.py +++ b/methods.py @@ -333,6 +333,7 @@ def mySubProcess(cmdline, env): startupinfo=startupinfo, shell=False, env=env, + text=True, ) _, err = proc.communicate() rv = proc.wait() From 503fddc0fe1b3f8af7bcefea58800d840824f15c Mon Sep 17 00:00:00 2001 From: kobewi Date: Wed, 17 Aug 2022 02:28:13 +0200 Subject: [PATCH 21/48] Mention the stretching behavior of PopupPanel (cherry picked from commit a2b088b1c1b79950212287fd4c8539a67cfcb56f) --- doc/classes/PopupPanel.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/classes/PopupPanel.xml b/doc/classes/PopupPanel.xml index 9aad81fb07bd..df2ce6e9d309 100644 --- a/doc/classes/PopupPanel.xml +++ b/doc/classes/PopupPanel.xml @@ -5,6 +5,7 @@ Class for displaying popups with a panel background. In some cases it might be simpler to use than [Popup], since it provides a configurable background. If you are making windows, better check [WindowDialog]. + If any [Control] node is added as a child of this [PopupPanel], it will be stretched to fit the panel's size (similar to how [PanelContainer] works). From 179a16a67cfeed360f9205477b7732ebffc3af9a Mon Sep 17 00:00:00 2001 From: Micky Date: Sat, 13 Aug 2022 00:30:40 +0200 Subject: [PATCH 22/48] Improve documentation of CanvasItem's draw logic (cherry picked from commit 953c78eaff2fc63e18c5da66c809c7e2b7666b11) --- doc/classes/CanvasItem.xml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 48f65119c092..c2dce0b07357 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -5,7 +5,7 @@ Base class of anything 2D. Canvas items are laid out in a tree; children inherit and extend their parent's transform. [CanvasItem] is extended by [Control] for anything GUI-related, and by [Node2D] for anything related to the 2D engine. - Any [CanvasItem] can draw. For this, [method update] must be called, then [constant NOTIFICATION_DRAW] will be received on idle time to request redraw. Because of this, canvas items don't need to be redrawn on every frame, improving the performance significantly. Several functions for drawing on the [CanvasItem] are provided (see [code]draw_*[/code] functions). However, they can only be used inside the [method Object._notification], signal or [method _draw] virtual functions. + Any [CanvasItem] can draw. For this, [method update] is called by the engine, then [constant NOTIFICATION_DRAW] will be received on idle time to request redraw. Because of this, canvas items don't need to be redrawn on every frame, improving the performance significantly. Several functions for drawing on the [CanvasItem] are provided (see [code]draw_*[/code] functions). However, they can only be used inside [method _draw], its corresponding [method Object._notification] or methods connected to the [signal draw] signal. Canvas items are drawn in tree order. By default, children are on top of their parents so a root [CanvasItem] will be drawn behind everything. This behavior can be changed on a per-item basis. A [CanvasItem] can also be hidden, which will also hide its children. It provides many ways to change parameters such as modulation (for itself and its children) and self modulation (only for itself), as well as its blend mode. Ultimately, a transform notification can be requested, which will notify the node that its global position changed in case the parent tree changed. @@ -20,7 +20,8 @@ - Overridable function called by the engine (if defined) to draw the canvas item. + Called when [CanvasItem] has been requested to redraw (when [method update] is called, either manually or by the engine). + Corresponds to the [constant NOTIFICATION_DRAW] notification in [method Object._notification]. @@ -366,7 +367,7 @@ - Returns [code]true[/code] if the node is present in the [SceneTree], its [member visible] property is [code]true[/code] and all its antecedents are also visible. If any antecedent is hidden, this node will not be visible in the scene tree. + Returns [code]true[/code] if the node is present in the [SceneTree], its [member visible] property is [code]true[/code] and all its antecedents are also visible. If any antecedent is hidden, this node will not be visible in the scene tree, and is consequently not drawn (see [method _draw]). @@ -413,7 +414,7 @@ - Queue the [CanvasItem] for update. [constant NOTIFICATION_DRAW] will be called on idle time to request redraw. + Queues the [CanvasItem] to redraw. During idle time, if [CanvasItem] is visible, [constant NOTIFICATION_DRAW] is sent and [method _draw] is called. This only occurs [b]once[/b] per frame, even if this method has been called multiple times. @@ -447,7 +448,8 @@ - Emitted when the [CanvasItem] must redraw. This can only be connected realtime, as deferred will not allow drawing. + Emitted when the [CanvasItem] must redraw, [i]after[/i] the related [constant NOTIFICATION_DRAW] notification, and [i]before[/i] [method _draw] is called. + [b]Note:[/b] Deferred connections do not allow drawing through the [code]draw_*[/code] methods. @@ -492,7 +494,7 @@ The [CanvasItem]'s local transform has changed. This notification is only received if enabled by [method set_notify_local_transform]. - The [CanvasItem] is requested to draw. + The [CanvasItem] is requested to draw (see [method _draw]). The [CanvasItem]'s visibility has changed. From 5d30d77fd75ee5a51a3ea756c82d5694deb260f5 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Thu, 25 Aug 2022 13:07:54 +0800 Subject: [PATCH 23/48] Fix missing URL text in the classref (cherry picked from commit a90c348a86d60cdabac9e7f5d1109beeaa52b506) --- doc/classes/AnimationNodeStateMachineTransition.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml index 46d4daf646ee..7c3d6a4eddd3 100644 --- a/doc/classes/AnimationNodeStateMachineTransition.xml +++ b/doc/classes/AnimationNodeStateMachineTransition.xml @@ -11,7 +11,7 @@ - Turn on auto advance when this condition is set. The provided name will become a boolean parameter on the [AnimationTree] that can be controlled from code (see [url=$DOCS_URL/tutorials/animation/animation_tree.html#controlling-from-code][/url]). For example, if [member AnimationTree.tree_root] is an [AnimationNodeStateMachine] and [member advance_condition] is set to [code]"idle"[/code]: + Turn on auto advance when this condition is set. The provided name will become a boolean parameter on the [AnimationTree] that can be controlled from code (see [url=$DOCS_URL/tutorials/animation/animation_tree.html#controlling-from-code]Using AnimationTree[/url]). For example, if [member AnimationTree.tree_root] is an [AnimationNodeStateMachine] and [member advance_condition] is set to [code]"idle"[/code]: [codeblock] $animation_tree["parameters/conditions/idle"] = is_on_floor and (linear_velocity.x == 0) [/codeblock] From b5e368c92b1e2cc2d6a75cc8a1bb5fa29ff9d846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Fri, 26 Aug 2022 14:06:56 +0200 Subject: [PATCH 24/48] Linux: Fix GNU ld detection for pck_embed linker script (cherry picked from commit fce3602a1e892cbc35fb3aa409bdae835a37be4f) --- platform/x11/detect.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/x11/detect.py b/platform/x11/detect.py index 98c9ddb00b66..8b48f7f87231 100644 --- a/platform/x11/detect.py +++ b/platform/x11/detect.py @@ -405,7 +405,9 @@ def configure(env): import subprocess import re - linker_version_str = subprocess.check_output([env.subst(env["LINK"]), "-Wl,--version"]).decode("utf-8") + linker_version_str = subprocess.check_output( + [env.subst(env["LINK"]), "-Wl,--version"] + env.subst(env["LINKFLAGS"]) + ).decode("utf-8") gnu_ld_version = re.search("^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE) if not gnu_ld_version: print( From 555840914b40bfd6ccaf96589007d2b21b2234d5 Mon Sep 17 00:00:00 2001 From: Max Hilbrunner Date: Sun, 28 Aug 2022 14:38:54 +0200 Subject: [PATCH 25/48] Update UPnP documentation Adds more details, especially about caveats, failure modes and pitfalls (cherry picked from commit be41c097691acfd3f5559a28262730f086c46845) --- modules/upnp/doc_classes/UPNP.xml | 29 ++++++++++++++++--------- modules/upnp/doc_classes/UPNPDevice.xml | 4 ++-- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml index 60801a325876..66c4d190943f 100644 --- a/modules/upnp/doc_classes/UPNP.xml +++ b/modules/upnp/doc_classes/UPNP.xml @@ -1,16 +1,15 @@ - UPNP network functions. + Universal Plug and Play (UPnP) functions for network device discovery, querying and port forwarding. - Provides UPNP functionality to discover [UPNPDevice]s on the local network and execute commands on them, like managing port mappings (port forwarding) and querying the local and remote network IP address. Note that methods on this class are synchronous and block the calling thread. - To forward a specific port: + This class can be used to discover compatible [UPNPDevice]s on the local network and execute commands on them, like managing port mappings (for port forwarding/NAT traversal) and querying the local and remote network IP address. Note that methods on this class are synchronous and block the calling thread. + To forward a specific port (here [code]7777[/code], note both [method discover] and [method add_port_mapping] can return errors that should be checked): [codeblock] - const PORT = 7777 var upnp = UPNP.new() - upnp.discover(2000, 2, "InternetGatewayDevice") - upnp.add_port_mapping(port) + upnp.discover() + upnp.add_port_mapping(7777) [/codeblock] To close a specific port (e.g. after you have finished using it): [codeblock] @@ -21,7 +20,7 @@ # Emitted when UPnP port mapping setup is completed (regardless of success or failure). signal upnp_completed(error) - # Replace this with your own server port number between 1025 and 65535. + # Replace this with your own server port number between 1024 and 65535. const SERVER_PORT = 3928 var thread = null @@ -48,6 +47,14 @@ # Wait for thread finish here to handle game exit while the thread is running. thread.wait_to_finish() [/codeblock] + [b]Terminology:[/b] In the context of UPnP networking, "gateway" (or "internet gateway device", short IGD) refers to network devices that allow computers in the local network to access the internet ("wide area network", WAN). These gateways are often also called "routers". + [b]Pitfalls:[/b] + - As explained above, these calls are blocking and shouldn't be run on the main thread, especially as they can block for multiple seconds at a time. Use threading! + - Networking is physical and messy. Packets get lost in transit or get filtered, addresses, free ports and assigned mappings change, and devices may leave or join the network at any time. Be mindful of this, be diligent when checking and handling errors, and handle these gracefully if you can: add clear error UI, timeouts and re-try handling. + - Port mappings may change (and be removed) at any time, and the remote/external IP address of the gateway can change likewise. You should consider re-querying the external IP and try to update/refresh the port mapping periodically (for example, every 5 minutes and on networking failures). + - Not all devices support UPnP, and some users disable UPnP support. You need to handle this (e.g. documenting and requiring the user to manually forward ports, or adding alternative methods of NAT traversal, like a relay/mirror server, or NAT hole punching, STUN/TURN, etc.). + - Consider what happens on mapping conflicts. Maybe multiple users on the same network would like to play your game at the same time, or maybe another application uses the same port. Make the port configurable, and optimally choose a port automatically (re-trying with a different port on failure). + [b]Further reading:[/b] If you want to know more about UPnP (and the Internet Gateway Device (IGD) and Port Control Protocol (PCP) specifically), [url=https://en.wikipedia.org/wiki/Universal_Plug_and_Play]Wikipedia[/url] is a good first stop, the specification can be found at the [url=https://openconnectivity.org/developer/specifications/upnp-resources/upnp/]Open Connectivity Foundation[/url] and Godot's implementation is based on the [url=https://github.com/miniupnp/miniupnp]MiniUPnP client[/url]. @@ -67,9 +74,11 @@ - Adds a mapping to forward the external [code]port[/code] (between 1 and 65535) on the default gateway (see [method get_gateway]) to the [code]internal_port[/code] on the local machine for the given protocol [code]proto[/code] (either [code]TCP[/code] or [code]UDP[/code], with UDP being the default). If a port mapping for the given port and protocol combination already exists on that gateway device, this method tries to overwrite it. If that is not desired, you can retrieve the gateway manually with [method get_gateway] and call [method add_port_mapping] on it, if any. + Adds a mapping to forward the external [code]port[/code] (between 1 and 65535, although recommended to use port 1024 or above) on the default gateway (see [method get_gateway]) to the [code]internal_port[/code] on the local machine for the given protocol [code]proto[/code] (either [code]TCP[/code] or [code]UDP[/code], with UDP being the default). If a port mapping for the given port and protocol combination already exists on that gateway device, this method tries to overwrite it. If that is not desired, you can retrieve the gateway manually with [method get_gateway] and call [method add_port_mapping] on it, if any. Note that forwarding a well-known port (below 1024) with UPnP may fail depending on the device. + Depending on the gateway device, if a mapping for that port already exists, it will either be updated or it will refuse this command due to that conflict, especially if the existing mapping for that port wasn't created via UPnP or points to a different network address (or device) than this one. If [code]internal_port[/code] is [code]0[/code] (the default), the same port number is used for both the external and the internal port (the [code]port[/code] value). - The description ([code]desc[/code]) is shown in some router UIs and can be used to point out which application added the mapping. The mapping's lease duration can be limited by specifying a [code]duration[/code] (in seconds). However, some routers are incompatible with one or both of these, so use with caution and add fallback logic in case of errors to retry without them if in doubt. + The description ([code]desc[/code]) is shown in some routers management UIs and can be used to point out which application added the mapping. + The mapping's lease [code]duration[/code] can be limited by specifying a duration in seconds. The default of [code]0[/code] means no duration, i.e. a permanent lease and notably some devices only support these permanent leases. Note that whether permanent or not, this is only a request and the gateway may still decide at any point to remove the mapping (which usually happens on a reboot of the gateway, when its external IP address changes, or on some models when it detects a port mapping has become inactive, i.e. had no traffic for multiple minutes). If not [code]0[/code] (permanent), the allowed range according to spec is between [code]120[/code] (2 minutes) and [code]86400[/code] seconds (24 hours). See [enum UPNPResult] for possible return values. @@ -84,7 +93,7 @@ - Deletes the port mapping for the given port and protocol combination on the default gateway (see [method get_gateway]) if one exists. [code]port[/code] must be a valid port between 1 and 65535, [code]proto[/code] can be either [code]TCP[/code] or [code]UDP[/code]. See [enum UPNPResult] for possible return values. + Deletes the port mapping for the given port and protocol combination on the default gateway (see [method get_gateway]) if one exists. [code]port[/code] must be a valid port between 1 and 65535, [code]proto[/code] can be either [code]TCP[/code] or [code]UDP[/code]. May be refused for mappings pointing to addresses other than this one, for well-known ports (below 1024), or for mappings not added via UPnP. See [enum UPNPResult] for possible return values. diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml index 218ceafedd61..fdc93be787b9 100644 --- a/modules/upnp/doc_classes/UPNPDevice.xml +++ b/modules/upnp/doc_classes/UPNPDevice.xml @@ -1,10 +1,10 @@ - UPNP device. + Universal Plug and Play (UPnP) device. - UPNP device. See [UPNP] for UPNP discovery and utility functions. Provides low-level access to UPNP control commands. Allows to manage port mappings (port forwarding) and to query network information of the device (like local and external IP address and status). Note that methods on this class are synchronous and block the calling thread. + Universal Plug and Play (UPnP) device. See [UPNP] for UPnP discovery and utility functions. Provides low-level access to UPNP control commands. Allows to manage port mappings (port forwarding) and to query network information of the device (like local and external IP address and status). Note that methods on this class are synchronous and block the calling thread. From 5becfce6032b8a3207eaf2f0fa3f2ae30a7d33e8 Mon Sep 17 00:00:00 2001 From: Michael Alexsander Date: Sat, 27 Aug 2022 18:26:31 -0300 Subject: [PATCH 26/48] Fix crash when pressing up on an empty `PopupMenu` (cherry picked from commit f0d380c9fd7e285b4ea0bb1dd334ef4bed3422f5) --- scene/gui/popup_menu.cpp | 126 ++++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 62 deletions(-) diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 1b22b2b81aa2..a8ac5b6db101 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -223,93 +223,95 @@ void PopupMenu::_scroll(float p_factor, const Point2 &p_over) { void PopupMenu::_gui_input(const Ref &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (p_event->is_action("ui_down") && p_event->is_pressed()) { - int search_from = mouse_over + 1; - if (search_from >= items.size()) { - search_from = 0; - } - - bool match_found = false; - for (int i = search_from; i < items.size(); i++) { - if (i < 0 || i >= items.size()) { - continue; + if (!items.empty()) { + if (p_event->is_action("ui_down") && p_event->is_pressed()) { + int search_from = mouse_over + 1; + if (search_from >= items.size()) { + search_from = 0; } - if (!items[i].separator && !items[i].disabled) { - mouse_over = i; - emit_signal("id_focused", i); - update(); - accept_event(); - match_found = true; - break; - } - } + bool match_found = false; + for (int i = search_from; i < items.size(); i++) { + if (i < 0 || i >= items.size()) { + continue; + } - if (!match_found) { - // If the last item is not selectable, try re-searching from the start. - for (int i = 0; i < search_from; i++) { if (!items[i].separator && !items[i].disabled) { mouse_over = i; emit_signal("id_focused", i); update(); accept_event(); + match_found = true; break; } } - } - } else if (p_event->is_action("ui_up") && p_event->is_pressed()) { - int search_from = mouse_over - 1; - if (search_from < 0) { - search_from = items.size() - 1; - } - bool match_found = false; - for (int i = search_from; i >= 0; i--) { - if (i >= items.size()) { - continue; + if (!match_found) { + // If the last item is not selectable, try re-searching from the start. + for (int i = 0; i < search_from; i++) { + if (!items[i].separator && !items[i].disabled) { + mouse_over = i; + emit_signal("id_focused", i); + update(); + accept_event(); + break; + } + } } - - if (!items[i].separator && !items[i].disabled) { - mouse_over = i; - emit_signal("id_focused", i); - update(); - accept_event(); - match_found = true; - break; + } else if (p_event->is_action("ui_up") && p_event->is_pressed()) { + int search_from = mouse_over - 1; + if (search_from < 0) { + search_from = items.size() - 1; } - } - if (!match_found) { - // If the first item is not selectable, try re-searching from the end. - for (int i = items.size() - 1; i >= search_from; i--) { + bool match_found = false; + for (int i = search_from; i >= 0; i--) { + if (i >= items.size()) { + continue; + } + if (!items[i].separator && !items[i].disabled) { mouse_over = i; emit_signal("id_focused", i); update(); accept_event(); + match_found = true; break; } } - } - } else if (p_event->is_action("ui_left") && p_event->is_pressed()) { - Node *n = get_parent(); - if (n && Object::cast_to(n)) { - hide(); - accept_event(); - } - } else if (p_event->is_action("ui_right") && p_event->is_pressed()) { - if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over) { - _activate_submenu(mouse_over); - accept_event(); - } - } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) { - if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) { - if (items[mouse_over].submenu != "" && submenu_over != mouse_over) { + + if (!match_found) { + // If the first item is not selectable, try re-searching from the end. + for (int i = items.size() - 1; i >= search_from; i--) { + if (!items[i].separator && !items[i].disabled) { + mouse_over = i; + emit_signal("id_focused", i); + update(); + accept_event(); + break; + } + } + } + } else if (p_event->is_action("ui_left") && p_event->is_pressed()) { + Node *n = get_parent(); + if (n && Object::cast_to(n)) { + hide(); + accept_event(); + } + } else if (p_event->is_action("ui_right") && p_event->is_pressed()) { + if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over) { _activate_submenu(mouse_over); - } else { - activate_item(mouse_over); + accept_event(); + } + } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) { + if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) { + if (items[mouse_over].submenu != "" && submenu_over != mouse_over) { + _activate_submenu(mouse_over); + } else { + activate_item(mouse_over); + } + accept_event(); } - accept_event(); } } From 9f6c64135c276b4efafccdea678aff2ecc49e075 Mon Sep 17 00:00:00 2001 From: Atlinx Date: Mon, 29 Aug 2022 19:14:30 -0400 Subject: [PATCH 27/48] Remove HDR warning if on low end (cherry picked from commit e3b3462187b4c3980fd992dbcdff255346fcfd04) --- scene/main/viewport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index d405fd909034..89f4d80bf1f1 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -3031,7 +3031,7 @@ String Viewport::get_configuration_warning() const { warning += TTR("The Viewport size must be greater than or equal to 2 pixels on both dimensions to render anything."); } - if (hdr && (usage == USAGE_2D || usage == USAGE_2D_NO_SAMPLING)) { + if (!VisualServer::get_singleton()->is_low_end() && hdr && (usage == USAGE_2D || usage == USAGE_2D_NO_SAMPLING)) { if (warning != String()) { warning += "\n\n"; } From 9dcbf8a8a5f89c04e52db259b55b8440e6ee6b6b Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Tue, 30 Aug 2022 08:16:49 +0300 Subject: [PATCH 28/48] [3.x, macOS / iOS Export] Fix generation of duplicate locale property list files. (cherry picked from commit 3a24839cb2357a020f0c56cd46f3a66a12738d26) --- platform/iphone/export/export.cpp | 47 ++++++++++++++++++++----------- platform/osx/export/export.cpp | 24 +++++++++------- 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index aeb325d07e74..d362b50e28fc 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -664,26 +664,37 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref &p_ String locale_files; Vector translations = ProjectSettings::get_singleton()->get("locale/translations"); if (translations.size() > 0) { + Set languages; for (int j = 0; j < translations.size(); j++) { Ref tr = ResourceLoader::load(translations[j]); - if (tr.is_valid()) { - String lang = tr->get_locale(); - locale_files += "D0BCFE4518AEBDA2004A" + itos(j).pad_zeros(4) + " /* " + lang + " */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = " + lang + "; path = " + lang + ".lproj/InfoPlist.strings; sourceTree = \"\"; };"; + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); } } + int index = 0; + for (const Set::Element *E = languages.front(); E; E = E->next()) { + const String &lang = E->get(); + locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = " + lang + "; path = " + lang + ".lproj/InfoPlist.strings; sourceTree = \"\"; };\n"; + index++; + } } strnew += lines[i].replace("$pbx_locale_file_reference", locale_files); } else if (lines[i].find("$pbx_locale_build_reference") != -1) { String locale_files; Vector translations = ProjectSettings::get_singleton()->get("locale/translations"); if (translations.size() > 0) { + Set languages; for (int j = 0; j < translations.size(); j++) { Ref tr = ResourceLoader::load(translations[j]); - if (tr.is_valid()) { - String lang = tr->get_locale(); - locale_files += "D0BCFE4518AEBDA2004A" + itos(j).pad_zeros(4) + " /* " + lang + " */,"; + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); } } + int index = 0; + for (const Set::Element *E = languages.front(); E; E = E->next()) { + locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + E->get() + " */,\n"; + index++; + } } strnew += lines[i].replace("$pbx_locale_build_reference", locale_files); } else { @@ -1909,16 +1920,20 @@ Error EditorExportPlatformIOS::export_project(const Ref &p_p f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get("application/config/name").operator String() + "\";"); } - for (int i = 0; i < translations.size(); i++) { - Ref tr = ResourceLoader::load(translations[i]); - if (tr.is_valid()) { - String fname = dest_dir + binary_name + "/" + tr->get_locale() + ".lproj"; - tmp_app_path->make_dir_recursive(fname); - FileAccessRef f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); - String prop = "application/config/name_" + tr->get_locale(); - if (ProjectSettings::get_singleton()->has_setting(prop)) { - f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get(prop).operator String() + "\";"); - } + Set languages; + for (int j = 0; j < translations.size(); j++) { + Ref tr = ResourceLoader::load(translations[j]); + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); + } + } + for (const Set::Element *E = languages.front(); E; E = E->next()) { + String fname = dest_dir + binary_name + "/" + E->get() + ".lproj"; + tmp_app_path->make_dir_recursive(fname); + FileAccessRef f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); + String prop = "application/config/name_" + E->get(); + if (ProjectSettings::get_singleton()->has_setting(prop)) { + f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get(prop).operator String() + "\";"); } } } diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 9dd28d3125a1..8066dc5d02ec 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -896,16 +896,20 @@ Error EditorExportPlatformOSX::export_project(const Ref &p_p f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get("application/config/name").operator String() + "\";"); } - for (int i = 0; i < translations.size(); i++) { - Ref tr = ResourceLoader::load(translations[i]); - if (tr.is_valid()) { - String fname = tmp_app_path_name + "/Contents/Resources/" + tr->get_locale() + ".lproj"; - tmp_app_dir->make_dir_recursive(fname); - FileAccessRef f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); - String prop = "application/config/name_" + tr->get_locale(); - if (ProjectSettings::get_singleton()->has_setting(prop)) { - f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get(prop).operator String() + "\";"); - } + Set languages; + for (int j = 0; j < translations.size(); j++) { + Ref tr = ResourceLoader::load(translations[j]); + if (tr.is_valid() && tr->get_locale() != "en") { + languages.insert(tr->get_locale()); + } + } + for (const Set::Element *E = languages.front(); E; E = E->next()) { + String fname = tmp_app_path_name + "/Contents/Resources/" + E->get() + ".lproj"; + tmp_app_dir->make_dir_recursive(fname); + FileAccessRef f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); + String prop = "application/config/name_" + E->get(); + if (ProjectSettings::get_singleton()->has_setting(prop)) { + f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get(prop).operator String() + "\";"); } } } From 480e7ffd4a14f6820abf21f61e31fe520792b338 Mon Sep 17 00:00:00 2001 From: kleonc <9283098+kleonc@users.noreply.github.com> Date: Tue, 16 Aug 2022 14:34:29 +0200 Subject: [PATCH 29/48] `SceneTreeDock` Toggling unique name in owner for all selected nodes (cherry picked from commit 6417b999ee11fefaf0c4d5c9a677065a70b27d8f) --- editor/scene_tree_dock.cpp | 82 ++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index ad117d6d4491..1ceb513a79c0 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1129,24 +1129,63 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } break; case TOOL_TOGGLE_SCENE_UNIQUE_NAME: { - List selection = editor_selection->get_selected_node_list(); - List::Element *e = selection.front(); - if (e) { - UndoRedo *undo_redo = &editor_data->get_undo_redo(); - Node *node = e->get(); - bool enabled = node->is_unique_name_in_owner(); - if (!enabled && get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(node->get_name())) != nullptr) { - accept->set_text(TTR("Another node already uses this unique name in the scene.")); + // Enabling/disabling based on the same node based on which the checkbox in the menu is checked/unchecked. + List::Element *first_selected = editor_selection->get_selected_node_list().front(); + if (first_selected == nullptr) { + return; + } + bool enabling = !first_selected->get()->is_unique_name_in_owner(); + + List full_selection = editor_selection->get_full_selected_node_list(); + UndoRedo *undo_redo = &editor_data->get_undo_redo(); + + if (enabling) { + Vector new_unique_nodes; + Vector new_unique_names; + Vector cant_be_set_unique_names; + + for (List::Element *e = full_selection.front(); e; e = e->next()) { + Node *node = e->get(); + if (node->is_unique_name_in_owner()) { + continue; + } + StringName name = node->get_name(); + if (new_unique_names.find(name) != -1 || get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(name)) != nullptr) { + cant_be_set_unique_names.push_back(name); + } else { + new_unique_nodes.push_back(node); + new_unique_names.push_back(name); + } + } + + if (new_unique_nodes.size()) { + undo_redo->create_action(TTR("Enable Scene Unique Name(s)")); + for (int i = 0; i < new_unique_nodes.size(); i++) { + undo_redo->add_do_method(new_unique_nodes[i], "set_unique_name_in_owner", true); + undo_redo->add_undo_method(new_unique_nodes[i], "set_unique_name_in_owner", false); + } + undo_redo->commit_action(); + } + + if (cant_be_set_unique_names.size()) { + String popup_text = TTR("Unique names already used by another node in the scene:"); + popup_text += "\n"; + for (int i = 0; i < cant_be_set_unique_names.size(); i++) { + popup_text += "\n" + String(cant_be_set_unique_names[i]); + } + accept->set_text(popup_text); accept->popup_centered(); - return; } - if (!enabled) { - undo_redo->create_action(TTR("Enable Scene Unique Name")); - } else { - undo_redo->create_action(TTR("Disable Scene Unique Name")); + } else { // Disabling. + undo_redo->create_action(TTR("Disable Scene Unique Name(s)")); + for (List::Element *e = full_selection.front(); e; e = e->next()) { + Node *node = e->get(); + if (!node->is_unique_name_in_owner()) { + continue; + } + undo_redo->add_do_method(node, "set_unique_name_in_owner", false); + undo_redo->add_undo_method(node, "set_unique_name_in_owner", true); } - undo_redo->add_do_method(node, "set_unique_name_in_owner", !enabled); - undo_redo->add_undo_method(node, "set_unique_name_in_owner", enabled); undo_redo->commit_action(); } } break; @@ -2815,9 +2854,18 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } if (profile_allow_editing) { - if (selection[0]->get_owner() == EditorNode::get_singleton()->get_edited_scene()) { - // Only for nodes owned by the edited scene root. + // Allow multi-toggling scene unique names but only if all selected nodes are owned by the edited scene root. + bool all_owned = true; + for (List::Element *e = full_selection.front(); e; e = e->next()) { + Node *node = e->get(); + if (node->get_owner() != EditorNode::get_singleton()->get_edited_scene()) { + all_owned = false; + break; + } + } + if (all_owned) { menu->add_icon_check_item(get_icon("SceneUniqueName", "EditorIcons"), TTR("Access as Scene Unique Name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME); + // Checked based on `selection[0]` because `full_selection` has undesired ordering. menu->set_item_checked(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), selection[0]->is_unique_name_in_owner()); menu->add_separator(); } From 1309633cdb52146c8b3e04df9653542501baada2 Mon Sep 17 00:00:00 2001 From: smix8 <52464204+smix8@users.noreply.github.com> Date: Sat, 13 Aug 2022 19:46:12 +0200 Subject: [PATCH 30/48] Fix NavigationObstacle nodes not registering to default navigation map Fix NavigationObstacle nodes not registering to default navigation map. (cherry picked from commit 47b39ce4c2d01e05aa630302c6cfdb7bb99ec106) --- scene/2d/navigation_obstacle_2d.cpp | 7 ++++++- scene/3d/navigation_obstacle.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index 1a9f2dba8037..c5ac9b33e2a7 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -139,7 +139,12 @@ void NavigationObstacle2D::set_navigation(Navigation2D *p_nav) { } navigation = p_nav; - Navigation2DServer::get_singleton()->agent_set_map(agent, navigation == nullptr ? RID() : navigation->get_rid()); + + if (navigation != nullptr) { + Navigation2DServer::get_singleton()->agent_set_map(agent, navigation->get_rid()); + } else if (parent_node2d && parent_node2d->is_inside_tree()) { + Navigation2DServer::get_singleton()->agent_set_map(agent, parent_node2d->get_world_2d()->get_navigation_map()); + } } void NavigationObstacle2D::set_navigation_node(Node *p_nav) { diff --git a/scene/3d/navigation_obstacle.cpp b/scene/3d/navigation_obstacle.cpp index 78594cee1808..1376a08d5213 100644 --- a/scene/3d/navigation_obstacle.cpp +++ b/scene/3d/navigation_obstacle.cpp @@ -145,7 +145,12 @@ void NavigationObstacle::set_navigation(Navigation *p_nav) { } navigation = p_nav; - NavigationServer::get_singleton()->agent_set_map(agent, navigation == nullptr ? RID() : navigation->get_rid()); + + if (navigation != nullptr) { + NavigationServer::get_singleton()->agent_set_map(agent, navigation->get_rid()); + } else if (parent_spatial && parent_spatial->is_inside_tree()) { + NavigationServer::get_singleton()->agent_set_map(agent, parent_spatial->get_world()->get_navigation_map()); + } } void NavigationObstacle::set_navigation_node(Node *p_nav) { From d3a86d6829ba6bf0f2e02b8b1b668b263d17012f Mon Sep 17 00:00:00 2001 From: Atlinx Date: Mon, 29 Aug 2022 18:27:43 -0400 Subject: [PATCH 31/48] Add missing parameters for signal in docs (cherry picked from commit 0e3097c023fa4562d44fa102bd2ef8e456f8901a) (cherry picked from commit f624acef429745b74989c38f646b627cacf19bd2) --- doc/classes/EditorProperty.xml | 2 ++ editor/editor_inspector.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml index 69125f204a4c..89720676f576 100644 --- a/doc/classes/EditorProperty.xml +++ b/doc/classes/EditorProperty.xml @@ -96,6 +96,8 @@ + + Do not emit this manually, use the [method emit_changed] method instead. diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 179ac61fccba..98b760342dce 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -765,7 +765,7 @@ void EditorProperty::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "checked"), "set_checked", "is_checked"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_red"), "set_draw_red", "is_draw_red"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keying"), "set_keying", "is_keying"); - ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); + ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::STRING, "field"), PropertyInfo(Variant::BOOL, "changing"))); ADD_SIGNAL(MethodInfo("multiple_properties_changed", PropertyInfo(Variant::POOL_STRING_ARRAY, "properties"), PropertyInfo(Variant::ARRAY, "value"))); ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property"))); ADD_SIGNAL(MethodInfo("property_keyed_with_value", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); From 9f4bb53a87bf422785ec12312dbf650b11fb8fee Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Mon, 29 Aug 2022 14:20:33 +0800 Subject: [PATCH 32/48] Improve documentation for `get_animation()` (cherry picked from commit fed2879463419583ccaf375d7cd44cff56fc69bf) --- doc/classes/AnimationPlayer.xml | 2 +- scene/animation/animation_player.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index ea404209012d..9090cd81692e 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -67,7 +67,7 @@ - Returns the [Animation] with key [code]name[/code] or [code]null[/code] if not found. + Returns the [Animation] with the key [code]name[/code]. If the animation does not exist, [code]null[/code] is returned and an error is logged. diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 7c0b6e0441bb..44d568407d88 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1052,13 +1052,15 @@ void AnimationPlayer::rename_animation(const StringName &p_name, const StringNam bool AnimationPlayer::has_animation(const StringName &p_name) const { return animation_set.has(p_name); } + Ref AnimationPlayer::get_animation(const StringName &p_name) const { - ERR_FAIL_COND_V(!animation_set.has(p_name), Ref()); + ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref(), vformat("Animation not found: \"%s\".", p_name)); const AnimationData &data = animation_set[p_name]; return data.animation; } + void AnimationPlayer::get_animation_list(List *p_animations) const { List anims; From 682428279a8295c4be30646a4cc9ced2dd152fd2 Mon Sep 17 00:00:00 2001 From: Michael Alexsander Date: Sun, 21 Aug 2022 18:06:07 -0300 Subject: [PATCH 33/48] Expose `set/get_tab_button_icon()` to scripting (cherry picked from commit 73470e1b162d52ae1c49fd42e85b8e4706f70010) --- doc/classes/Tabs.xml | 17 ++++++++++++++++- scene/gui/tabs.cpp | 4 +++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/doc/classes/Tabs.xml b/doc/classes/Tabs.xml index f49096254959..b68730077a4e 100644 --- a/doc/classes/Tabs.xml +++ b/doc/classes/Tabs.xml @@ -42,6 +42,13 @@ Returns [code]true[/code] if select with right mouse button is enabled. + + + + + Returns the button icon from the tab at index [code]tab_idx[/code]. + + @@ -110,6 +117,14 @@ If [code]true[/code], enables selecting a tab with the right mouse button. + + + + + + Sets the button icon from the tab at index [code]tab_idx[/code]. + + @@ -169,7 +184,7 @@ - Emitted when a tab is right-clicked. + Emitted when a tab's right button is pressed. See [method set_tab_button_icon]. diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 66e131a6cd78..6526fc781b49 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -139,7 +139,7 @@ void Tabs::_gui_input(const Ref &p_event) { if (rb_pressing && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { if (rb_hover != -1) { - // Right mouse button pressed. + // Right tab button pressed. emit_signal("right_button_pressed", rb_hover); } @@ -955,6 +955,8 @@ void Tabs::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tab_title", "tab_idx"), &Tabs::get_tab_title); ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &Tabs::set_tab_icon); ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &Tabs::get_tab_icon); + ClassDB::bind_method(D_METHOD("set_tab_button_icon", "tab_idx", "icon"), &Tabs::set_tab_right_button); + ClassDB::bind_method(D_METHOD("get_tab_button_icon", "tab_idx"), &Tabs::get_tab_right_button); ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &Tabs::set_tab_disabled); ClassDB::bind_method(D_METHOD("get_tab_disabled", "tab_idx"), &Tabs::get_tab_disabled); ClassDB::bind_method(D_METHOD("remove_tab", "tab_idx"), &Tabs::remove_tab); From a957b4fb8c4011ada085bd637022db346abf6219 Mon Sep 17 00:00:00 2001 From: Marcel Admiraal Date: Fri, 26 Aug 2022 16:04:54 +0100 Subject: [PATCH 34/48] Fix header guard in error_macros.h (cherry picked from commit e2dac6ecd9b5b657263953001294aa8560866853) --- core/error_macros.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/error_macros.h b/core/error_macros.h index 38d118a9e141..3aa4c9c48236 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -518,8 +518,6 @@ void _err_flush_stdout(); } else \ ((void)0) -#endif - /** * This should be a 'free' assert for program flow and should not be needed in any releases, * only used in dev builds. @@ -558,5 +556,6 @@ void _err_flush_stdout(); ((void)0) #else #define DEV_CHECK_ONCE(m_cond) +#endif #endif // ERROR_MACROS_H From 519bc3a1e813841d42fc0903347a28efa077c255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Fri, 19 Aug 2022 10:38:13 +0200 Subject: [PATCH 35/48] Make audio thread control flags safe (cherry picked from commit c92ceca5ce9f219a5f803cdb0ddc354b7d5e1dce) --- drivers/alsa/audio_driver_alsa.cpp | 25 +++++++-------- drivers/alsa/audio_driver_alsa.h | 6 ++-- drivers/alsamidi/midi_driver_alsamidi.cpp | 8 ++--- drivers/alsamidi/midi_driver_alsamidi.h | 3 +- .../pulseaudio/audio_driver_pulseaudio.cpp | 30 +++++++---------- drivers/pulseaudio/audio_driver_pulseaudio.h | 6 ++-- drivers/wasapi/audio_driver_wasapi.cpp | 32 ++++++++----------- drivers/wasapi/audio_driver_wasapi.h | 7 ++-- drivers/xaudio2/audio_driver_xaudio2.cpp | 17 +++++----- drivers/xaudio2/audio_driver_xaudio2.h | 6 ++-- servers/audio/audio_driver_dummy.cpp | 17 +++++----- servers/audio/audio_driver_dummy.h | 6 ++-- 12 files changed, 73 insertions(+), 90 deletions(-) diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index 876aa08e358a..5222b99cf92a 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -168,9 +168,8 @@ Error AudioDriverALSA::init() { return ERR_CANT_OPEN; } - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); Error err = init_device(); if (err == OK) { @@ -183,11 +182,11 @@ Error AudioDriverALSA::init() { void AudioDriverALSA::thread_func(void *p_udata) { AudioDriverALSA *ad = (AudioDriverALSA *)p_udata; - while (!ad->exit_thread) { + while (!ad->exit_thread.is_set()) { ad->lock(); ad->start_counting_ticks(); - if (!ad->active) { + if (!ad->active.is_set()) { for (uint64_t i = 0; i < ad->period_size * ad->channels; i++) { ad->samples_out.write[i] = 0; } @@ -203,7 +202,7 @@ void AudioDriverALSA::thread_func(void *p_udata) { int todo = ad->period_size; int total = 0; - while (todo && !ad->exit_thread) { + while (todo && !ad->exit_thread.is_set()) { int16_t *src = (int16_t *)ad->samples_out.ptr(); int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo); @@ -222,8 +221,8 @@ void AudioDriverALSA::thread_func(void *p_udata) { wrote = snd_pcm_recover(ad->pcm_handle, wrote, 0); if (wrote < 0) { ERR_PRINT("ALSA: Failed and can't recover: " + String(snd_strerror(wrote))); - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); } } } @@ -241,8 +240,8 @@ void AudioDriverALSA::thread_func(void *p_udata) { err = ad->init_device(); if (err != OK) { - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); } } } @@ -250,12 +249,10 @@ void AudioDriverALSA::thread_func(void *p_udata) { ad->stop_counting_ticks(); ad->unlock(); } - - ad->thread_exited = true; } void AudioDriverALSA::start() { - active = true; + active.set(); } int AudioDriverALSA::get_mix_rate() const { @@ -327,7 +324,7 @@ void AudioDriverALSA::finish_device() { } void AudioDriverALSA::finish() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); finish_device(); diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h index e61fe6f1bab9..082a377aac8a 100644 --- a/drivers/alsa/audio_driver_alsa.h +++ b/drivers/alsa/audio_driver_alsa.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "servers/audio_server.h" #include "asound-so_wrap.h" @@ -64,9 +65,8 @@ class AudioDriverALSA : public AudioDriver { snd_pcm_uframes_t period_size; int channels; - bool active; - bool thread_exited; - mutable bool exit_thread; + SafeFlag active; + SafeFlag exit_thread; public: const char *get_name() const { diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp index ba9287b18ae6..73f6a2eaa728 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.cpp +++ b/drivers/alsamidi/midi_driver_alsamidi.cpp @@ -79,7 +79,7 @@ void MIDIDriverALSAMidi::thread_func(void *p_udata) { int expected_size = 255; int bytes = 0; - while (!md->exit_thread) { + while (!md->exit_thread.is_set()) { int ret; md->lock(); @@ -149,14 +149,14 @@ Error MIDIDriverALSAMidi::open() { } snd_device_name_free_hint(hints); - exit_thread = false; + exit_thread.clear(); thread.start(MIDIDriverALSAMidi::thread_func, this); return OK; } void MIDIDriverALSAMidi::close() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); for (int i = 0; i < connected_inputs.size(); i++) { @@ -193,7 +193,7 @@ PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() { } MIDIDriverALSAMidi::MIDIDriverALSAMidi() { - exit_thread = false; + exit_thread.clear(); } MIDIDriverALSAMidi::~MIDIDriverALSAMidi() { diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h index dada62a10546..96554f462d82 100644 --- a/drivers/alsamidi/midi_driver_alsamidi.h +++ b/drivers/alsamidi/midi_driver_alsamidi.h @@ -36,6 +36,7 @@ #include "core/os/midi_driver.h" #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "core/vector.h" #include "../alsa/asound-so_wrap.h" @@ -47,7 +48,7 @@ class MIDIDriverALSAMidi : public MIDIDriver { Vector connected_inputs; - bool exit_thread; + SafeFlag exit_thread; static void thread_func(void *p_udata); diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index fd0fccb3f9e2..55baf7afa2bd 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -285,9 +285,8 @@ Error AudioDriverPulseAudio::init() { return ERR_CANT_OPEN; } - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); mix_rate = GLOBAL_GET("audio/mix_rate"); @@ -384,7 +383,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { size_t avail_bytes = 0; uint64_t default_device_msec = OS::get_singleton()->get_ticks_msec(); - while (!ad->exit_thread) { + while (!ad->exit_thread.is_set()) { size_t read_bytes = 0; size_t written_bytes = 0; @@ -394,7 +393,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { int16_t *out_ptr = ad->samples_out.ptrw(); - if (!ad->active) { + if (!ad->active.is_set()) { for (unsigned int i = 0; i < ad->pa_buffer_size; i++) { out_ptr[i] = 0; } @@ -464,8 +463,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { err = ad->init_device(); if (err != OK) { - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); break; } } @@ -503,8 +502,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { Error err = ad->init_device(); if (err != OK) { ERR_PRINT("PulseAudio: init_device error"); - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); break; } @@ -557,8 +556,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { err = ad->capture_init_device(); if (err != OK) { - ad->active = false; - ad->exit_thread = true; + ad->active.clear(); + ad->exit_thread.set(); break; } } @@ -573,12 +572,10 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { OS::get_singleton()->delay_usec(1000); } } - - ad->thread_exited = true; } void AudioDriverPulseAudio::start() { - active = true; + active.set(); } int AudioDriverPulseAudio::get_mix_rate() const { @@ -663,7 +660,7 @@ void AudioDriverPulseAudio::finish() { return; } - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); finish_device(); @@ -840,9 +837,6 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() : channels(0), pa_ready(0), pa_status(0), - active(false), - thread_exited(false), - exit_thread(false), latency(0) { samples_in.clear(); samples_out.clear(); diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index 125dd34b9277..bbe45ca91d3d 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/drivers/pulseaudio/audio_driver_pulseaudio.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "servers/audio_server.h" #include "pulse-so_wrap.h" @@ -70,9 +71,8 @@ class AudioDriverPulseAudio : public AudioDriver { Array pa_devices; Array pa_rec_devices; - bool active; - bool thread_exited; - mutable bool exit_thread; + SafeFlag active; + SafeFlag exit_thread; float latency; diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index fcde0c05b8ba..ce599f7ee648 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -365,12 +365,12 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) { } Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) { - if (p_device->active) { + if (p_device->active.is_set()) { if (p_device->audio_client) { p_device->audio_client->Stop(); } - p_device->active = false; + p_device->active.clear(); } SAFE_RELEASE(p_device->audio_client) @@ -396,8 +396,7 @@ Error AudioDriverWASAPI::init() { ERR_PRINT("WASAPI: init_render_device error"); } - exit_thread = false; - thread_exited = false; + exit_thread.clear(); thread.start(thread_func, this); @@ -543,7 +542,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { uint32_t avail_frames = 0; uint32_t write_ofs = 0; - while (!ad->exit_thread) { + while (!ad->exit_thread.is_set()) { uint32_t read_frames = 0; uint32_t written_frames = 0; @@ -551,7 +550,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { ad->lock(); ad->start_counting_ticks(); - if (ad->audio_output.active) { + if (ad->audio_output.active.is_set()) { ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw()); } else { for (int i = 0; i < ad->samples_in.size(); i++) { @@ -617,7 +616,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } } else { ERR_PRINT("WASAPI: Get buffer error"); - ad->exit_thread = true; + ad->exit_thread.set(); } } } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { @@ -666,7 +665,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { write_ofs = 0; } - if (ad->audio_input.active) { + if (ad->audio_input.active.is_set()) { UINT32 packet_length = 0; BYTE *data; UINT32 num_frames_available; @@ -745,8 +744,6 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { OS::get_singleton()->delay_usec(1000); } } - - ad->thread_exited = true; } void AudioDriverWASAPI::start() { @@ -755,7 +752,7 @@ void AudioDriverWASAPI::start() { if (hr != S_OK) { ERR_PRINT("WASAPI: Start failed"); } else { - audio_output.active = true; + audio_output.active.set(); } } } @@ -769,7 +766,7 @@ void AudioDriverWASAPI::unlock() { } void AudioDriverWASAPI::finish() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); finish_capture_device(); @@ -783,19 +780,19 @@ Error AudioDriverWASAPI::capture_start() { return err; } - if (audio_input.active) { + if (audio_input.active.is_set()) { return FAILED; } audio_input.audio_client->Start(); - audio_input.active = true; + audio_input.active.set(); return OK; } Error AudioDriverWASAPI::capture_stop() { - if (audio_input.active) { + if (audio_input.active.is_set()) { audio_input.audio_client->Stop(); - audio_input.active = false; + audio_input.active.clear(); return OK; } @@ -827,9 +824,6 @@ AudioDriverWASAPI::AudioDriverWASAPI() { channels = 0; mix_rate = 0; buffer_frames = 0; - - thread_exited = false; - exit_thread = false; } #endif diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index 5bf8aa3b8879..e708906bb4b6 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "servers/audio_server.h" #include @@ -48,7 +49,7 @@ class AudioDriverWASAPI : public AudioDriver { IAudioClient *audio_client; IAudioRenderClient *render_client; IAudioCaptureClient *capture_client; - bool active; + SafeFlag active; WORD format_tag; WORD bits_per_sample; @@ -62,7 +63,6 @@ class AudioDriverWASAPI : public AudioDriver { audio_client(NULL), render_client(NULL), capture_client(NULL), - active(false), format_tag(0), bits_per_sample(0), channels(0), @@ -84,8 +84,7 @@ class AudioDriverWASAPI : public AudioDriver { int mix_rate; int buffer_frames; - bool thread_exited; - mutable bool exit_thread; + SafeFlag exit_thread; static _FORCE_INLINE_ void write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample); static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i); diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp index 14b21d0f52e0..e86c74bc4a71 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.cpp @@ -38,9 +38,8 @@ const char *AudioDriverXAudio2::get_name() const { } Error AudioDriverXAudio2::init() { - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); pcm_open = false; samples_in = NULL; @@ -86,17 +85,19 @@ Error AudioDriverXAudio2::init() { void AudioDriverXAudio2::thread_func(void *p_udata) { AudioDriverXAudio2 *ad = (AudioDriverXAudio2 *)p_udata; - while (!ad->exit_thread) { - if (!ad->active) { + while (!ad->exit_thread.is_set()) { + if (!ad->active.is_set()) { for (int i = 0; i < AUDIO_BUFFERS; i++) { ad->xaudio_buffer[i].Flags = XAUDIO2_END_OF_STREAM; } } else { ad->lock(); + ad->start_counting_ticks(); ad->audio_server_process(ad->buffer_size, ad->samples_in); + ad->stop_counting_ticks(); ad->unlock(); for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { @@ -117,12 +118,10 @@ void AudioDriverXAudio2::thread_func(void *p_udata) { } } } - - ad->thread_exited = true; } void AudioDriverXAudio2::start() { - active = true; + active.set(); HRESULT hr = source_voice->Start(0); ERR_FAIL_COND_MSG(hr != S_OK, "Error starting XAudio2 driver. Error code: " + itos(hr) + "."); } @@ -156,7 +155,7 @@ void AudioDriverXAudio2::finish() { if (!thread.is_started()) return; - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); if (source_voice) { diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h index 5c1382b4cf1d..4a161fc39daa 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.h +++ b/drivers/xaudio2/audio_driver_xaudio2.h @@ -33,6 +33,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" #include "servers/audio_server.h" #include @@ -77,9 +78,8 @@ class AudioDriverXAudio2 : public AudioDriver { int channels; - bool active; - bool thread_exited; - mutable bool exit_thread; + SafeFlag active; + SafeFlag exit_thread; bool pcm_open; WAVEFORMATEX wave_format; diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp index 216df99ca288..e53d5f42004a 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -34,9 +34,8 @@ #include "core/project_settings.h" Error AudioDriverDummy::init() { - active = false; - thread_exited = false; - exit_thread = false; + active.clear(); + exit_thread.clear(); samples_in = nullptr; mix_rate = GLOBAL_GET("audio/mix_rate"); @@ -58,23 +57,23 @@ void AudioDriverDummy::thread_func(void *p_udata) { uint64_t usdelay = (ad->buffer_frames / float(ad->mix_rate)) * 1000000; - while (!ad->exit_thread) { - if (ad->active) { + while (!ad->exit_thread.is_set()) { + if (ad->active.is_set()) { ad->lock(); + ad->start_counting_ticks(); ad->audio_server_process(ad->buffer_frames, ad->samples_in); + ad->stop_counting_ticks(); ad->unlock(); }; OS::get_singleton()->delay_usec(usdelay); }; - - ad->thread_exited = true; }; void AudioDriverDummy::start() { - active = true; + active.set(); }; int AudioDriverDummy::get_mix_rate() const { @@ -94,7 +93,7 @@ void AudioDriverDummy::unlock() { }; void AudioDriverDummy::finish() { - exit_thread = true; + exit_thread.set(); thread.wait_to_finish(); if (samples_in) { diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h index 5c93533a99be..b04ce73c8540 100644 --- a/servers/audio/audio_driver_dummy.h +++ b/servers/audio/audio_driver_dummy.h @@ -35,6 +35,7 @@ #include "core/os/mutex.h" #include "core/os/thread.h" +#include "core/safe_refcount.h" class AudioDriverDummy : public AudioDriver { Thread thread; @@ -50,9 +51,8 @@ class AudioDriverDummy : public AudioDriver { int channels; - bool active; - bool thread_exited; - mutable bool exit_thread; + SafeFlag active; + SafeFlag exit_thread; public: const char *get_name() const { From 93f4a12278af83d0c7b3580cc7bfacf8a6399e2e Mon Sep 17 00:00:00 2001 From: Marcel Admiraal Date: Wed, 17 Aug 2022 09:10:36 +0100 Subject: [PATCH 36/48] Fix axis mapped to DPad buttons not releasing opposite button (cherry picked from commit cdd60416ed4059e2e547dedd3cbfeb379de04574) --- main/input_default.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/main/input_default.cpp b/main/input_default.cpp index ad37da8ac562..b0431b681d92 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -841,11 +841,9 @@ void InputDefault::joy_axis(int p_device, int p_axis, float p_value) { } bool pressed = map.value > 0.5; - if (pressed == joy_buttons_pressed.has(_combine_device(map.index, p_device))) { - // Button already pressed or released; so ignore. - return; + if (pressed != joy_buttons_pressed.has(_combine_device(map.index, p_device))) { + _button_event(p_device, map.index, pressed); } - _button_event(p_device, map.index, pressed); // Ensure opposite D-Pad button is also released. switch (map.index) { @@ -992,7 +990,7 @@ InputDefault::JoyEvent InputDefault::_get_mapped_axis_event(const JoyDeviceMappi value = -value; } if (binding.input.axis.range == FULL_AXIS || - (binding.input.axis.range == POSITIVE_HALF_AXIS && value > 0) || + (binding.input.axis.range == POSITIVE_HALF_AXIS && value >= 0) || (binding.input.axis.range == NEGATIVE_HALF_AXIS && value < 0)) { event.type = binding.outputType; float shifted_positive_value = 0; From e3745de02d1cc135451aaee2a3f86adf68e038ff Mon Sep 17 00:00:00 2001 From: Aaron Franke Date: Sun, 14 Aug 2022 16:06:57 -0500 Subject: [PATCH 37/48] [3.x] Fix incorrect Camera3D size documentation (cherry picked from commit cac69ea13266cba46b9c78de65028e0846c9b0ac) --- doc/classes/Camera.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/classes/Camera.xml b/doc/classes/Camera.xml index a9d45fc888a2..648b79c0d1ef 100644 --- a/doc/classes/Camera.xml +++ b/doc/classes/Camera.xml @@ -179,7 +179,7 @@ The camera's projection mode. In [constant PROJECTION_PERSPECTIVE] mode, objects' Z distance from the camera's local space scales their perceived size. - The camera's size measured as 1/2 the width or height. Only applicable in orthogonal and frustum modes. Since [member keep_aspect] locks on axis, [code]size[/code] sets the other axis' size length. + The camera's size in meters measured as the diameter of the width or height, depending on [member keep_aspect]. Only applicable in orthogonal and frustum modes. The vertical (Y) offset of the camera viewport. From 92eab475918b8ed4d9c5d8e362f38906ddd092ed Mon Sep 17 00:00:00 2001 From: Cory Petkovsek <632766+tinmanjuggernaut@users.noreply.github.com> Date: Thu, 11 Aug 2022 02:22:37 +0800 Subject: [PATCH 38/48] Fix free(RID) abuse by various classes (cherry picked from commit f7f112ab1f1b0c70f23f7ac643a108c4b4695914) --- scene/2d/particles_2d.cpp | 4 +++- scene/3d/gi_probe.cpp | 8 ++++++-- scene/3d/particles.cpp | 4 +++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index 79182cb2b86d..6cdf5f8cd186 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -419,5 +419,7 @@ Particles2D::Particles2D() { } Particles2D::~Particles2D() { - VS::get_singleton()->free(particles); + if (particles.is_valid()) { + VS::get_singleton()->free(particles); + } } diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index f70d308cb346..df5f6de21b21 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -179,7 +179,9 @@ GIProbeData::GIProbeData() { } GIProbeData::~GIProbeData() { - VS::get_singleton()->free(probe); + if (probe.is_valid()) { + VS::get_singleton()->free(probe); + } } ////////////////////// @@ -527,5 +529,7 @@ GIProbe::GIProbe() { } GIProbe::~GIProbe() { - VS::get_singleton()->free(gi_probe); + if (gi_probe.is_valid()) { + VS::get_singleton()->free(gi_probe); + } } diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 4076aa27527a..26c40e0677d5 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -416,5 +416,7 @@ Particles::Particles() { } Particles::~Particles() { - VS::get_singleton()->free(particles); + if (particles.is_valid()) { + VS::get_singleton()->free(particles); + } } From 2ac25fbcc793f2b21c2469206215e4a00c19a562 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Sun, 14 Aug 2022 15:05:56 +0200 Subject: [PATCH 39/48] Document run-time SceneTree debug property changes not working correctly (cherry picked from commit 3396f45eef7f4c7f7ca3e3be5074fbbf58307780) --- doc/classes/SceneTree.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index 399dd3ccf1fa..2d57a05a6564 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -233,9 +233,11 @@ If [code]true[/code], collision shapes will be visible when running the game from the editor for debugging purposes. + [b]Note:[/b] This property is not designed to be changed at run-time. Changing the value of [member debug_collisions_hint] while the project is running will not have the desired effect. If [code]true[/code], navigation polygons will be visible when running the game from the editor for debugging purposes. + [b]Note:[/b] This property is not designed to be changed at run-time. Changing the value of [member debug_navigation_hint] while the project is running will not have the desired effect. The root of the edited scene. From e85c5dba2350716f580eca20b0169f4ec218d063 Mon Sep 17 00:00:00 2001 From: Andy Maloney Date: Wed, 17 Aug 2022 12:17:28 -0400 Subject: [PATCH 40/48] [doc 3.x] Clarify that AnimationNode virtual methods need to be implemented rather than called directly Backport of #64344 Fixes #35272 (cherry picked from commit 4ee4c7954aa99c82fc87fe9eef0eca6607c948cf) --- doc/classes/AnimationNode.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index 96776325d5f9..4dc77cd09acb 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -57,20 +57,20 @@ - Gets the text caption for this node (used by some editors). + When inheriting from [AnimationRootNode], implement this virtual method to override the text caption for this node. - Gets a child node by index (used by editors inheriting from [AnimationRootNode]). + When inheriting from [AnimationRootNode], implement this virtual method to return a child node by its [code]name[/code]. - Gets all children nodes in order as a [code]name: node[/code] dictionary. Only useful when inheriting [AnimationRootNode]. + When inheriting from [AnimationRootNode], implement this virtual method to return all children nodes in order as a [code]name: node[/code] dictionary. @@ -97,19 +97,19 @@ - Gets the default value of a parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. + When inheriting from [AnimationRootNode], implement this virtual method to return the default value of parameter "[code]name[/code]". Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. - Gets the property information for parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. Format is similar to [method Object.get_property_list]. + When inheriting from [AnimationRootNode], implement this virtual method to return a list of the properties on this node. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. Format is similar to [method Object.get_property_list]. - Returns [code]true[/code] whether you want the blend tree editor to display filter editing on this node. + When inheriting from [AnimationRootNode], implement this virtual method to return whether the blend tree editor should display filter editing on this node. @@ -124,7 +124,7 @@ - User-defined callback called when a custom node is processed. The [code]time[/code] parameter is a relative delta, unless [code]seek[/code] is [code]true[/code], in which case it is absolute. + When inheriting from [AnimationRootNode], implement this virtual method to run some code when this node is processed. The [code]time[/code] parameter is a relative delta, unless [code]seek[/code] is [code]true[/code], in which case it is absolute. Here, call the [method blend_input], [method blend_node] or [method blend_animation] functions. You can also use [method get_parameter] and [method set_parameter] to modify local memory. This function should return the time left for the current animation to finish (if unsure, pass the value from the main blend being called). From ab5f3fcbe0703983fcbb9a3e488e651780fe320c Mon Sep 17 00:00:00 2001 From: Nathan Franke Date: Fri, 19 Aug 2022 12:05:15 -0500 Subject: [PATCH 41/48] 3.x: ios: force app store icon to be opaque, use proper errors, fix memory leak (cherry picked from commit da3aecff01c0d06342301ddd276dbc6fea62eaeb) --- platform/iphone/export/export.cpp | 68 ++++++++++++++++++------------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index d362b50e28fc..2cd9e3443aae 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -413,27 +413,27 @@ void EditorExportPlatformIOS::get_export_options(List *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone/iPod Touch with Retina display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone with Retina HD display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone/iPod Touch with Retina display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone with Retina HD display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad with Retina display - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad Pro + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad with Retina display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad Pro - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png"), "")); // App Store + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // App Store - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with Retina display + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight on devices with Retina display r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0)); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color())); for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); } } @@ -792,26 +792,27 @@ struct IconInfo { const char *actual_size_side; const char *scale; const char *unscaled_size; + const bool force_opaque; }; static const IconInfo icon_infos[] = { // Home screen on iPhone - { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60" }, - { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40" }, - { "icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60" }, + { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60", false }, + { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40", false }, + { "icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60", false }, // Home screen on iPad - { "icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76" }, - { "icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76" }, - { "icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5" }, + { "icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76", false }, + { "icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76", false }, + { "icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false }, // App Store - { "icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024" }, + { "icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true }, // Spotlight - { "icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40" }, - { "icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40" }, - { "icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40" } + { "icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40", false }, + { "icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40", false }, + { "icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40", false } }; Error EditorExportPlatformIOS::_export_icons(const Ref &p_preset, const String &p_iconset_dir) { @@ -831,14 +832,20 @@ Error EditorExportPlatformIOS::_export_icons(const Ref &p_pr Ref img = memnew(Image); Error err = ImageLoader::load_image(icon_path, img); if (err != OK) { - ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'."); + memdelete(da); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path)); + return ERR_UNCONFIGURED; + } + if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) { + memdelete(da); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key)); return ERR_UNCONFIGURED; } img->resize(side_size, side_size); err = img->save_png(p_iconset_dir + info.export_name); if (err) { - String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'."); - ERR_PRINT(err_str.utf8().get_data()); + memdelete(da); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path)); return err; } } else { @@ -846,11 +853,17 @@ Error EditorExportPlatformIOS::_export_icons(const Ref &p_pr Ref img = memnew(Image); Error err = ImageLoader::load_image(icon_path, img); if (err != OK) { - ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'."); + memdelete(da); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path)); + return ERR_UNCONFIGURED; + } + if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) { + memdelete(da); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key)); return ERR_UNCONFIGURED; } if (img->get_width() != side_size || img->get_height() != side_size) { - WARN_PRINT("Icon (" + String(info.preset_key) + "): '" + icon_path + "' has incorrect size (" + String::num_int64(img->get_width()) + "x" + String::num_int64(img->get_height()) + ") and was automatically resized to " + String::num_int64(side_size) + "x" + String::num_int64(side_size) + "."); + add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s): '%s' has incorrect size %s and was automatically resized to %s.", info.preset_key, icon_path, img->get_size(), Vector2(side_size, side_size))); img->resize(side_size, side_size); err = img->save_png(p_iconset_dir + info.export_name); } else { @@ -859,8 +872,7 @@ Error EditorExportPlatformIOS::_export_icons(const Ref &p_pr if (err) { memdelete(da); - String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'."); - ERR_PRINT(err_str.utf8().get_data()); + add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path)); return err; } } From b5e4a3c3e0e8f21974a3821dca4b1dc29e3f37e2 Mon Sep 17 00:00:00 2001 From: Perrier Mathis Date: Sat, 31 Jul 2021 23:17:24 +0200 Subject: [PATCH 42/48] Fix output port type mismatch for some VisualScript nodes (cherry picked from commit dcacecaed03ecee19b7cfc62c77327c941a9b68d) --- .../visual_script_builtin_funcs.cpp | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index d34dcb47be2b..9149518d944c 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -518,10 +518,10 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons t = Variant::REAL; } break; case MATH_ABS: { - t = Variant::NIL; + t = Variant::REAL; } break; case MATH_SIGN: { - t = Variant::NIL; + t = Variant::REAL; } break; case MATH_POW: case MATH_LOG: @@ -547,7 +547,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons case MATH_MOVE_TOWARD: case MATH_DECTIME: { t = Variant::REAL; - } break; case MATH_RANDOMIZE: { } break; @@ -584,34 +583,29 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons case LOGIC_MAX: case LOGIC_MIN: case LOGIC_CLAMP: { + t = Variant::REAL; } break; - case LOGIC_NEAREST_PO2: { - t = Variant::NIL; + t = Variant::INT; } break; case OBJ_WEAKREF: { t = Variant::OBJECT; - } break; case FUNC_FUNCREF: { t = Variant::OBJECT; - } break; case TYPE_CONVERT: { } break; case TEXT_ORD: case TYPE_OF: { t = Variant::INT; - } break; case TYPE_EXISTS: { t = Variant::BOOL; - } break; case TEXT_CHAR: case TEXT_STR: { t = Variant::STRING; - } break; case TEXT_PRINT: { } break; @@ -630,7 +624,6 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons } else { t = Variant::BOOL; } - } break; case BYTES_TO_VAR: { if (p_idx == 1) { @@ -1218,10 +1211,6 @@ class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance { VisualScriptBuiltinFunc::BuiltinFunc func; - //virtual int get_working_memory_size() const { return 0; } - //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } - //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; } - virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Variant::CallError &r_error, String &r_error_str) { VisualScriptBuiltinFunc::exec_func(func, p_inputs, p_outputs[0], r_error, r_error_str); return 0; From d92b2071894557e6ca5d6705c5f02b9665381d1d Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Fri, 19 Aug 2022 15:41:59 +0300 Subject: [PATCH 43/48] Backport fixes to documentation for paths, curves and navigation servers (cherry picked from commit 39f46613bb9ac3f63ac740507a7e9c1d8981f2dd) --- doc/classes/Curve2D.xml | 6 +++--- doc/classes/Curve3D.xml | 6 +++--- doc/classes/Line2D.xml | 20 ++++++++++---------- doc/classes/Navigation2DServer.xml | 2 +- doc/classes/NavigationServer.xml | 2 +- scene/2d/line_2d.cpp | 8 ++++---- scene/resources/curve.cpp | 4 ++-- servers/navigation_2d_server.cpp | 2 +- servers/navigation_server.cpp | 2 +- 9 files changed, 26 insertions(+), 26 deletions(-) diff --git a/doc/classes/Curve2D.xml b/doc/classes/Curve2D.xml index 73879f2c57f6..61029bb79831 100644 --- a/doc/classes/Curve2D.xml +++ b/doc/classes/Curve2D.xml @@ -15,10 +15,10 @@ - + - Adds a point to a curve at [code]position[/code] relative to the [Curve2D]'s position, with control points [code]in[/code] and [code]out[/code]. - If [code]at_position[/code] is given, the point is inserted before the point number [code]at_position[/code], moving that point (and every point after) after the inserted point. If [code]at_position[/code] is not given, or is an illegal value ([code]at_position <0[/code] or [code]at_position >= [method get_point_count][/code]), the point will be appended at the end of the point list. + Adds a point with the specified [code]position[/code] relative to the curve's own position, with control points [code]in[/code] and [code]out[/code]. Appends the new point at the end of the point list. + If [code]index[/code] is given, the new point is inserted before the existing point identified by index [code]index[/code]. Every existing point starting from [code]index[/code] is shifted further down the list of points. The index must be greater than or equal to [code]0[/code] and must not exceed the number of existing points in the line. See [method get_point_count]. diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml index 9cbaa9a52143..0c78081b6dbd 100644 --- a/doc/classes/Curve3D.xml +++ b/doc/classes/Curve3D.xml @@ -15,10 +15,10 @@ - + - Adds a point to a curve at [code]position[/code] relative to the [Curve3D]'s position, with control points [code]in[/code] and [code]out[/code]. - If [code]at_position[/code] is given, the point is inserted before the point number [code]at_position[/code], moving that point (and every point after) after the inserted point. If [code]at_position[/code] is not given, or is an illegal value ([code]at_position <0[/code] or [code]at_position >= [method get_point_count][/code]), the point will be appended at the end of the point list. + Adds a point with the specified [code]position[/code] relative to the curve's own position, with control points [code]in[/code] and [code]out[/code]. Appends the new point at the end of the point list. + If [code]index[/code] is given, the new point is inserted before the existing point identified by index [code]index[/code]. Every existing point starting from [code]index[/code] is shifted further down the list of points. The index must be greater than or equal to [code]0[/code] and must not exceed the number of existing points in the line. See [method get_point_count]. diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml index 05ad7387ab61..1c81b1c8ea18 100644 --- a/doc/classes/Line2D.xml +++ b/doc/classes/Line2D.xml @@ -15,10 +15,10 @@ - + - Adds a point at the [code]position[/code]. Appends the point at the end of the line. - If [code]at_position[/code] is given, the point is inserted before the point number [code]at_position[/code], moving that point (and every point after) after the inserted point. If [code]at_position[/code] is not given, or is an illegal value ([code]at_position < 0[/code] or [code]at_position >= [method get_point_count][/code]), the point will be appended at the end of the point list. + Adds a point with the specified [code]position[/code] relative to the line's own position. Appends the new point at the end of the point list. + If [code]index[/code] is given, the new point is inserted before the existing point identified by index [code]index[/code]. Every existing point starting from [code]index[/code] is shifted further down the list of points. The index must be greater than or equal to [code]0[/code] and must not exceed the number of existing points in the line. See [method get_point_count]. @@ -30,29 +30,29 @@ - Returns the Line2D's amount of points. + Returns the amount of points in the line. - + - Returns point [code]i[/code]'s position. + Returns the position of the point at index [code]index[/code]. - + - Removes the point at index [code]i[/code] from the line. + Removes the point at index [code]index[/code] from the line. - + - Overwrites the position in point [code]i[/code] with the supplied [code]position[/code]. + Overwrites the position of the point at index [code]index[/code] with the supplied [code]position[/code]. diff --git a/doc/classes/Navigation2DServer.xml b/doc/classes/Navigation2DServer.xml index 5b03f494e6e4..6d3359b0c240 100644 --- a/doc/classes/Navigation2DServer.xml +++ b/doc/classes/Navigation2DServer.xml @@ -213,7 +213,7 @@ - + Returns [code]true[/code] if the map is active. diff --git a/doc/classes/NavigationServer.xml b/doc/classes/NavigationServer.xml index 38a09c0486a9..a56626f968f7 100644 --- a/doc/classes/NavigationServer.xml +++ b/doc/classes/NavigationServer.xml @@ -237,7 +237,7 @@ - + Returns [code]true[/code] if the map is active. diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 1535b679124c..5985f70cb5fd 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -355,13 +355,13 @@ void Line2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_points", "points"), &Line2D::set_points); ClassDB::bind_method(D_METHOD("get_points"), &Line2D::get_points); - ClassDB::bind_method(D_METHOD("set_point_position", "i", "position"), &Line2D::set_point_position); - ClassDB::bind_method(D_METHOD("get_point_position", "i"), &Line2D::get_point_position); + ClassDB::bind_method(D_METHOD("set_point_position", "index", "position"), &Line2D::set_point_position); + ClassDB::bind_method(D_METHOD("get_point_position", "index"), &Line2D::get_point_position); ClassDB::bind_method(D_METHOD("get_point_count"), &Line2D::get_point_count); - ClassDB::bind_method(D_METHOD("add_point", "position", "at_position"), &Line2D::add_point, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("remove_point", "i"), &Line2D::remove_point); + ClassDB::bind_method(D_METHOD("add_point", "position", "index"), &Line2D::add_point, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("remove_point", "index"), &Line2D::remove_point); ClassDB::bind_method(D_METHOD("clear_points"), &Line2D::clear_points); diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index e0c84d05d59b..1c9de8b8b2f7 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -962,7 +962,7 @@ PoolVector2Array Curve2D::tessellate(int p_max_stages, float p_tolerance) const void Curve2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_count"), &Curve2D::get_point_count); - ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "index"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve2D::set_point_position); ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve2D::get_point_position); ClassDB::bind_method(D_METHOD("set_point_in", "idx", "position"), &Curve2D::set_point_in); @@ -1626,7 +1626,7 @@ PoolVector3Array Curve3D::tessellate(int p_max_stages, float p_tolerance) const void Curve3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_count"), &Curve3D::get_point_count); - ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "index"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve3D::set_point_position); ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve3D::get_point_position); ClassDB::bind_method(D_METHOD("set_point_tilt", "idx", "tilt"), &Curve3D::set_point_tilt); diff --git a/servers/navigation_2d_server.cpp b/servers/navigation_2d_server.cpp index b35814f1959c..074b92b46f0c 100644 --- a/servers/navigation_2d_server.cpp +++ b/servers/navigation_2d_server.cpp @@ -175,7 +175,7 @@ void Navigation2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("map_create"), &Navigation2DServer::map_create); ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &Navigation2DServer::map_set_active); - ClassDB::bind_method(D_METHOD("map_is_active", "nap"), &Navigation2DServer::map_is_active); + ClassDB::bind_method(D_METHOD("map_is_active", "map"), &Navigation2DServer::map_is_active); ClassDB::bind_method(D_METHOD("map_set_cell_size", "map", "cell_size"), &Navigation2DServer::map_set_cell_size); ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &Navigation2DServer::map_get_cell_size); ClassDB::bind_method(D_METHOD("map_set_cell_height", "map", "cell_height"), &Navigation2DServer::map_set_cell_size); diff --git a/servers/navigation_server.cpp b/servers/navigation_server.cpp index 582fcb536b32..9a585450089a 100644 --- a/servers/navigation_server.cpp +++ b/servers/navigation_server.cpp @@ -37,7 +37,7 @@ void NavigationServer::_bind_methods() { ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer::map_create); ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer::map_set_active); - ClassDB::bind_method(D_METHOD("map_is_active", "nap"), &NavigationServer::map_is_active); + ClassDB::bind_method(D_METHOD("map_is_active", "map"), &NavigationServer::map_is_active); ClassDB::bind_method(D_METHOD("map_set_up", "map", "up"), &NavigationServer::map_set_up); ClassDB::bind_method(D_METHOD("map_get_up", "map"), &NavigationServer::map_get_up); ClassDB::bind_method(D_METHOD("map_set_cell_size", "map", "cell_size"), &NavigationServer::map_set_cell_size); From 6a6d5952867959ad4712c9a7afbffcbdcb255c75 Mon Sep 17 00:00:00 2001 From: Jordan Schidlowsky Date: Tue, 23 Aug 2022 20:51:07 -0600 Subject: [PATCH 44/48] workaround for angle project issue 7245, safari, iOS (cherry picked from commit 1ed1a3067b5fad7a751842d4cfa8c0b16a325bc2) --- drivers/gles3/shaders/particles.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index 570e54e56dc5..b09e7faaaebd 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -211,7 +211,7 @@ VERTEX_SHADER_CODE xform = transpose(xform); - out_velocity_active.a = mix(0.0, 1.0, shader_active); + out_velocity_active.a = float(shader_active); out_xform_1 = xform[0]; out_xform_2 = xform[1]; From 08844b6143b4f6e52c66e679ff76d41e3e2affe4 Mon Sep 17 00:00:00 2001 From: Michael Alexsander Date: Sun, 21 Aug 2022 22:10:41 -0300 Subject: [PATCH 45/48] Fix `ItemList` selection visual when the scrollbar visibility changes (cherry picked from commit e298144a41338d80b5f0090ce8f28aef888c13dd) --- scene/gui/item_list.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 3ed6bdbe4a51..5c512bc05d03 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -754,11 +754,7 @@ void ItemList::_notification(int p_what) { scroll_bar->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -bg->get_margin(MARGIN_BOTTOM)); Size2 size = get_size(); - int width = size.width - bg->get_minimum_size().width; - if (scroll_bar->is_visible()) { - width -= mw; - } draw_style_box(bg, Rect2(Point2(), size)); @@ -917,6 +913,10 @@ void ItemList::_notification(int p_what) { shape_changed = false; } + if (scroll_bar->is_visible()) { + width -= mw; + } + //ensure_selected_visible needs to be checked before we draw the list. if (ensure_selected_visible && current >= 0 && current < items.size()) { Rect2 r = items[current].rect_cache; From 75a3af4d3ce5ccbdc82a0467ac333fab654205f1 Mon Sep 17 00:00:00 2001 From: bitsawer Date: Mon, 15 Aug 2022 20:27:29 +0300 Subject: [PATCH 46/48] Fix Windows list dir handle leak (cherry picked from commit 40325006b6c08c32b3db9dfd901e54d44b9d4dc3) --- drivers/windows/dir_access_windows.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 8de5908c1224..f9656f28012e 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -403,6 +403,8 @@ DirAccessWindows::DirAccessWindows() { } DirAccessWindows::~DirAccessWindows() { + list_dir_end(); + memdelete(p); } From 5296ab8cd60f4d7d91cdf79f30c01f522906bac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Fri, 26 Aug 2022 15:01:22 +0200 Subject: [PATCH 47/48] Determine ProjectSettings' resource path early (cherry picked from commit 89892e4f328f2e71f88ed62b2101e46866f32a02) --- core/project_settings.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/project_settings.cpp b/core/project_settings.cpp index f75b7c9d97a9..3f8390712860 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -358,6 +358,15 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) { * If nothing was found, error out. */ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, bool p_upwards, bool p_ignore_override) { + if (OS::get_singleton()->get_resource_dir() != "") { + // OS will call ProjectSettings->get_resource_path which will be empty if not overridden! + // If the OS would rather use a specific location, then it will not be empty. + resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/"); + if (resource_path != "" && resource_path[resource_path.length() - 1] == '/') { + resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end. + } + } + // If looking for files in a network client, use it directly if (FileAccessNetworkClient::get_singleton()) { @@ -439,13 +448,6 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b // (Only Android -when reading from pck- and iOS use this.) if (OS::get_singleton()->get_resource_dir() != "") { - // OS will call ProjectSettings->get_resource_path which will be empty if not overridden! - // If the OS would rather use a specific location, then it will not be empty. - resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/"); - if (resource_path != "" && resource_path[resource_path.length() - 1] == '/') { - resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end. - } - Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); if (err == OK && !p_ignore_override) { // Optional, we don't mind if it fails. From 60292006623833113e76725263a1af5615c8141c Mon Sep 17 00:00:00 2001 From: fabriceci Date: Thu, 25 Aug 2022 10:16:20 +0200 Subject: [PATCH 48/48] Hack as a hot fix for Bullet's collision margin issue (cherry picked from commit b3210c5cd6b6af960d0e79d7ad2e1afabdad10f1) --- scene/3d/physics_body.cpp | 7 ++++++- servers/physics_server.cpp | 3 +++ servers/physics_server.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 2f6b575ea3ed..6b951dfc9c2e 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -962,8 +962,13 @@ Ref KinematicBody::_move(const Vector3 &p_motion, bool p_inf bool collided = move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes, p_test_only); + // Ugly hack as a hot fix, 65b3200 fix an issue but cause a problem with Bullet that broke games using Bullet. + // The bug is something internal to Bullet, seems to be related to the Bullet’s margin. As not proper fix was found yet, + // this temporary solution solves the issue for games using Bullet. + bool is_bullet = PhysicsServerManager::current_server_id != 0; + // Don't report collision when the whole motion is done. - if (collided && col.collision_safe_fraction < 1) { + if (collided && (col.collision_safe_fraction < 1 || is_bullet)) { // Create a new instance when the cached reference is invalid or still in use in script. if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) { motion_cache.instance(); diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index b04a3fa36b44..3c0250893a3f 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -810,6 +810,7 @@ PhysicsServer::~PhysicsServer() { Vector PhysicsServerManager::physics_servers; int PhysicsServerManager::default_server_id = -1; +int PhysicsServerManager::current_server_id = -1; int PhysicsServerManager::default_server_priority = -1; const String PhysicsServerManager::setting_property_name(PNAME("physics/3d/physics_engine")); @@ -857,6 +858,7 @@ String PhysicsServerManager::get_server_name(int p_id) { PhysicsServer *PhysicsServerManager::new_default_server() { ERR_FAIL_COND_V(default_server_id == -1, nullptr); + current_server_id = default_server_id; return physics_servers[default_server_id].create_callback(); } @@ -865,6 +867,7 @@ PhysicsServer *PhysicsServerManager::new_server(const String &p_name) { if (id == -1) { return nullptr; } else { + current_server_id = id; return physics_servers[id].create_callback(); } } diff --git a/servers/physics_server.h b/servers/physics_server.h index c2c5d74844d7..fbbfdbb19210 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -807,6 +807,7 @@ class PhysicsServerManager { public: static const String setting_property_name; + static int current_server_id; private: static void on_servers_changed();