diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index 1b75a014c03..dedf1e0bc29 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -992,6 +992,10 @@ void Geometry::make_atlas(const Vector &p_rects, Vector &r_resu // 256x8192 atlas (won't work anywhere). ERR_FAIL_COND(p_rects.size() == 0); + for (int i = 0; i < p_rects.size(); i++) { + ERR_FAIL_COND(p_rects[i].width <= 0); + ERR_FAIL_COND(p_rects[i].height <= 0); + } Vector<_AtlasWorkRect> wrects; wrects.resize(p_rects.size()); diff --git a/core/os/thread.cpp b/core/os/thread.cpp index ff1c03ca8e7..58b29b98024 100644 --- a/core/os/thread.cpp +++ b/core/os/thread.cpp @@ -92,6 +92,7 @@ bool Thread::is_started() const { void Thread::wait_to_finish() { if (id != 0) { + ERR_FAIL_COND_MSG(id == get_caller_id(), "A Thread can't wait for itself to finish."); thread.join(); std::thread empty_thread; thread.swap(empty_thread); diff --git a/core/translation.cpp b/core/translation.cpp index 5d6c38c7f19..5a7a5bcc8a6 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -34,13 +34,14 @@ #include "core/os/os.h" #include "core/project_settings.h" -// ISO 639-1 language codes, with the addition of glibc locales with their -// regional identifiers. This list must match the language names (in English) -// of locale_names. +// ISO 639-1 language codes (and a couple of three-letter ISO 639-2 codes), +// with the addition of glibc locales with their regional identifiers. +// This list must match the language names (in English) of locale_names. // // References: // - https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes // - https://lh.2xlibre.net/locales/ +// - https://iso639-3.sil.org/ static const char *locale_list[] = { "aa", // Afar @@ -95,6 +96,7 @@ static const char *locale_list[] = { "bo", // Tibetan "bo_CN", // Tibetan (China) "bo_IN", // Tibetan (India) + "br", // Breton "br_FR", // Breton (France) "brx_IN", // Bodo (India) "bs_BA", // Bosnian (Bosnia and Herzegovina) @@ -196,6 +198,7 @@ static const char *locale_list[] = { "gd_GB", // Scottish Gaelic (United Kingdom) "gez_ER", // Geez (Eritrea) "gez_ET", // Geez (Ethiopia) + "gl", // Galician "gl_ES", // Galician (Spain) "gu_IN", // Gujarati (India) "gv_GB", // Manx (United Kingdom) @@ -268,6 +271,7 @@ static const char *locale_list[] = { "ml_IN", // Malayalam (India) "mni_IN", // Manipuri (India) "mn_MN", // Mongolian (Mongolia) + "mr", // Marathi "mr_IN", // Marathi (India) "ms", // Malay "ms_MY", // Malay (Malaysia) @@ -297,6 +301,7 @@ static const char *locale_list[] = { "om", // Oromo "om_ET", // Oromo (Ethiopia) "om_KE", // Oromo (Kenya) + "or", // Oriya "or_IN", // Oriya (India) "os_RU", // Ossetian (Russia) "pa_IN", // Panjabi (India) @@ -381,6 +386,8 @@ static const char *locale_list[] = { "tr_TR", // Turkish (Turkey) "ts_ZA", // Tsonga (South Africa) "tt_RU", // Tatar (Russia) + "tzm", // Central Atlas Tamazight + "tzm_MA", // Central Atlas Tamazight (Marrocos) "ug_CN", // Uighur (China) "uk", // Ukrainian "uk_UA", // Ukrainian (Ukraine) @@ -463,6 +470,7 @@ static const char *locale_names[] = { "Tibetan", "Tibetan (China)", "Tibetan (India)", + "Breton", "Breton (France)", "Bodo (India)", "Bosnian (Bosnia and Herzegovina)", @@ -564,6 +572,7 @@ static const char *locale_names[] = { "Scottish Gaelic (United Kingdom)", "Geez (Eritrea)", "Geez (Ethiopia)", + "Galician", "Galician (Spain)", "Gujarati (India)", "Manx (United Kingdom)", @@ -636,6 +645,7 @@ static const char *locale_names[] = { "Malayalam (India)", "Manipuri (India)", "Mongolian (Mongolia)", + "Marathi", "Marathi (India)", "Malay", "Malay (Malaysia)", @@ -665,6 +675,7 @@ static const char *locale_names[] = { "Oromo", "Oromo (Ethiopia)", "Oromo (Kenya)", + "Oriya", "Oriya (India)", "Ossetian (Russia)", "Panjabi (India)", @@ -749,6 +760,8 @@ static const char *locale_names[] = { "Turkish (Turkey)", "Tsonga (South Africa)", "Tatar (Russia)", + "Central Atlas Tamazight", + "Central Atlas Tamazight (Marrocos)", "Uighur (China)", "Ukrainian", "Ukrainian (Ukraine)", diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index 409fd7a23c0..682f2a473ee 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -48,6 +48,13 @@ The new item will be the [code]idx[/code]th child of parent, or it will be the last child if there are not enough siblings. + + + + + Edits the selected tree item as if it was clicked. The item must be set editable with [method TreeItem.set_editable]. Returns [code]true[/code] if the item could be edited. Fails if no item is selected. + + diff --git a/main/input_default.cpp b/main/input_default.cpp index fb73a7e2c4b..09142a188cb 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -97,12 +97,18 @@ bool InputDefault::is_joy_button_pressed(int p_device, int p_button) const { } bool InputDefault::is_action_pressed(const StringName &p_action) const { - +#ifdef DEBUG_ENABLED + bool has_action = InputMap::get_singleton()->has_action(p_action); + ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); +#endif return action_state.has(p_action) && action_state[p_action].pressed; } bool InputDefault::is_action_just_pressed(const StringName &p_action) const { - +#ifdef DEBUG_ENABLED + bool has_action = InputMap::get_singleton()->has_action(p_action); + ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); +#endif const Map::Element *E = action_state.find(p_action); if (!E) return false; @@ -115,7 +121,10 @@ bool InputDefault::is_action_just_pressed(const StringName &p_action) const { } bool InputDefault::is_action_just_released(const StringName &p_action) const { - +#ifdef DEBUG_ENABLED + bool has_action = InputMap::get_singleton()->has_action(p_action); + ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); +#endif const Map::Element *E = action_state.find(p_action); if (!E) return false; @@ -128,6 +137,10 @@ bool InputDefault::is_action_just_released(const StringName &p_action) const { } float InputDefault::get_action_strength(const StringName &p_action) const { +#ifdef DEBUG_ENABLED + bool has_action = InputMap::get_singleton()->has_action(p_action); + ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); +#endif const Map::Element *E = action_state.find(p_action); if (!E) return 0.0f; diff --git a/misc/dist/linux/org.godotengine.Godot.xml b/misc/dist/linux/org.godotengine.Godot.xml new file mode 100644 index 00000000000..2f647f71a64 --- /dev/null +++ b/misc/dist/linux/org.godotengine.Godot.xml @@ -0,0 +1,29 @@ + + + + Godot Engine project + + + + + + Godot Engine resource + + + + + + + Godot Engine scene + + + + + + + + GDScript script + + + + diff --git a/misc/dist/linux/x-godot-project.xml b/misc/dist/linux/x-godot-project.xml deleted file mode 100644 index 9f28bab2ae0..00000000000 --- a/misc/dist/linux/x-godot-project.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - Godot Engine project - - - - diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 0e3cc054104..e1f7ec26c9d 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -2916,6 +2916,7 @@ public: cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies. cmdline.push_back("-Pperform_zipalign=" + zipalign_flag); // argument to specify whether the build should be zipaligned. cmdline.push_back("-Pperform_signing=" + sign_flag); // argument to specify whether the build should be signed. + cmdline.push_back("-Pgodot_editor_version=" + String(VERSION_FULL_CONFIG)); // NOTE: The release keystore is not included in the verbose logging // to avoid accidentally leaking sensitive information when sharing verbose logs for troubleshooting. diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index 3e5444a886a..8e5dab349e4 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -29,6 +29,11 @@ + + + diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index 722cdae3016..604d63e2f3e 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -97,6 +97,8 @@ android { abiFilters export_abi_list } + manifestPlaceholders = [godotEditorVersion: getGodotEditorVersion()] + // Feel free to modify the application id to your own. applicationId getExportPackageName() versionCode getExportVersionCode() diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index 202b3c35c0c..06d1f4064e3 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -50,6 +50,55 @@ ext.getExportVersionName = { -> return versionName } +ext.getGodotEditorVersion = { -> + String editorVersion = project.hasProperty("godot_editor_version") ? project.property("godot_editor_version") : "" + if (editorVersion == null || editorVersion.isEmpty()) { + // Try the library version first + editorVersion = getGodotLibraryVersion() + + if (editorVersion.isEmpty()) { + // Fallback value. + editorVersion = "custom_build" + } + } + return editorVersion +} + +ext.getGodotLibraryVersion = { -> + // Attempt to read the version from the `version.py` file. + String libraryVersion = "" + + File versionFile = new File("../../../version.py") + if (versionFile.isFile()) { + List requiredKeys = ["major", "minor", "patch", "status", "module_config"] + def map = [:] + + List lines = versionFile.readLines() + for (String line in lines) { + String[] keyValue = line.split("=") + String key = keyValue[0].trim() + String value = keyValue[1].trim().replaceAll("\"", "") + + if (requiredKeys.contains(key)) { + if (!value.isEmpty()) { + map[key] = value + } + requiredKeys.remove(key) + } + } + + if (requiredKeys.empty) { + libraryVersion = map.values().join(".") + } + } + + if (libraryVersion.isEmpty()) { + // Fallback value in case we're unable to read the file. + libraryVersion = "custom_build" + } + return libraryVersion +} + final String PLUGIN_VALUE_SEPARATOR_REGEX = "\\|" // get the list of ABIs the project should be exported to diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle index 73c136ed0e2..ec02b0fc7a7 100644 --- a/platform/android/java/build.gradle +++ b/platform/android/java/build.gradle @@ -165,12 +165,6 @@ task cleanGodotTemplates(type: Delete) { // Delete the library generated AAR files delete("lib/build/outputs/aar") - // Delete the godotpayment libs directory contents - delete("plugins/godotpayment/libs") - - // Delete the generated godotpayment aar - delete("plugins/godotpayment/build/outputs/aar") - // Delete the app libs directory contents delete("app/libs") diff --git a/platform/android/java/lib/AndroidManifest.xml b/platform/android/java/lib/AndroidManifest.xml index 9c8722222d2..2c9f14fbfd3 100644 --- a/platform/android/java/lib/AndroidManifest.xml +++ b/platform/android/java/lib/AndroidManifest.xml @@ -7,6 +7,11 @@ + + + diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle index ca5153f7f6c..6fc9a11a08c 100644 --- a/platform/android/java/lib/build.gradle +++ b/platform/android/java/lib/build.gradle @@ -18,6 +18,8 @@ android { defaultConfig { minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk + + manifestPlaceholders = [godotLibraryVersion: getGodotLibraryVersion()] } compileOptions { diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 082ca36d5d2..4728f805eff 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -575,7 +575,9 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle) { + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + final Activity activity = getActivity(); Window window = activity.getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); @@ -687,24 +689,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) { // This is where you do set up to display the download - // progress (next step) + // progress (next step in onCreateView) mDownloaderClientStub = DownloaderClientMarshaller.CreateStub(this, GodotDownloaderService.class); - View downloadingExpansionView = - inflater.inflate(R.layout.downloading_expansion, container, false); - mPB = (ProgressBar)downloadingExpansionView.findViewById(R.id.progressBar); - mStatusText = (TextView)downloadingExpansionView.findViewById(R.id.statusText); - mProgressFraction = (TextView)downloadingExpansionView.findViewById(R.id.progressAsFraction); - mProgressPercent = (TextView)downloadingExpansionView.findViewById(R.id.progressAsPercentage); - mAverageSpeed = (TextView)downloadingExpansionView.findViewById(R.id.progressAverageSpeed); - mTimeRemaining = (TextView)downloadingExpansionView.findViewById(R.id.progressTimeRemaining); - mDashboard = downloadingExpansionView.findViewById(R.id.downloaderDashboard); - mCellMessage = downloadingExpansionView.findViewById(R.id.approveCellular); - mPauseButton = (Button)downloadingExpansionView.findViewById(R.id.pauseButton); - mWiFiSettingsButton = (Button)downloadingExpansionView.findViewById(R.id.wifiSettingsButton); - - return downloadingExpansionView; + return; } } catch (NameNotFoundException e) { // TODO Auto-generated catch block @@ -715,6 +704,27 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC mCurrentIntent = activity.getIntent(); initializeGodot(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle icicle) { + if (mDownloaderClientStub != null) { + View downloadingExpansionView = + inflater.inflate(R.layout.downloading_expansion, container, false); + mPB = (ProgressBar)downloadingExpansionView.findViewById(R.id.progressBar); + mStatusText = (TextView)downloadingExpansionView.findViewById(R.id.statusText); + mProgressFraction = (TextView)downloadingExpansionView.findViewById(R.id.progressAsFraction); + mProgressPercent = (TextView)downloadingExpansionView.findViewById(R.id.progressAsPercentage); + mAverageSpeed = (TextView)downloadingExpansionView.findViewById(R.id.progressAverageSpeed); + mTimeRemaining = (TextView)downloadingExpansionView.findViewById(R.id.progressTimeRemaining); + mDashboard = downloadingExpansionView.findViewById(R.id.downloaderDashboard); + mCellMessage = downloadingExpansionView.findViewById(R.id.approveCellular); + mPauseButton = (Button)downloadingExpansionView.findViewById(R.id.pauseButton); + mWiFiSettingsButton = (Button)downloadingExpansionView.findViewById(R.id.wifiSettingsButton); + + return downloadingExpansionView; + } + return containerLayout; } diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis index 90f0b55d0a4..d9842835bbd 100644 --- a/platform/windows/godot.natvis +++ b/platform/windows/godot.natvis @@ -10,6 +10,16 @@ + + + count + + count + data + + + + alloc ? (alloc->size / sizeof($T1)) : 0 diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 04335aa9a13..1b927723fcc 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -1342,6 +1342,9 @@ bool Tween::interpolate_property(Object *p_object, NodePath p_property, Variant return true; } + // Check that the target object is valid + ERR_FAIL_COND_V_MSG(p_object == nullptr, false, vformat("The Tween \"%s\"'s target node is `null`. Is the node reference correct?", get_name())); + // Get the property from the node path p_property = p_property.get_as_property_path(); @@ -1365,6 +1368,9 @@ bool Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_ return true; } + // Check that the target object is valid + ERR_FAIL_COND_V_MSG(p_object == nullptr, false, vformat("The Tween \"%s\"'s target node is `null`. Is the node reference correct?", get_name())); + // Convert any integers into REALs as they are better for interpolation if (p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); if (p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 332054f507d..829daedd25c 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -433,10 +433,6 @@ void Control::_resize(const Size2 &p_size) { _size_changed(); } -void Control::_clear_size_warning() { - data.size_warning = false; -} - //moved theme configuration here, so controls can set up even if still not inside active scene void Control::add_child_notify(Node *p_child) { @@ -488,9 +484,7 @@ void Control::_notification(int p_notification) { case NOTIFICATION_EXIT_TREE: { get_viewport()->_gui_remove_control(this); - } break; - case NOTIFICATION_READY: { - connect("ready", this, "_clear_size_warning", varray(), CONNECT_DEFERRED | CONNECT_ONESHOT); + } break; case NOTIFICATION_ENTER_CANVAS: { @@ -1835,11 +1829,6 @@ void Control::set_position(const Size2 &p_point, bool p_keep_margins) { } void Control::_set_size(const Size2 &p_size) { -#ifdef DEBUG_ENABLED - if (data.size_warning) { - WARN_PRINT("Adjusting the size of Control nodes before they are fully initialized is unreliable. Consider deferring it with set_deferred()."); - } -#endif set_size(p_size); } @@ -2964,8 +2953,6 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("_override_changed"), &Control::_override_changed); - ClassDB::bind_method(D_METHOD("_clear_size_warning"), &Control::_clear_size_warning); - BIND_VMETHOD(MethodInfo("_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_get_minimum_size")); diff --git a/scene/gui/control.h b/scene/gui/control.h index 1836e4bd1ab..3d47e7ce5ee 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -160,7 +160,6 @@ private: float rotation; Vector2 scale; Vector2 pivot_offset; - bool size_warning = true; bool pending_resize; @@ -225,7 +224,6 @@ private: void _change_notify_margins(); void _update_minimum_size(); - void _clear_size_warning(); void _update_scroll(); void _resize(const Size2 &p_size); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 3dbd8341770..64c6dc55236 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -4013,6 +4013,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_edited"), &Tree::get_edited); ClassDB::bind_method(D_METHOD("get_edited_column"), &Tree::get_edited_column); + ClassDB::bind_method(D_METHOD("edit_selected"), &Tree::edit_selected); ClassDB::bind_method(D_METHOD("get_custom_popup_rect"), &Tree::get_custom_popup_rect); ClassDB::bind_method(D_METHOD("get_item_area_rect", "item", "column"), &Tree::_get_item_rect, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_item_at_position", "position"), &Tree::get_item_at_position); diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp index 1ef2f62ca38..3e8422ed0d1 100644 --- a/scene/resources/mesh_data_tool.cpp +++ b/scene/resources/mesh_data_tool.cpp @@ -52,6 +52,28 @@ Error MeshDataTool::create_from_surface(const Ref &p_mesh, int p_surf int vcount = varray.size(); ERR_FAIL_COND_V(vcount == 0, ERR_INVALID_PARAMETER); + PoolVector indices; + + if (arrays[Mesh::ARRAY_INDEX].get_type() != Variant::NIL) { + + indices = arrays[Mesh::ARRAY_INDEX]; + } else { + //make code simpler + indices.resize(vcount); + PoolVector::Write iw = indices.write(); + for (int i = 0; i < vcount; i++) + iw[i] = i; + } + + int icount = indices.size(); + PoolVector::Read r = indices.read(); + + ERR_FAIL_COND_V(icount == 0, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(icount % 3, ERR_INVALID_PARAMETER); + for (int i = 0; i < icount; i++) { + ERR_FAIL_INDEX_V(r[i], vcount, ERR_INVALID_PARAMETER); + } + clear(); format = p_mesh->surface_get_format(p_surface); material = p_mesh->surface_get_material(p_surface); @@ -121,22 +143,6 @@ Error MeshDataTool::create_from_surface(const Ref &p_mesh, int p_surf vertices.write[i] = v; } - PoolVector indices; - - if (arrays[Mesh::ARRAY_INDEX].get_type() != Variant::NIL) { - - indices = arrays[Mesh::ARRAY_INDEX]; - } else { - //make code simpler - indices.resize(vcount); - PoolVector::Write iw = indices.write(); - for (int i = 0; i < vcount; i++) - iw[i] = i; - } - - int icount = indices.size(); - PoolVector::Read r = indices.read(); - Map edge_indices; for (int i = 0; i < icount; i += 3) {