summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-tidy1
-rw-r--r--.github/actions/godot-api-dump/action.yml1
-rw-r--r--.github/workflows/web_builds.yml2
-rw-r--r--core/debugger/engine_debugger.cpp2
-rw-r--r--core/extension/extension_api_dump.cpp2
-rw-r--r--core/io/ip_address.cpp2
-rw-r--r--core/math/static_raycaster.h2
-rw-r--r--core/object/object.cpp7
-rw-r--r--core/string/ustring.cpp436
-rw-r--r--core/string/ustring.h17
-rw-r--r--core/templates/command_queue_mt.h17
-rw-r--r--core/templates/simple_type.h21
-rw-r--r--core/variant/binder_common.h16
-rw-r--r--core/variant/variant_call.cpp27
-rw-r--r--core/variant/variant_internal.h2
-rw-r--r--doc/classes/@GlobalScope.xml1
-rw-r--r--doc/classes/DisplayServer.xml5
-rw-r--r--doc/classes/EditorPlugin.xml8
-rw-r--r--doc/classes/EditorSettings.xml3
-rw-r--r--doc/classes/GDExtensionManager.xml2
-rw-r--r--doc/classes/GPUParticles2D.xml2
-rw-r--r--doc/classes/Node.xml2
-rw-r--r--doc/classes/Object.xml2
-rw-r--r--doc/classes/String.xml12
-rw-r--r--doc/classes/StringName.xml10
-rw-r--r--doc/classes/TextEdit.xml2
-rw-r--r--doc/classes/TileMapLayer.xml2
-rw-r--r--doc/classes/Time.xml2
-rw-r--r--doc/classes/VisualShaderNodeFrame.xml2
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp2
-rw-r--r--drivers/egl/egl_manager.cpp2
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp7
-rw-r--r--drivers/gles3/shaders/effects/post.glsl2
-rw-r--r--drivers/gles3/storage/config.cpp2
-rw-r--r--drivers/gles3/storage/texture_storage.cpp4
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp4
-rw-r--r--editor/animation_track_editor.cpp2
-rw-r--r--editor/connections_dialog.cpp2
-rw-r--r--editor/create_dialog.cpp2
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.cpp2
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.h2
-rw-r--r--editor/debugger/editor_debugger_node.cpp2
-rw-r--r--editor/debugger/editor_file_server.cpp2
-rw-r--r--editor/dependency_editor.cpp4
-rw-r--r--editor/doc_tools.cpp18
-rw-r--r--editor/doc_tools.h2
-rw-r--r--editor/editor_dock_manager.cpp79
-rw-r--r--editor/editor_dock_manager.h11
-rw-r--r--editor/editor_file_system.cpp4
-rw-r--r--editor/editor_help_search.cpp8
-rw-r--r--editor/editor_inspector.cpp37
-rw-r--r--editor/editor_log.cpp2
-rw-r--r--editor/editor_node.cpp33
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_properties.cpp1
-rw-r--r--editor/editor_property_name_processor.cpp2
-rw-r--r--editor/editor_quick_open.cpp2
-rw-r--r--editor/editor_sectioned_inspector.cpp2
-rw-r--r--editor/editor_settings.cpp18
-rw-r--r--editor/editor_translation.cpp170
-rw-r--r--editor/editor_translation.h2
-rw-r--r--editor/filesystem_dock.cpp6
-rw-r--r--editor/import/3d/resource_importer_obj.cpp2
-rw-r--r--editor/import/3d/resource_importer_scene.cpp12
-rw-r--r--editor/input_event_configuration_dialog.cpp8
-rw-r--r--editor/plugins/editor_plugin.cpp6
-rw-r--r--editor/plugins/editor_plugin.h2
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp9
-rw-r--r--editor/plugins/script_editor_plugin.cpp4
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp2
-rw-r--r--editor/plugins/theme_editor_plugin.cpp4
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp2
-rw-r--r--editor/pot_generator.cpp7
-rw-r--r--editor/project_manager/project_list.cpp2
-rw-r--r--editor/property_selector.cpp8
-rw-r--r--editor/rename_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp2
-rw-r--r--gles3_builders.py2
-rw-r--r--main/main.cpp53
-rw-r--r--misc/dist/ios_xcode/godot_ios/en.lproj/InfoPlist.strings1
-rw-r--r--misc/error_suppressions/tsan.txt1
-rw-r--r--misc/extension_api_validation/4.2-stable.expected4
-rw-r--r--modules/csg/csg.cpp2
-rw-r--r--modules/enet/doc_classes/ENetConnection.xml2
-rw-r--r--modules/gdscript/README.md2
-rw-r--r--modules/gdscript/gdscript_editor.cpp1
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/cast_enum_to_int.gd1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd1
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg2
-rw-r--r--modules/gdscript/tests/scripts/lsp/lambdas.gd4
-rw-r--r--modules/gdscript/tests/scripts/lsp/local_variables.gd4
-rw-r--r--modules/gdscript/tests/scripts/lsp/properties.gd2
-rw-r--r--modules/gdscript/tests/scripts/lsp/scopes.gd10
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd1
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.gd1
-rw-r--r--modules/gdscript/tests/test_lsp.h2
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp2
-rw-r--r--modules/gltf/gltf_document.cpp2
-rw-r--r--modules/gltf/skin_tool.cpp24
-rw-r--r--modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp44
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets10
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ClassPartialModifier.GD0001.fixed.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ClassPartialModifier.GD0001.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj1
-rw-r--r--modules/mono/editor/bindings_generator.cpp6
-rw-r--r--modules/multiplayer/editor/replication_editor.cpp2
-rw-r--r--modules/openxr/action_map/openxr_action_map.cpp8
-rw-r--r--modules/openxr/action_map/openxr_action_set.cpp2
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile.cpp2
-rw-r--r--modules/openxr/doc_classes/OpenXRCompositionLayer.xml4
-rw-r--r--modules/openxr/extensions/openxr_composition_layer_extension.cpp3
-rw-r--r--modules/openxr/openxr_api.cpp2
-rw-r--r--modules/openxr/openxr_interface.cpp2
-rw-r--r--modules/openxr/scene/openxr_composition_layer.cpp95
-rw-r--r--modules/openxr/scene/openxr_composition_layer.h7
-rw-r--r--modules/openxr/scene/openxr_composition_layer_cylinder.cpp7
-rw-r--r--modules/openxr/scene/openxr_composition_layer_cylinder.h1
-rw-r--r--modules/openxr/scene/openxr_composition_layer_equirect.cpp7
-rw-r--r--modules/openxr/scene/openxr_composition_layer_equirect.h1
-rw-r--r--modules/openxr/scene/openxr_composition_layer_quad.cpp7
-rw-r--r--modules/openxr/scene/openxr_composition_layer_quad.h1
-rw-r--r--modules/regex/regex.cpp2
-rw-r--r--modules/text_server_adv/text_server_adv.h40
-rw-r--r--modules/text_server_fb/text_server_fb.h40
-rw-r--r--modules/upnp/upnp.cpp8
-rw-r--r--platform/android/export/export_plugin.cpp8
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotProjectManager.kt1
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java1
-rw-r--r--platform/android/java/scripts/publish-root.gradle1
-rw-r--r--platform/android/os_android.cpp4
-rw-r--r--platform/ios/export/export_plugin.cpp106
-rw-r--r--platform/linuxbsd/detect.py2
-rw-r--r--platform/linuxbsd/joypad_linux.cpp6
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp4
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.cpp10
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp2
-rw-r--r--platform/macos/display_server_macos.mm8
-rw-r--r--platform/macos/export/export_plugin.cpp46
-rw-r--r--platform/windows/display_server_windows.cpp14
-rw-r--r--platform/windows/export/export_plugin.cpp14
-rw-r--r--platform/windows/godot.natvis2
-rw-r--r--platform/windows/platform_windows_builders.py19
-rw-r--r--scene/3d/lightmapper.h2
-rw-r--r--scene/3d/skeleton_3d.cpp2
-rw-r--r--scene/gui/aspect_ratio_container.cpp13
-rw-r--r--scene/gui/box_container.cpp30
-rw-r--r--scene/gui/center_container.cpp14
-rw-r--r--scene/gui/container.cpp8
-rw-r--r--scene/gui/container.h2
-rw-r--r--scene/gui/flow_container.cpp23
-rw-r--r--scene/gui/graph_element.cpp13
-rw-r--r--scene/gui/graph_frame.cpp12
-rw-r--r--scene/gui/graph_node.cpp17
-rw-r--r--scene/gui/grid_container.cpp15
-rw-r--r--scene/gui/margin_container.cpp13
-rw-r--r--scene/gui/panel_container.cpp14
-rw-r--r--scene/gui/scroll_container.cpp19
-rw-r--r--scene/gui/split_container.cpp5
-rw-r--r--scene/gui/texture_progress_bar.cpp2
-rw-r--r--scene/gui/tree.cpp2
-rw-r--r--scene/main/http_request.cpp2
-rw-r--r--scene/main/node.cpp6
-rw-r--r--scene/resources/mesh.cpp2
-rw-r--r--servers/audio/audio_stream.cpp2
-rw-r--r--servers/physics_server_2d_wrap_mt.cpp44
-rw-r--r--servers/physics_server_2d_wrap_mt.h9
-rw-r--r--servers/physics_server_3d_wrap_mt.cpp44
-rw-r--r--servers/physics_server_3d_wrap_mt.h10
-rw-r--r--servers/rendering/renderer_rd/shaders/samplers_inc.glsl2
-rw-r--r--servers/rendering/renderer_viewport.cpp6
-rw-r--r--servers/rendering/renderer_viewport.h1
-rw-r--r--servers/rendering/rendering_device.cpp8
-rw-r--r--servers/rendering/rendering_server_default.cpp126
-rw-r--r--servers/rendering/rendering_server_default.h27
-rw-r--r--tests/core/math/test_math_funcs.h3
-rw-r--r--tests/core/object/test_class_db.h12
-rw-r--r--tests/core/string/test_string.h309
-rw-r--r--tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl1
-rw-r--r--tests/test_macros.h67
-rw-r--r--tests/test_main.cpp8
200 files changed, 1752 insertions, 984 deletions
diff --git a/.clang-tidy b/.clang-tidy
index 02aa95c709..aa5a269eac 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -43,4 +43,3 @@ CheckOptions:
- key: readability-braces-around-statements.ShortStatementLines
value: '0'
...
-
diff --git a/.github/actions/godot-api-dump/action.yml b/.github/actions/godot-api-dump/action.yml
index 47b675ae99..7730688661 100644
--- a/.github/actions/godot-api-dump/action.yml
+++ b/.github/actions/godot-api-dump/action.yml
@@ -21,4 +21,3 @@ runs:
with:
name: 'godot-api-dump'
path: './godot-api/*'
-
diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml
index 47f7e4d458..cfa1571d1f 100644
--- a/.github/workflows/web_builds.yml
+++ b/.github/workflows/web_builds.yml
@@ -7,7 +7,7 @@ env:
# Used for the cache key. Add version suffix to force clean build.
GODOT_BASE_BRANCH: master
SCONSFLAGS: verbose=yes warnings=extra werror=yes debug_symbols=no
- EM_VERSION: 3.1.39
+ EM_VERSION: 3.1.59
EM_CACHE_FOLDER: "emsdk-cache"
concurrency:
diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp
index a7655c874a..97a020e4c3 100644
--- a/core/debugger/engine_debugger.cpp
+++ b/core/debugger/engine_debugger.cpp
@@ -137,7 +137,7 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co
script_debugger = memnew(ScriptDebugger);
// Tell the OS that we want to handle termination signals.
OS::get_singleton()->initialize_debugging();
- } else if (p_uri.find("://") >= 0) {
+ } else if (p_uri.contains("://")) {
const String proto = p_uri.substr(0, p_uri.find("://") + 3);
if (!protocols.has(proto)) {
return;
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 1c9b4dc3e8..848b6f3886 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -1201,7 +1201,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api(bool p_include_docs) {
if (F.name.begins_with("_")) {
continue; //hidden property
}
- if (F.name.find("/") >= 0) {
+ if (F.name.contains("/")) {
// Ignore properties with '/' (slash) in the name. These are only meant for use in the inspector.
continue;
}
diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp
index ce74bb36d6..a93876a2b5 100644
--- a/core/io/ip_address.cpp
+++ b/core/io/ip_address.cpp
@@ -202,7 +202,7 @@ IPAddress::IPAddress(const String &p_string) {
// Wildcard (not a valid IP)
wildcard = true;
- } else if (p_string.find(":") >= 0) {
+ } else if (p_string.contains(":")) {
// IPv6
_parse_ipv6(p_string);
valid = true;
diff --git a/core/math/static_raycaster.h b/core/math/static_raycaster.h
index c53868e12d..74e4b75163 100644
--- a/core/math/static_raycaster.h
+++ b/core/math/static_raycaster.h
@@ -49,7 +49,7 @@ protected:
static StaticRaycaster *(*create_function)();
public:
- // compatible with embree3 rays
+ // Compatible with embree4 rays.
struct __aligned(16) Ray {
const static unsigned int INVALID_GEOMETRY_ID = ((unsigned int)-1); // from rtcore_common.h
diff --git a/core/object/object.cpp b/core/object/object.cpp
index ab89f96a0d..dfc8e2a29a 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -2307,9 +2307,9 @@ void ObjectDB::setup() {
}
void ObjectDB::cleanup() {
- if (slot_count > 0) {
- spin_lock.lock();
+ spin_lock.lock();
+ if (slot_count > 0) {
WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details).");
if (OS::get_singleton()->is_stdout_verbose()) {
// Ensure calling the native classes because if a leaked instance has a script
@@ -2340,10 +2340,11 @@ void ObjectDB::cleanup() {
}
print_line("Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`).");
}
- spin_lock.unlock();
}
if (object_slots) {
memfree(object_slots);
}
+
+ spin_lock.unlock();
}
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 2b62b72a51..3d37e17ef8 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -1184,6 +1184,26 @@ int String::get_slice_count(const String &p_splitter) const {
return slices;
}
+int String::get_slice_count(const char *p_splitter) const {
+ if (is_empty()) {
+ return 0;
+ }
+ if (p_splitter == nullptr || *p_splitter == '\0') {
+ return 0;
+ }
+
+ int pos = 0;
+ int slices = 1;
+ int splitter_length = strlen(p_splitter);
+
+ while ((pos = find(p_splitter, pos)) >= 0) {
+ slices++;
+ pos += splitter_length;
+ }
+
+ return slices;
+}
+
String String::get_slice(const String &p_splitter, int p_slice) const {
if (is_empty() || p_splitter.is_empty()) {
return "";
@@ -1224,6 +1244,47 @@ String String::get_slice(const String &p_splitter, int p_slice) const {
return ""; //no find!
}
+String String::get_slice(const char *p_splitter, int p_slice) const {
+ if (is_empty() || p_splitter == nullptr || *p_splitter == '\0') {
+ return "";
+ }
+
+ int pos = 0;
+ int prev_pos = 0;
+ //int slices=1;
+ if (p_slice < 0) {
+ return "";
+ }
+ if (find(p_splitter) == -1) {
+ return *this;
+ }
+
+ int i = 0;
+ int splitter_length = strlen(p_splitter);
+ while (true) {
+ pos = find(p_splitter, pos);
+ if (pos == -1) {
+ pos = length(); //reached end
+ }
+
+ int from = prev_pos;
+ //int to=pos;
+
+ if (p_slice == i) {
+ return substr(from, pos - from);
+ }
+
+ if (pos == length()) { //reached end and no find
+ break;
+ }
+ pos += splitter_length;
+ prev_pos = pos;
+ i++;
+ }
+
+ return ""; //no find!
+}
+
String String::get_slicec(char32_t p_splitter, int p_slice) const {
if (is_empty()) {
return String();
@@ -1338,6 +1399,54 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p
return ret;
}
+Vector<String> String::split(const char *p_splitter, bool p_allow_empty, int p_maxsplit) const {
+ Vector<String> ret;
+
+ if (is_empty()) {
+ if (p_allow_empty) {
+ ret.push_back("");
+ }
+ return ret;
+ }
+
+ int from = 0;
+ int len = length();
+
+ while (true) {
+ int end;
+ if (p_splitter == nullptr || *p_splitter == '\0') {
+ end = from + 1;
+ } else {
+ end = find(p_splitter, from);
+ if (end < 0) {
+ end = len;
+ }
+ }
+ if (p_allow_empty || (end > from)) {
+ if (p_maxsplit <= 0) {
+ ret.push_back(substr(from, end - from));
+ } else {
+ // Put rest of the string and leave cycle.
+ if (p_maxsplit == ret.size()) {
+ ret.push_back(substr(from, len));
+ break;
+ }
+
+ // Otherwise, push items until positive limit is reached.
+ ret.push_back(substr(from, end - from));
+ }
+ }
+
+ if (end == len) {
+ break;
+ }
+
+ from = end + strlen(p_splitter);
+ }
+
+ return ret;
+}
+
Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int p_maxsplit) const {
Vector<String> ret;
const int len = length();
@@ -1380,6 +1489,49 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
return ret;
}
+Vector<String> String::rsplit(const char *p_splitter, bool p_allow_empty, int p_maxsplit) const {
+ Vector<String> ret;
+ const int len = length();
+ const int splitter_length = strlen(p_splitter);
+ int remaining_len = len;
+
+ while (true) {
+ if (remaining_len < splitter_length || (p_maxsplit > 0 && p_maxsplit == ret.size())) {
+ // no room for another splitter or hit max splits, push what's left and we're done
+ if (p_allow_empty || remaining_len > 0) {
+ ret.push_back(substr(0, remaining_len));
+ }
+ break;
+ }
+
+ int left_edge;
+ if (p_splitter == nullptr || *p_splitter == '\0') {
+ left_edge = remaining_len - 1;
+ if (left_edge == 0) {
+ left_edge--; // Skip to the < 0 condition.
+ }
+ } else {
+ left_edge = rfind(p_splitter, remaining_len - splitter_length);
+ }
+
+ if (left_edge < 0) {
+ // no more splitters, we're done
+ ret.push_back(substr(0, remaining_len));
+ break;
+ }
+
+ int substr_start = left_edge + splitter_length;
+ if (p_allow_empty || substr_start < remaining_len) {
+ ret.push_back(substr(substr_start, remaining_len - substr_start));
+ }
+
+ remaining_len = left_edge;
+ }
+
+ ret.reverse();
+ return ret;
+}
+
Vector<double> String::split_floats(const String &p_splitter, bool p_allow_empty) const {
Vector<double> ret;
int from = 0;
@@ -3087,23 +3239,20 @@ int String::find(const String &p_str, int p_from) const {
}
int String::find(const char *p_str, int p_from) const {
- if (p_from < 0) {
+ if (p_from < 0 || !p_str) {
return -1;
}
+ const int src_len = strlen(p_str);
+
const int len = length();
- if (len == 0) {
+ if (len == 0 || src_len == 0) {
return -1; // won't find anything!
}
const char32_t *src = get_data();
- int src_len = 0;
- while (p_str[src_len] != '\0') {
- src_len++;
- }
-
if (src_len == 1) {
const char32_t needle = p_str[0];
@@ -3238,6 +3387,46 @@ int String::findn(const String &p_str, int p_from) const {
return -1;
}
+int String::findn(const char *p_str, int p_from) const {
+ if (p_from < 0) {
+ return -1;
+ }
+
+ int src_len = strlen(p_str);
+
+ if (src_len == 0 || length() == 0) {
+ return -1; // won't find anything!
+ }
+
+ const char32_t *srcd = get_data();
+
+ for (int i = p_from; i <= (length() - src_len); i++) {
+ bool found = true;
+ for (int j = 0; j < src_len; j++) {
+ int read_pos = i + j;
+
+ if (read_pos >= length()) {
+ ERR_PRINT("read_pos>=length()");
+ return -1;
+ }
+
+ char32_t src = _find_lower(srcd[read_pos]);
+ char32_t dst = _find_lower(p_str[j]);
+
+ if (src != dst) {
+ found = false;
+ break;
+ }
+ }
+
+ if (found) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
int String::rfind(const String &p_str, int p_from) const {
// establish a limit
int limit = length() - p_str.length();
@@ -3285,6 +3474,57 @@ int String::rfind(const String &p_str, int p_from) const {
return -1;
}
+int String::rfind(const char *p_str, int p_from) const {
+ const int source_length = length();
+ int substring_length = strlen(p_str);
+
+ if (source_length == 0 || substring_length == 0) {
+ return -1; // won't find anything!
+ }
+
+ // establish a limit
+ int limit = length() - substring_length;
+ if (limit < 0) {
+ return -1;
+ }
+
+ // establish a starting point
+ int starting_point;
+ if (p_from < 0) {
+ starting_point = limit;
+ } else if (p_from > limit) {
+ starting_point = limit;
+ } else {
+ starting_point = p_from;
+ }
+
+ const char32_t *source = get_data();
+
+ for (int i = starting_point; i >= 0; i--) {
+ bool found = true;
+ for (int j = 0; j < substring_length; j++) {
+ int read_pos = i + j;
+
+ if (read_pos >= source_length) {
+ ERR_PRINT("read_pos>=source_length");
+ return -1;
+ }
+
+ const char32_t key_needle = p_str[j];
+ if (source[read_pos] != key_needle) {
+ found = false;
+ break;
+ }
+ }
+
+ if (found) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
int String::rfindn(const String &p_str, int p_from) const {
// establish a limit
int limit = length() - p_str.length();
@@ -3335,6 +3575,60 @@ int String::rfindn(const String &p_str, int p_from) const {
return -1;
}
+int String::rfindn(const char *p_str, int p_from) const {
+ const int source_length = length();
+ int substring_length = strlen(p_str);
+
+ if (source_length == 0 || substring_length == 0) {
+ return -1; // won't find anything!
+ }
+
+ // establish a limit
+ int limit = length() - substring_length;
+ if (limit < 0) {
+ return -1;
+ }
+
+ // establish a starting point
+ int starting_point;
+ if (p_from < 0) {
+ starting_point = limit;
+ } else if (p_from > limit) {
+ starting_point = limit;
+ } else {
+ starting_point = p_from;
+ }
+
+ const char32_t *source = get_data();
+
+ for (int i = starting_point; i >= 0; i--) {
+ bool found = true;
+ for (int j = 0; j < substring_length; j++) {
+ int read_pos = i + j;
+
+ if (read_pos >= source_length) {
+ ERR_PRINT("read_pos>=source_length");
+ return -1;
+ }
+
+ const char32_t key_needle = p_str[j];
+ int srcc = _find_lower(source[read_pos]);
+ int keyc = _find_lower(key_needle);
+
+ if (srcc != keyc) {
+ found = false;
+ break;
+ }
+ }
+
+ if (found) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
bool String::ends_with(const String &p_string) const {
int l = p_string.length();
if (l > length()) {
@@ -3357,6 +3651,31 @@ bool String::ends_with(const String &p_string) const {
return true;
}
+bool String::ends_with(const char *p_string) const {
+ if (!p_string) {
+ return false;
+ }
+
+ int l = strlen(p_string);
+ if (l > length()) {
+ return false;
+ }
+
+ if (l == 0) {
+ return true;
+ }
+
+ const char32_t *s = &operator[](length() - l);
+
+ for (int i = 0; i < l; i++) {
+ if (static_cast<char32_t>(p_string[i]) != s[i]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
bool String::begins_with(const String &p_string) const {
int l = p_string.length();
if (l > length()) {
@@ -3380,11 +3699,11 @@ bool String::begins_with(const String &p_string) const {
}
bool String::begins_with(const char *p_string) const {
- int l = length();
if (!p_string) {
return false;
}
+ int l = length();
if (l == 0) {
return *p_string == 0;
}
@@ -3456,14 +3775,61 @@ int String::_count(const String &p_string, int p_from, int p_to, bool p_case_ins
return c;
}
+int String::_count(const char *p_string, int p_from, int p_to, bool p_case_insensitive) const {
+ int substring_length = strlen(p_string);
+ if (substring_length == 0) {
+ return 0;
+ }
+ const int source_length = length();
+
+ if (source_length < substring_length) {
+ return 0;
+ }
+ String str;
+ int search_limit = p_to;
+ if (p_from >= 0 && p_to >= 0) {
+ if (p_to == 0) {
+ search_limit = source_length;
+ } else if (p_from >= p_to) {
+ return 0;
+ }
+ if (p_from == 0 && search_limit == source_length) {
+ str = String();
+ str.copy_from_unchecked(&get_data()[0], source_length);
+ } else {
+ str = substr(p_from, search_limit - p_from);
+ }
+ } else {
+ return 0;
+ }
+ int c = 0;
+ int idx = -1;
+ do {
+ idx = p_case_insensitive ? str.findn(p_string) : str.find(p_string);
+ if (idx != -1) {
+ str = str.substr(idx + substring_length, str.length() - substring_length);
+ ++c;
+ }
+ } while (idx != -1);
+ return c;
+}
+
int String::count(const String &p_string, int p_from, int p_to) const {
return _count(p_string, p_from, p_to, false);
}
+int String::count(const char *p_string, int p_from, int p_to) const {
+ return _count(p_string, p_from, p_to, false);
+}
+
int String::countn(const String &p_string, int p_from, int p_to) const {
return _count(p_string, p_from, p_to, true);
}
+int String::countn(const char *p_string, int p_from, int p_to) const {
+ return _count(p_string, p_from, p_to, true);
+}
+
bool String::_base_is_subsequence_of(const String &p_string, bool case_insensitive) const {
int len = length();
if (len == 0) {
@@ -3598,7 +3964,7 @@ String String::format(const Variant &values, const String &placeholder) const {
Variant v_val = values_arr[i];
String val = v_val;
- if (placeholder.find("_") > -1) {
+ if (placeholder.contains("_")) {
new_string = new_string.replace(placeholder.replace("_", i_as_str), val);
} else {
new_string = new_string.replace_first(placeholder, val);
@@ -3673,6 +4039,16 @@ String String::replace_first(const String &p_key, const String &p_with) const {
return *this;
}
+String String::replace_first(const char *p_key, const char *p_with) const {
+ int pos = find(p_key);
+ if (pos >= 0) {
+ int substring_length = strlen(p_key);
+ return substr(0, pos) + p_with + substr(pos + substring_length, length());
+ }
+
+ return *this;
+}
+
String String::replacen(const String &p_key, const String &p_with) const {
String new_string;
int search_from = 0;
@@ -3692,6 +4068,31 @@ String String::replacen(const String &p_key, const String &p_with) const {
return new_string;
}
+String String::replacen(const char *p_key, const char *p_with) const {
+ String new_string;
+ int search_from = 0;
+ int result = 0;
+ int substring_length = strlen(p_key);
+
+ if (substring_length == 0) {
+ return *this; // there's nothing to match or substitute
+ }
+
+ while ((result = findn(p_key, search_from)) >= 0) {
+ new_string += substr(search_from, result - search_from);
+ new_string += p_with;
+ search_from = result + substring_length;
+ }
+
+ if (search_from == 0) {
+ return *this;
+ }
+
+ new_string += substr(search_from, length() - search_from);
+
+ return new_string;
+}
+
String String::repeat(int p_count) const {
ERR_FAIL_COND_V_MSG(p_count < 0, "", "Parameter count should be a positive number.");
@@ -4420,6 +4821,15 @@ String String::trim_prefix(const String &p_prefix) const {
return s;
}
+String String::trim_prefix(const char *p_prefix) const {
+ String s = *this;
+ if (s.begins_with(p_prefix)) {
+ int prefix_length = strlen(p_prefix);
+ return s.substr(prefix_length, s.length() - prefix_length);
+ }
+ return s;
+}
+
String String::trim_suffix(const String &p_suffix) const {
String s = *this;
if (s.ends_with(p_suffix)) {
@@ -4428,6 +4838,14 @@ String String::trim_suffix(const String &p_suffix) const {
return s;
}
+String String::trim_suffix(const char *p_suffix) const {
+ String s = *this;
+ if (s.ends_with(p_suffix)) {
+ return s.substr(0, s.length() - strlen(p_suffix));
+ }
+ return s;
+}
+
bool String::is_valid_int() const {
int len = length();
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 693df6dcba..9df2d56e80 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -198,6 +198,7 @@ class String {
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const;
+ int _count(const char *p_string, int p_from, int p_to, bool p_case_insensitive) const;
String _camelcase_to_underscore() const;
public:
@@ -288,14 +289,18 @@ public:
int find(const char *p_str, int p_from = 0) const; ///< return <0 if failed
int find_char(const char32_t &p_char, int p_from = 0) const; ///< return <0 if failed
int findn(const String &p_str, int p_from = 0) const; ///< return <0 if failed, case insensitive
+ int findn(const char *p_str, int p_from = 0) const; ///< return <0 if failed
int rfind(const String &p_str, int p_from = -1) const; ///< return <0 if failed
+ int rfind(const char *p_str, int p_from = -1) const; ///< return <0 if failed
int rfindn(const String &p_str, int p_from = -1) const; ///< return <0 if failed, case insensitive
+ int rfindn(const char *p_str, int p_from = -1) const; ///< return <0 if failed
int findmk(const Vector<String> &p_keys, int p_from = 0, int *r_key = nullptr) const; ///< return <0 if failed
bool match(const String &p_wildcard) const;
bool matchn(const String &p_wildcard) const;
bool begins_with(const String &p_string) const;
bool begins_with(const char *p_string) const;
bool ends_with(const String &p_string) const;
+ bool ends_with(const char *p_string) const;
bool is_enclosed_in(const String &p_string) const;
bool is_subsequence_of(const String &p_string) const;
bool is_subsequence_ofn(const String &p_string) const;
@@ -304,9 +309,11 @@ public:
float similarity(const String &p_string) const;
String format(const Variant &values, const String &placeholder = "{_}") const;
String replace_first(const String &p_key, const String &p_with) const;
+ String replace_first(const char *p_key, const char *p_with) const;
String replace(const String &p_key, const String &p_with) const;
String replace(const char *p_key, const char *p_with) const;
String replacen(const String &p_key, const String &p_with) const;
+ String replacen(const char *p_key, const char *p_with) const;
String repeat(int p_count) const;
String reverse() const;
String insert(int p_at_pos, const String &p_string) const;
@@ -314,7 +321,9 @@ public:
String pad_decimals(int p_digits) const;
String pad_zeros(int p_digits) const;
String trim_prefix(const String &p_prefix) const;
+ String trim_prefix(const char *p_prefix) const;
String trim_suffix(const String &p_suffix) const;
+ String trim_suffix(const char *p_suffix) const;
String lpad(int min_length, const String &character = " ") const;
String rpad(int min_length, const String &character = " ") const;
String sprintf(const Array &values, bool *error) const;
@@ -353,11 +362,15 @@ public:
String get_with_code_lines() const;
int get_slice_count(const String &p_splitter) const;
+ int get_slice_count(const char *p_splitter) const;
String get_slice(const String &p_splitter, int p_slice) const;
+ String get_slice(const char *p_splitter, int p_slice) const;
String get_slicec(char32_t p_splitter, int p_slice) const;
Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
+ Vector<String> split(const char *p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
Vector<String> rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
+ Vector<String> rsplit(const char *p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
Vector<String> split_spaces() const;
Vector<double> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
@@ -372,7 +385,9 @@ public:
String to_lower() const;
int count(const String &p_string, int p_from = 0, int p_to = 0) const;
+ int count(const char *p_string, int p_from = 0, int p_to = 0) const;
int countn(const String &p_string, int p_from = 0, int p_to = 0) const;
+ int countn(const char *p_string, int p_from = 0, int p_to = 0) const;
String left(int p_len) const;
String right(int p_len) const;
@@ -414,6 +429,8 @@ public:
_FORCE_INLINE_ bool is_empty() const { return length() == 0; }
_FORCE_INLINE_ bool contains(const char *p_str) const { return find(p_str) != -1; }
_FORCE_INLINE_ bool contains(const String &p_str) const { return find(p_str) != -1; }
+ _FORCE_INLINE_ bool containsn(const char *p_str) const { return findn(p_str) != -1; }
+ _FORCE_INLINE_ bool containsn(const String &p_str) const { return findn(p_str) != -1; }
// path functions
bool is_absolute_path() const;
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index c149861467..9f9b77d9d0 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -208,7 +208,7 @@
#define ARG(N) p##N
#define PARAM(N) P##N p##N
#define TYPE_PARAM(N) typename P##N
-#define PARAM_DECL(N) typename GetSimpleTypeT<P##N>::type_t p##N
+#define PARAM_DECL(N) GetSimpleTypeT<P##N> p##N
#define DECL_CMD(N) \
template <typename T, typename M COMMA(N) COMMA_SEP_LIST(TYPE_PARAM, N)> \
@@ -302,7 +302,7 @@ class CommandQueueMT {
struct CommandBase {
bool sync = false;
virtual void call() = 0;
- virtual ~CommandBase() = default; // Won't be called.
+ virtual ~CommandBase() = default;
};
struct SyncCommand : public CommandBase {
@@ -368,6 +368,10 @@ class CommandQueueMT {
sync_cond_var.notify_all();
}
+ // If the command involved reallocating the buffer, the address may have changed.
+ cmd = reinterpret_cast<CommandBase *>(&command_mem[flush_read_ptr]);
+ cmd->~CommandBase();
+
flush_read_ptr += size;
}
WorkerThreadPool::thread_exit_command_queue_mt_flush();
@@ -384,6 +388,8 @@ class CommandQueueMT {
} while (sync_head != sync_head_goal); // Can't use lower-than because of wraparound.
}
+ void _no_op() {}
+
public:
void lock();
void unlock();
@@ -405,10 +411,15 @@ public:
_flush();
}
}
+
void flush_all() {
_flush();
}
+ void sync() {
+ push_and_sync(this, &CommandQueueMT::_no_op);
+ }
+
void wait_and_flush() {
ERR_FAIL_COND(pump_task_id == WorkerThreadPool::INVALID_TASK_ID);
WorkerThreadPool::get_singleton()->wait_for_task_completion(pump_task_id);
@@ -416,7 +427,9 @@ public:
}
void set_pump_task_id(WorkerThreadPool::TaskID p_task_id) {
+ lock();
pump_task_id = p_task_id;
+ unlock();
}
CommandQueueMT();
diff --git a/core/templates/simple_type.h b/core/templates/simple_type.h
index b2ae0110e2..197115ddb9 100644
--- a/core/templates/simple_type.h
+++ b/core/templates/simple_type.h
@@ -31,26 +31,9 @@
#ifndef SIMPLE_TYPE_H
#define SIMPLE_TYPE_H
-/* Batch of specializations to obtain the actual simple type */
+#include <type_traits>
template <typename T>
-struct GetSimpleTypeT {
- typedef T type_t;
-};
-
-template <typename T>
-struct GetSimpleTypeT<T &> {
- typedef T type_t;
-};
-
-template <typename T>
-struct GetSimpleTypeT<T const> {
- typedef T type_t;
-};
-
-template <typename T>
-struct GetSimpleTypeT<T const &> {
- typedef T type_t;
-};
+using GetSimpleTypeT = typename std::remove_cv_t<std::remove_reference_t<T>>;
#endif // SIMPLE_TYPE_H
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index 0fe4518b0f..61b90e2a26 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -362,42 +362,42 @@ void call_with_ptr_args_static_method_helper(void (*p_method)(P...), const void
template <typename T, typename... P, size_t... Is>
void call_with_validated_variant_args_helper(T *p_instance, void (T::*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
- (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+ (p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
}
template <typename T, typename... P, size_t... Is>
void call_with_validated_variant_argsc_helper(T *p_instance, void (T::*p_method)(P...) const, const Variant **p_args, IndexSequence<Is...>) {
- (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+ (p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
}
template <typename T, typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_ret_helper(T *p_instance, R (T::*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
- VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+ VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
}
template <typename T, typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_retc_helper(T *p_instance, R (T::*p_method)(P...) const, const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
- VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+ VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, (p_instance->*p_method)((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
}
template <typename T, typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_static_retc_helper(T *p_instance, R (*p_method)(T *, P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
- VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+ VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, p_method(p_instance, (VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
}
template <typename T, typename... P, size_t... Is>
void call_with_validated_variant_args_static_helper(T *p_instance, void (*p_method)(T *, P...), const Variant **p_args, IndexSequence<Is...>) {
- p_method(p_instance, (VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+ p_method(p_instance, (VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
}
template <typename R, typename... P, size_t... Is>
void call_with_validated_variant_args_static_method_ret_helper(R (*p_method)(P...), const Variant **p_args, Variant *r_ret, IndexSequence<Is...>) {
- VariantInternalAccessor<typename GetSimpleTypeT<R>::type_t>::set(r_ret, p_method((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...));
+ VariantInternalAccessor<GetSimpleTypeT<R>>::set(r_ret, p_method((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...));
}
template <typename... P, size_t... Is>
void call_with_validated_variant_args_static_method_helper(void (*p_method)(P...), const Variant **p_args, IndexSequence<Is...>) {
- p_method((VariantInternalAccessor<typename GetSimpleTypeT<P>::type_t>::get(p_args[Is]))...);
+ p_method((VariantInternalAccessor<GetSimpleTypeT<P>>::get(p_args[Is]))...);
}
template <typename T, typename... P>
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 7012bf698d..9b7777f480 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1648,19 +1648,19 @@ static void _register_variant_builtin_methods() {
bind_string_method(filenocasecmp_to, sarray("to"), varray());
bind_string_method(length, sarray(), varray());
bind_string_method(substr, sarray("from", "len"), varray(-1));
- bind_string_method(get_slice, sarray("delimiter", "slice"), varray());
+ bind_string_methodv(get_slice, static_cast<String (String::*)(const String &, int) const>(&String::get_slice), sarray("delimiter", "slice"), varray());
bind_string_method(get_slicec, sarray("delimiter", "slice"), varray());
- bind_string_method(get_slice_count, sarray("delimiter"), varray());
+ bind_string_methodv(get_slice_count, static_cast<int (String::*)(const String &) const>(&String::get_slice_count), sarray("delimiter"), varray());
bind_string_methodv(find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0));
- bind_string_method(count, sarray("what", "from", "to"), varray(0, 0));
- bind_string_method(countn, sarray("what", "from", "to"), varray(0, 0));
- bind_string_method(findn, sarray("what", "from"), varray(0));
- bind_string_method(rfind, sarray("what", "from"), varray(-1));
- bind_string_method(rfindn, sarray("what", "from"), varray(-1));
+ bind_string_methodv(findn, static_cast<int (String::*)(const String &, int) const>(&String::findn), sarray("what", "from"), varray(0));
+ bind_string_methodv(count, static_cast<int (String::*)(const String &, int, int) const>(&String::count), sarray("what", "from", "to"), varray(0, 0));
+ bind_string_methodv(countn, static_cast<int (String::*)(const String &, int, int) const>(&String::countn), sarray("what", "from", "to"), varray(0, 0));
+ bind_string_methodv(rfind, static_cast<int (String::*)(const String &, int) const>(&String::rfind), sarray("what", "from"), varray(-1));
+ bind_string_methodv(rfindn, static_cast<int (String::*)(const String &, int) const>(&String::rfindn), sarray("what", "from"), varray(-1));
bind_string_method(match, sarray("expr"), varray());
bind_string_method(matchn, sarray("expr"), varray());
bind_string_methodv(begins_with, static_cast<bool (String::*)(const String &) const>(&String::begins_with), sarray("text"), varray());
- bind_string_method(ends_with, sarray("text"), varray());
+ bind_string_methodv(ends_with, static_cast<bool (String::*)(const String &) const>(&String::ends_with), sarray("text"), varray());
bind_string_method(is_subsequence_of, sarray("text"), varray());
bind_string_method(is_subsequence_ofn, sarray("text"), varray());
bind_string_method(bigrams, sarray(), varray());
@@ -1668,7 +1668,7 @@ static void _register_variant_builtin_methods() {
bind_string_method(format, sarray("values", "placeholder"), varray("{_}"));
bind_string_methodv(replace, static_cast<String (String::*)(const String &, const String &) const>(&String::replace), sarray("what", "forwhat"), varray());
- bind_string_method(replacen, sarray("what", "forwhat"), varray());
+ bind_string_methodv(replacen, static_cast<String (String::*)(const String &, const String &) const>(&String::replacen), sarray("what", "forwhat"), varray());
bind_string_method(repeat, sarray("count"), varray());
bind_string_method(reverse, sarray(), varray());
bind_string_method(insert, sarray("position", "what"), varray());
@@ -1677,8 +1677,8 @@ static void _register_variant_builtin_methods() {
bind_string_method(to_camel_case, sarray(), varray());
bind_string_method(to_pascal_case, sarray(), varray());
bind_string_method(to_snake_case, sarray(), varray());
- bind_string_method(split, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
- bind_string_method(rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
+ bind_string_methodv(split, static_cast<Vector<String> (String::*)(const String &, bool, int) const>(&String::split), sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
+ bind_string_methodv(rsplit, static_cast<Vector<String> (String::*)(const String &, bool, int) const>(&String::rsplit), sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
bind_string_method(split_floats, sarray("delimiter", "allow_empty"), varray(true));
bind_string_method(join, sarray("parts"), varray());
@@ -1707,6 +1707,7 @@ static void _register_variant_builtin_methods() {
bind_string_method(sha256_buffer, sarray(), varray());
bind_string_method(is_empty, sarray(), varray());
bind_string_methodv(contains, static_cast<bool (String::*)(const String &) const>(&String::contains), sarray("what"), varray());
+ bind_string_methodv(containsn, static_cast<bool (String::*)(const String &) const>(&String::containsn), sarray("what"), varray());
bind_string_method(is_absolute_path, sarray(), varray());
bind_string_method(is_relative_path, sarray(), varray());
@@ -1741,8 +1742,8 @@ static void _register_variant_builtin_methods() {
bind_string_method(rpad, sarray("min_length", "character"), varray(" "));
bind_string_method(pad_decimals, sarray("digits"), varray());
bind_string_method(pad_zeros, sarray("digits"), varray());
- bind_string_method(trim_prefix, sarray("prefix"), varray());
- bind_string_method(trim_suffix, sarray("suffix"), varray());
+ bind_string_methodv(trim_prefix, static_cast<String (String::*)(const String &) const>(&String::trim_prefix), sarray("prefix"), varray());
+ bind_string_methodv(trim_suffix, static_cast<String (String::*)(const String &) const>(&String::trim_suffix), sarray("suffix"), varray());
bind_string_method(to_ascii_buffer, sarray(), varray());
bind_string_method(to_utf8_buffer, sarray(), varray());
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index ec87081f15..c52ab6917b 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -1546,7 +1546,7 @@ struct VariantTypeChanger {
template <typename T>
struct VariantTypeAdjust {
_FORCE_INLINE_ static void adjust(Variant *r_ret) {
- VariantTypeChanger<typename GetSimpleTypeT<T>::type_t>::change(r_ret);
+ VariantTypeChanger<GetSimpleTypeT<T>>::change(r_ret);
}
};
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 26bf515135..4b32acaaa0 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1097,6 +1097,7 @@
remap(75, 0, 100, -1, 1) # Returns 0.5
[/codeblock]
For complex use cases where multiple ranges are needed, consider using [Curve] or [Gradient] instead.
+ [b]Note:[/b] If [code]istart == istop[/code], the return value is undefined (most likely NaN, INF, or -INF).
</description>
</method>
<method name="rid_allocate_id">
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index a054048266..688e1b70ca 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1103,8 +1103,9 @@
<param index="0" name="screen" type="int" default="-1" />
<description>
Returns the scale factor of the specified screen by index.
- [b]Note:[/b] On macOS returned value is [code]2.0[/code] for hiDPI (Retina) screen, and [code]1.0[/code] for all other cases.
- [b]Note:[/b] This method is implemented only on macOS.
+ [b]Note:[/b] On macOS, the returned value is [code]2.0[/code] for hiDPI (Retina) screens, and [code]1.0[/code] for all other cases.
+ [b]Note:[/b] On Linux (Wayland), the returned value is accurate only when [param screen] is [constant SCREEN_OF_MAIN_WINDOW]. Due to API limitations, passing a direct index will return a rounded-up integer, if the screen has a fractional scale (e.g. [code]1.25[/code] would get rounded up to [code]2.0[/code]).
+ [b]Note:[/b] This method is implemented only on macOS and Linux (Wayland).
</description>
</method>
<method name="screen_get_size" qualifiers="const">
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index e874b44cfc..89b9e7d6c2 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -727,6 +727,14 @@
Removes a callback previously added by [method add_undo_redo_inspector_hook_callback].
</description>
</method>
+ <method name="set_dock_tab_icon">
+ <return type="void" />
+ <param index="0" name="control" type="Control" />
+ <param index="1" name="icon" type="Texture2D" />
+ <description>
+ Sets the tab icon for the given control in a dock slot. Setting to [code]null[/code] removes the icon.
+ </description>
+ </method>
<method name="set_force_draw_over_forwarding_enabled">
<return type="void" />
<description>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 6aa81803b7..f31f8135ff 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -632,6 +632,9 @@
If set to [b]Auto[/b], the editor scale is automatically determined based on the screen resolution and reported display DPI. This heuristic is not always ideal, which means you can get better results by setting the editor scale manually.
If set to [b]Custom[/b], the scaling value in [member interface/editor/custom_display_scale] will be used.
</member>
+ <member name="interface/editor/dock_tab_style" type="int" setter="" getter="">
+ Tab style of editor docks.
+ </member>
<member name="interface/editor/editor_language" type="String" setter="" getter="">
The language to use for the editor interface.
Translations are provided by the community. If you spot a mistake, [url=$DOCS_URL/contributing/documentation/editor_and_docs_localization.html]contribute to editor translations on Weblate![/url]
diff --git a/doc/classes/GDExtensionManager.xml b/doc/classes/GDExtensionManager.xml
index 1ecb23a03b..211bc023c0 100644
--- a/doc/classes/GDExtensionManager.xml
+++ b/doc/classes/GDExtensionManager.xml
@@ -43,7 +43,7 @@
<return type="int" enum="GDExtensionManager.LoadStatus" />
<param index="0" name="path" type="String" />
<description>
- Reloads the extension at the given file path. The [param path] needs to point to a valid [GDExtension], otherwise this method may return either [constant LOAD_STATUS_NOT_LOADED] or [constant LOAD_STATUS_FAILED].
+ Reloads the extension at the given file path. The [param path] needs to point to a valid [GDExtension], otherwise this method may return either [constant LOAD_STATUS_NOT_LOADED] or [constant LOAD_STATUS_FAILED].
[b]Note:[/b] You can only reload extensions in the editor. In release builds, this method always fails and returns [constant LOAD_STATUS_FAILED].
</description>
</method>
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index a7d89e8596..3c48f5ba31 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -43,7 +43,7 @@
<method name="restart">
<return type="void" />
<description>
- Restarts the particle emission cycle, clearing existing particles. To avoid particles vanishing from the viewport, wait for the [signal finished] signal before calling.
+ Restarts the particle emission cycle, clearing existing particles. To avoid particles vanishing from the viewport, wait for the [signal finished] signal before calling.
[b]Note:[/b] The [signal finished] signal is only emitted by [member one_shot] emitters.
</description>
</method>
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 3342e99ab6..176bdea4a1 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -991,7 +991,7 @@
[b]Note:[/b] When changing the name, the following characters will be replaced with an underscore: ([code].[/code] [code]:[/code] [code]@[/code] [code]/[/code] [code]"[/code] [code]%[/code]). In particular, the [code]@[/code] character is reserved for auto-generated names. See also [method String.validate_node_name].
</member>
<member name="owner" type="Node" setter="set_owner" getter="get_owner">
- The owner of this node. The owner must be an ancestor of this node. When packing the owner node in a [PackedScene], all the nodes it owns are also saved with it.
+ The owner of this node. The owner must be an ancestor of this node. When packing the owner node in a [PackedScene], all the nodes it owns are also saved with it.
[b]Note:[/b] In the editor, nodes not owned by the scene root are usually not displayed in the Scene dock, and will [b]not[/b] be saved. To prevent this, remember to set the owner after calling [method add_child]. See also (see [member unique_name_in_owner])
</member>
<member name="physics_interpolation_mode" type="int" setter="set_physics_interpolation_mode" getter="get_physics_interpolation_mode" enum="Node.PhysicsInterpolationMode" default="0">
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 68d2d6411c..b0dec2d00a 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -1034,6 +1034,7 @@
Translates a [param message], using the translation catalogs configured in the Project Settings. Further [param context] can be specified to help with the translation. Note that most [Control] nodes automatically translate their strings, so this method is mostly useful for formatted strings or custom drawn text.
If [method can_translate_messages] is [code]false[/code], or no translation is available, this method returns the [param message] without changes. See [method set_message_translation].
For detailed examples, see [url=$DOCS_URL/tutorials/i18n/internationalizing_games.html]Internationalizing games[/url].
+ [b]Note:[/b] This method can't be used without an [Object] instance, as it requires the [method can_translate_messages] method. To translate strings in a static context, use [method TranslationServer.translate].
</description>
</method>
<method name="tr_n" qualifiers="const">
@@ -1048,6 +1049,7 @@
The [param n] is the number, or amount, of the message's subject. It is used by the translation system to fetch the correct plural form for the current language.
For detailed examples, see [url=$DOCS_URL/tutorials/i18n/localization_using_gettext.html]Localization using gettext[/url].
[b]Note:[/b] Negative and [float] numbers may not properly apply to some countable subjects. It's recommended to handle these cases with [method tr].
+ [b]Note:[/b] This method can't be used without an [Object] instance, as it requires the [method can_translate_messages] method. To translate strings in a static context, use [method TranslationServer.translate_plural].
</description>
</method>
</methods>
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 13bf994e83..450e483f69 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -126,7 +126,7 @@
[/codeblock]
</description>
</method>
- <method name="contains" qualifiers="const" keywords="includes, has">
+ <method name="contains" qualifiers="const">
<return type="bool" />
<param index="0" name="what" type="String" />
<description>
@@ -142,7 +142,15 @@
GD.Print("team".Contains("I")); // Prints false
[/csharp]
[/codeblocks]
- If you need to know where [param what] is within the string, use [method find].
+ If you need to know where [param what] is within the string, use [method find]. See also [method containsn].
+ </description>
+ </method>
+ <method name="containsn" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="what" type="String" />
+ <description>
+ Returns [code]true[/code] if the string contains [param what], [b]ignoring case[/b].
+ If you need to know where [param what] is within the string, use [method findn]. See also [method contains].
</description>
</method>
<method name="count" qualifiers="const">
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index fbb73fd483..76586b7968 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -126,7 +126,15 @@
GD.Print("team".Contains("I")); // Prints false
[/csharp]
[/codeblocks]
- If you need to know where [param what] is within the string, use [method find].
+ If you need to know where [param what] is within the string, use [method find]. See also [method containsn].
+ </description>
+ </method>
+ <method name="containsn" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="what" type="String" />
+ <description>
+ Returns [code]true[/code] if the string contains [param what], [b]ignoring case[/b].
+ If you need to know where [param what] is within the string, use [method findn]. See also [method contains].
</description>
</method>
<method name="count" qualifiers="const">
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 2959ec4cfa..4dda1f8db8 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -1193,7 +1193,7 @@
<param index="2" name="wrap_index" type="int" default="-1" />
<param index="3" name="caret_index" type="int" default="0" />
<description>
- Sets the selection origin line to the [param line] for the given [param caret_index]. If the selection origin is moved to the caret position, the selection will deselect.
+ Sets the selection origin line to the [param line] for the given [param caret_index]. If the selection origin is moved to the caret position, the selection will deselect.
If [param can_be_hidden] is [code]false[/code], The line will be set to the nearest unhidden line below or above.
If [param wrap_index] is [code]-1[/code], the selection origin column will be clamped to the [param line]'s length. If [param wrap_index] is greater than [code]-1[/code], the column will be moved to attempt to match the visual x position on the line's [param wrap_index] to the position from the last time [method set_selection_origin_column] or [method select] was called.
</description>
diff --git a/doc/classes/TileMapLayer.xml b/doc/classes/TileMapLayer.xml
index 0513a7934c..1bff6d911b 100644
--- a/doc/classes/TileMapLayer.xml
+++ b/doc/classes/TileMapLayer.xml
@@ -97,7 +97,7 @@
<method name="get_navigation_map" qualifiers="const">
<return type="RID" />
<description>
- Returns the [RID] of the [NavigationServer2D] navigation used by this [TileMapLayer].
+ Returns the [RID] of the [NavigationServer2D] navigation used by this [TileMapLayer].
By default this returns the default [World2D] navigation map, unless a custom map was provided using [method set_navigation_map].
</description>
</method>
diff --git a/doc/classes/Time.xml b/doc/classes/Time.xml
index 2948d20fbb..bf002ec6e2 100644
--- a/doc/classes/Time.xml
+++ b/doc/classes/Time.xml
@@ -152,7 +152,7 @@
<method name="get_time_zone_from_system" qualifiers="const">
<return type="Dictionary" />
<description>
- Returns the current time zone as a dictionary of keys: [code]bias[/code] and [code]name[/code].
+ Returns the current time zone as a dictionary of keys: [code]bias[/code] and [code]name[/code].
- [code]bias[/code] is the offset from UTC in minutes, since not all time zones are multiples of an hour from UTC.
- [code]name[/code] is the localized name of the time zone, according to the OS locale settings of the current user.
</description>
diff --git a/doc/classes/VisualShaderNodeFrame.xml b/doc/classes/VisualShaderNodeFrame.xml
index 3126a56abe..a86587f16a 100644
--- a/doc/classes/VisualShaderNodeFrame.xml
+++ b/doc/classes/VisualShaderNodeFrame.xml
@@ -4,7 +4,7 @@
A frame other visual shader nodes can be attached to for better organization.
</brief_description>
<description>
- A rectangular frame that can be used to group visual shader nodes together to improve organization.
+ A rectangular frame that can be used to group visual shader nodes together to improve organization.
Nodes attached to the frame will move with it when it is dragged and it can automatically resize to enclose all attached nodes.
Its title, description and color can be customized.
</description>
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index 764d66c3b8..0c9635339b 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -52,7 +52,7 @@ Error AudioDriverALSA::init_output_device() {
// If there is a specified output device check that it is really present
if (output_device_name != "Default") {
PackedStringArray list = get_output_device_list();
- if (list.find(output_device_name) == -1) {
+ if (!list.has(output_device_name)) {
output_device_name = "Default";
new_output_device = "Default";
}
diff --git a/drivers/egl/egl_manager.cpp b/drivers/egl/egl_manager.cpp
index 4eddfd027b..6073856747 100644
--- a/drivers/egl/egl_manager.cpp
+++ b/drivers/egl/egl_manager.cpp
@@ -383,7 +383,7 @@ Error EGLManager::initialize() {
ERR_FAIL_COND_V(eglGetError() != EGL_SUCCESS, ERR_BUG);
const char *platform = _get_platform_extension_name();
- if (extensions_string.split(" ").find(platform) < 0) {
+ if (!extensions_string.split(" ").has(platform)) {
ERR_FAIL_V_MSG(ERR_UNAVAILABLE, vformat("EGL platform extension \"%s\" not found.", platform));
}
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 767a394ce5..6e7d4a6733 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -395,10 +395,13 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
if (p_first) {
- Size2i win_size = DisplayServer::get_singleton()->window_get_size();
if (p_screen_rect.position != Vector2() || p_screen_rect.size != rt->size) {
// Viewport doesn't cover entire window so clear window to black before blitting.
- glViewport(0, 0, win_size.width, win_size.height);
+ // Querying the actual window size from the DisplayServer would deadlock in separate render thread mode,
+ // so let's set the biggest viewport the implementation supports, to be sure the window is fully covered.
+ GLsizei max_vp[2] = {};
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, max_vp);
+ glViewport(0, 0, max_vp[0], max_vp[1]);
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
}
diff --git a/drivers/gles3/shaders/effects/post.glsl b/drivers/gles3/shaders/effects/post.glsl
index 1d17510c52..904158abcd 100644
--- a/drivers/gles3/shaders/effects/post.glsl
+++ b/drivers/gles3/shaders/effects/post.glsl
@@ -1,6 +1,6 @@
/* clang-format off */
#[modes]
-mode_default =
+mode_default =
#[specializations]
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 1a41b60836..6b5e227782 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -157,7 +157,7 @@ Config::Config() {
continue;
}
- if (renderer.findn(v) != -1) {
+ if (renderer.containsn(v)) {
use_depth_prepass = false;
}
}
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 373df8d8de..a65347a5b1 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -2312,9 +2312,11 @@ void TextureStorage::_clear_render_target(RenderTarget *rt) {
if (rt->backbuffer_fbo != 0) {
glDeleteFramebuffers(1, &rt->backbuffer_fbo);
+ rt->backbuffer_fbo = 0;
+ }
+ if (rt->backbuffer != 0) {
GLES3::Utilities::get_singleton()->texture_free_data(rt->backbuffer);
rt->backbuffer = 0;
- rt->backbuffer_fbo = 0;
}
if (rt->backbuffer_depth != 0) {
GLES3::Utilities::get_singleton()->texture_free_data(rt->backbuffer_depth);
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 20382e7f7c..669e6c2aa9 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -183,7 +183,7 @@ Error AudioDriverPulseAudio::init_output_device() {
// If there is a specified output device, check that it is really present
if (output_device_name != "Default") {
PackedStringArray list = get_output_device_list();
- if (list.find(output_device_name) == -1) {
+ if (!list.has(output_device_name)) {
output_device_name = "Default";
new_output_device = "Default";
}
@@ -695,7 +695,7 @@ Error AudioDriverPulseAudio::init_input_device() {
// If there is a specified input device, check that it is really present
if (input_device_name != "Default") {
PackedStringArray list = get_input_device_list();
- if (list.find(input_device_name) == -1) {
+ if (!list.has(input_device_name)) {
input_device_name = "Default";
new_input_device = "Default";
}
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 9c7f4c33d6..f21a0816ca 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -7122,7 +7122,7 @@ void AnimationTrackEditor::_pick_track_select_recursive(TreeItem *p_item, const
NodePath np = p_item->get_metadata(0);
Node *node = get_node_or_null(np);
- if (node && !p_filter.is_empty() && ((String)node->get_name()).findn(p_filter) != -1) {
+ if (node && !p_filter.is_empty() && ((String)node->get_name()).containsn(p_filter)) {
p_select_candidates.push_back(node);
}
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 787cae22cb..478067629e 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -282,7 +282,7 @@ List<MethodInfo> ConnectDialog::_filter_method_list(const List<MethodInfo> &p_me
List<MethodInfo> ret;
for (const MethodInfo &mi : p_methods) {
- if (!p_search_string.is_empty() && mi.name.findn(p_search_string) == -1) {
+ if (!p_search_string.is_empty() && !mi.name.containsn(p_search_string)) {
continue;
}
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index b00f059b36..2c7f6fb21a 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -376,7 +376,7 @@ float CreateDialog::_score_type(const String &p_type, const String &p_search) co
score *= _is_type_preferred(p_type) ? 1.0f : 0.9f;
// Add score for being a favorite type.
- score *= (favorite_list.find(p_type) > -1) ? 1.0f : 0.8f;
+ score *= favorite_list.has(p_type) ? 1.0f : 0.8f;
// Look through at most 5 recent items
bool in_recent = false;
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
index 3c0420d2f0..4210baeed2 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
@@ -358,7 +358,7 @@ Dictionary DebugAdapterParser::req_setBreakpoints(const Dictionary &p_params) co
}
// If path contains \, it's a Windows path, so we need to convert it to /, and make the drive letter uppercase
- if (source.path.find("\\") != -1) {
+ if (source.path.contains("\\")) {
source.path = source.path.replace("\\", "/");
source.path = source.path.substr(0, 1).to_upper() + source.path.substr(1);
}
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.h b/editor/debugger/debug_adapter/debug_adapter_parser.h
index 9860e96498..8fd2c2b3e2 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.h
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.h
@@ -50,7 +50,7 @@ private:
if (p_path.contains("\\")) {
String project_path = ProjectSettings::get_singleton()->get_resource_path();
String path = p_path.replace("\\", "/");
- return path.findn(project_path) != -1;
+ return path.containsn(project_path);
}
return p_path.begins_with(ProjectSettings::get_singleton()->get_resource_path());
}
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 3ee8a33e70..931e360a34 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -262,7 +262,7 @@ void EditorDebuggerNode::set_keep_open(bool p_keep_open) {
}
Error EditorDebuggerNode::start(const String &p_uri) {
- ERR_FAIL_COND_V(p_uri.find("://") < 0, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!p_uri.contains("://"), ERR_INVALID_PARAMETER);
if (keep_open && current_uri == p_uri && server.is_valid()) {
return OK;
}
diff --git a/editor/debugger/editor_file_server.cpp b/editor/debugger/editor_file_server.cpp
index e84eb14636..1092b07054 100644
--- a/editor/debugger/editor_file_server.cpp
+++ b/editor/debugger/editor_file_server.cpp
@@ -80,7 +80,7 @@ void EditorFileServer::_scan_files_changed(EditorFileSystemDirectory *efd, const
_add_file(remapped_path, mt, files_to_send, cached_files);
} else if (remap.begins_with("path.")) {
String feature = remap.get_slice(".", 1);
- if (p_tags.find(feature) != -1) {
+ if (p_tags.has(feature)) {
String remapped_path = cf->get_value("remap", remap);
uint64_t mt = FileAccess::get_modified_time(remapped_path);
_add_file(remapped_path, mt, files_to_send, cached_files);
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 8c3cad3e89..84d6cb67d8 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -642,11 +642,11 @@ void DependencyRemoveDialog::ok_pressed() {
for (int i = 0; i < previous_favorites.size(); ++i) {
if (previous_favorites[i].ends_with("/")) {
- if (dirs_to_delete.find(previous_favorites[i]) < 0) {
+ if (!dirs_to_delete.has(previous_favorites[i])) {
new_favorites.push_back(previous_favorites[i]);
}
} else {
- if (files_to_delete.find(previous_favorites[i]) < 0) {
+ if (!files_to_delete.has(previous_favorites[i])) {
new_favorites.push_back(previous_favorites[i]);
}
}
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index d3875709ee..b58e82b7e7 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -1602,7 +1602,7 @@ static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<Do
}
}
-Error DocTools::save_classes(const String &p_default_path, const HashMap<String, String> &p_class_path, bool p_include_xml_schema) {
+Error DocTools::save_classes(const String &p_default_path, const HashMap<String, String> &p_class_path, bool p_use_relative_schema) {
for (KeyValue<String, DocData::ClassDoc> &E : class_list) {
DocData::ClassDoc &c = E.value;
@@ -1634,15 +1634,17 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
if (!c.keywords.is_empty()) {
header += String(" keywords=\"") + c.keywords.xml_escape(true) + "\"";
}
- if (p_include_xml_schema) {
- // Reference the XML schema so editors can provide error checking.
+ // Reference the XML schema so editors can provide error checking.
+ String schema_path;
+ if (p_use_relative_schema) {
// Modules are nested deep, so change the path to reference the same schema everywhere.
- const String schema_path = save_path.find("modules/") != -1 ? "../../../doc/class.xsd" : "../class.xsd";
- header += vformat(
- R"( xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="%s")",
- schema_path);
+ schema_path = save_path.contains("modules/") ? "../../../doc/class.xsd" : "../class.xsd";
+ } else {
+ schema_path = "https://raw.githubusercontent.com/godotengine/godot/master/doc/class.xsd";
}
- header += ">";
+ header += vformat(
+ R"( xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="%s">)",
+ schema_path);
_write_string(f, 0, header);
_write_string(f, 1, "<brief_description>");
diff --git a/editor/doc_tools.h b/editor/doc_tools.h
index a6910baf28..3be59bf233 100644
--- a/editor/doc_tools.h
+++ b/editor/doc_tools.h
@@ -52,7 +52,7 @@ public:
};
void generate(BitField<GenerateFlags> p_flags = {});
Error load_classes(const String &p_dir);
- Error save_classes(const String &p_default_path, const HashMap<String, String> &p_class_path, bool p_include_xml_schema = true);
+ Error save_classes(const String &p_default_path, const HashMap<String, String> &p_class_path, bool p_use_relative_schema = true);
Error _load(Ref<XMLParser> parser);
Error load_compressed(const uint8_t *p_data, int p_compressed_size, int p_uncompressed_size);
diff --git a/editor/editor_dock_manager.cpp b/editor/editor_dock_manager.cpp
index 06dd33d8ab..4956fa867a 100644
--- a/editor/editor_dock_manager.cpp
+++ b/editor/editor_dock_manager.cpp
@@ -33,12 +33,10 @@
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
-#include "scene/gui/popup.h"
#include "scene/gui/split_container.h"
#include "scene/gui/tab_container.h"
#include "scene/main/window.h"
-#include "editor/editor_command_palette.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
@@ -47,6 +45,12 @@
#include "editor/themes/editor_scale.h"
#include "editor/window_wrapper.h"
+enum class TabStyle {
+ TEXT_ONLY,
+ ICON_ONLY,
+ TEXT_AND_ICON,
+};
+
EditorDockManager *EditorDockManager::singleton = nullptr;
void DockSplitContainer::_update_visibility() {
@@ -156,7 +160,7 @@ void EditorDockManager::_update_docks_menu() {
docks_menu->clear();
docks_menu->reset_size();
- const Ref<Texture2D> icon = docks_menu->get_editor_theme_icon(SNAME("Window"));
+ const Ref<Texture2D> default_icon = docks_menu->get_editor_theme_icon(SNAME("Window"));
const Color closed_icon_color_mod = Color(1, 1, 1, 0.5);
// Add docks.
@@ -169,7 +173,8 @@ void EditorDockManager::_update_docks_menu() {
} else {
docks_menu->add_item(dock.value.title, id);
}
- docks_menu->set_item_icon(id, icon);
+ const Ref<Texture2D> icon = dock.value.icon_name ? docks_menu->get_editor_theme_icon(dock.value.icon_name) : dock.value.icon;
+ docks_menu->set_item_icon(id, icon.is_valid() ? icon : default_icon);
if (!dock.value.open) {
docks_menu->set_item_icon_modulate(id, closed_icon_color_mod);
}
@@ -344,7 +349,9 @@ void EditorDockManager::_move_dock(Control *p_dock, Control *p_target, int p_tab
p_target->set_block_signals(false);
TabContainer *dock_tab_container = Object::cast_to<TabContainer>(p_target);
if (dock_tab_container) {
- dock_tab_container->set_tab_title(dock_tab_container->get_tab_idx_from_control(p_dock), all_docks[p_dock].title);
+ if (dock_tab_container->is_inside_tree()) {
+ _update_tab_style(p_dock);
+ }
if (p_tab_index >= 0) {
_move_dock_tab_index(p_dock, p_tab_index, p_set_current);
}
@@ -352,6 +359,42 @@ void EditorDockManager::_move_dock(Control *p_dock, Control *p_target, int p_tab
}
}
+void EditorDockManager::_update_tab_style(Control *p_dock) {
+ const DockInfo &dock_info = all_docks[p_dock];
+ if (!dock_info.enabled || !dock_info.open) {
+ return; // Disabled by feature profile or manually closed by user.
+ }
+ if (dock_info.dock_window || dock_info.at_bottom) {
+ return; // Floating or sent to bottom.
+ }
+
+ TabContainer *tab_container = get_dock_tab_container(p_dock);
+ ERR_FAIL_NULL(tab_container);
+ int index = tab_container->get_tab_idx_from_control(p_dock);
+ ERR_FAIL_COND(index == -1);
+
+ const TabStyle style = (TabStyle)EDITOR_GET("interface/editor/dock_tab_style").operator int();
+ switch (style) {
+ case TabStyle::TEXT_ONLY: {
+ tab_container->set_tab_title(index, dock_info.title);
+ tab_container->set_tab_icon(index, Ref<Texture2D>());
+ tab_container->set_tab_tooltip(index, String());
+ } break;
+ case TabStyle::ICON_ONLY: {
+ const Ref<Texture2D> icon = dock_info.icon_name ? tab_container->get_editor_theme_icon(dock_info.icon_name) : dock_info.icon;
+ tab_container->set_tab_title(index, icon.is_valid() ? String() : dock_info.title);
+ tab_container->set_tab_icon(index, icon);
+ tab_container->set_tab_tooltip(index, icon.is_valid() ? dock_info.title : String());
+ } break;
+ case TabStyle::TEXT_AND_ICON: {
+ const Ref<Texture2D> icon = dock_info.icon_name ? tab_container->get_editor_theme_icon(dock_info.icon_name) : dock_info.icon;
+ tab_container->set_tab_title(index, dock_info.title);
+ tab_container->set_tab_icon(index, icon);
+ tab_container->set_tab_tooltip(index, String());
+ } break;
+ }
+}
+
void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) const {
// Save docks by dock slot.
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
@@ -665,14 +708,15 @@ void EditorDockManager::focus_dock(Control *p_dock) {
tab_container->set_current_tab(tab_index);
}
-void EditorDockManager::add_dock(Control *p_dock, const String &p_title, DockSlot p_slot, const Ref<Shortcut> &p_shortcut) {
+void EditorDockManager::add_dock(Control *p_dock, const String &p_title, DockSlot p_slot, const Ref<Shortcut> &p_shortcut, const StringName &p_icon_name) {
ERR_FAIL_NULL(p_dock);
ERR_FAIL_COND_MSG(all_docks.has(p_dock), vformat("Cannot add dock '%s', already added.", p_dock->get_name()));
DockInfo dock_info;
- dock_info.title = !p_title.is_empty() ? p_title : String(p_dock->get_name());
+ dock_info.title = p_title.is_empty() ? String(p_dock->get_name()) : p_title;
dock_info.dock_slot_index = p_slot;
dock_info.shortcut = p_shortcut;
+ dock_info.icon_name = p_icon_name;
all_docks[p_dock] = dock_info;
if (p_slot != DOCK_SLOT_NONE) {
@@ -695,6 +739,14 @@ void EditorDockManager::remove_dock(Control *p_dock) {
_update_layout();
}
+void EditorDockManager::set_dock_tab_icon(Control *p_dock, const Ref<Texture2D> &p_icon) {
+ ERR_FAIL_NULL(p_dock);
+ ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot set tab icon for unknown dock '%s'.", p_dock->get_name()));
+
+ all_docks[p_dock].icon = p_icon;
+ _update_tab_style(p_dock);
+}
+
void EditorDockManager::set_docks_visible(bool p_show) {
if (docks_visible == p_show) {
return;
@@ -710,6 +762,19 @@ bool EditorDockManager::are_docks_visible() const {
return docks_visible;
}
+void EditorDockManager::update_tab_styles() {
+ for (const KeyValue<Control *, DockInfo> &dock : all_docks) {
+ _update_tab_style(dock.key);
+ }
+}
+
+void EditorDockManager::set_tab_icon_max_width(int p_max_width) {
+ for (int i = 0; i < DOCK_SLOT_MAX; i++) {
+ TabContainer *tab_container = dock_slot[i];
+ tab_container->add_theme_constant_override(SNAME("icon_max_width"), p_max_width);
+ }
+}
+
void EditorDockManager::add_vsplit(DockSplitContainer *p_split) {
vsplits.push_back(p_split);
p_split->connect("dragged", callable_mp(this, &EditorDockManager::_dock_split_dragged));
diff --git a/editor/editor_dock_manager.h b/editor/editor_dock_manager.h
index cbb076c809..226222c55a 100644
--- a/editor/editor_dock_manager.h
+++ b/editor/editor_dock_manager.h
@@ -87,6 +87,8 @@ private:
WindowWrapper *dock_window = nullptr;
int dock_slot_index = DOCK_SLOT_NONE;
Ref<Shortcut> shortcut;
+ Ref<Texture2D> icon; // Only used when `icon_name` is empty.
+ StringName icon_name;
};
static EditorDockManager *singleton;
@@ -126,9 +128,14 @@ private:
void _move_dock_tab_index(Control *p_dock, int p_tab_index, bool p_set_current);
void _move_dock(Control *p_dock, Control *p_target, int p_tab_index = -1, bool p_set_current = true);
+ void _update_tab_style(Control *p_dock);
+
public:
static EditorDockManager *get_singleton() { return singleton; }
+ void update_tab_styles();
+ void set_tab_icon_max_width(int p_max_width);
+
void add_vsplit(DockSplitContainer *p_split);
void add_hsplit(DockSplitContainer *p_split);
void register_dock_slot(DockSlot p_dock_slot, TabContainer *p_tab_container);
@@ -150,9 +157,11 @@ public:
void set_docks_visible(bool p_show);
bool are_docks_visible() const;
- void add_dock(Control *p_dock, const String &p_title = "", DockSlot p_slot = DOCK_SLOT_NONE, const Ref<Shortcut> &p_shortcut = nullptr);
+ void add_dock(Control *p_dock, const String &p_title = "", DockSlot p_slot = DOCK_SLOT_NONE, const Ref<Shortcut> &p_shortcut = nullptr, const StringName &p_icon_name = StringName());
void remove_dock(Control *p_dock);
+ void set_dock_tab_icon(Control *p_dock, const Ref<Texture2D> &p_icon);
+
EditorDockManager();
};
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 1e91a326b3..bee1275d64 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -269,7 +269,7 @@ void EditorFileSystem::_scan_filesystem() {
FileCache fc;
fc.type = split[1];
- if (fc.type.find("/") != -1) {
+ if (fc.type.contains("/")) {
fc.type = fc.type.get_slice("/", 0);
fc.resource_script_class = fc.type.get_slice("/", 1);
}
@@ -2707,7 +2707,7 @@ void EditorFileSystem::_update_extensions() {
}
void EditorFileSystem::add_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query) {
- ERR_FAIL_COND(import_support_queries.find(p_query) != -1);
+ ERR_FAIL_COND(import_support_queries.has(p_query));
import_support_queries.push_back(p_query);
}
void EditorFileSystem::remove_import_format_support_query(Ref<EditorFileSystemImportFormatSupportQuery> p_query) {
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index ff381d68c0..1e0c0e9fd8 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -40,7 +40,7 @@
bool EditorHelpSearch::_all_terms_in_name(const Vector<String> &p_terms, const String &p_name) const {
for (int i = 0; i < p_terms.size(); i++) {
- if (p_name.findn(p_terms[i]) < 0) {
+ if (!p_name.containsn(p_terms[i])) {
return false;
}
}
@@ -109,7 +109,7 @@ Dictionary EditorHelpSearch::_native_search_cb(const String &p_search_string, in
if (class_doc.name.is_empty()) {
continue;
}
- if (class_doc.name.findn(term) > -1) {
+ if (class_doc.name.containsn(term)) {
ret[vformat("class_name:%s", class_doc.name)] = class_doc.name;
}
if (term.length() > 1 || term == "@") {
@@ -744,9 +744,9 @@ String EditorHelpSearch::Runner::_match_keywords_in_all_terms(const String &p_ke
bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String &p_string) const {
if (search_flags & SEARCH_CASE_SENSITIVE) {
- return p_string.find(p_term) > -1;
+ return p_string.contains(p_term);
} else {
- return p_string.findn(p_term) > -1;
+ return p_string.containsn(p_term);
}
}
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index d9dcf949c7..9599479c83 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -52,7 +52,7 @@
#include "scene/resources/style_box_flat.h"
bool EditorInspector::_property_path_matches(const String &p_property_path, const String &p_filter, EditorPropertyNameProcessor::Style p_style) {
- if (p_property_path.findn(p_filter) != -1) {
+ if (p_property_path.containsn(p_filter)) {
return true;
}
@@ -72,16 +72,10 @@ Size2 EditorProperty::get_minimum_size() const {
ms.height = label.is_empty() ? 0 : font->get_height(font_size) + 4 * EDSCALE;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
- if (!c->is_visible()) {
- continue;
- }
if (c == bottom_editor) {
continue;
}
@@ -143,16 +137,10 @@ void EditorProperty::_notification(int p_what) {
//compute room needed
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
- if (!c->is_visible()) {
- continue;
- }
if (c == bottom_editor) {
continue;
}
@@ -218,13 +206,10 @@ void EditorProperty::_notification(int p_what) {
//set children
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
if (c == bottom_editor) {
continue;
}
@@ -1347,14 +1332,10 @@ void EditorInspectorSection::_notification(int p_what) {
int header_height = _get_header_height();
Vector2 offset = Vector2(is_layout_rtl() ? 0 : inspector_margin, header_height);
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
-
fit_child_in_rect(c, Rect2(offset, size));
}
} break;
@@ -1503,16 +1484,10 @@ void EditorInspectorSection::_notification(int p_what) {
Size2 EditorInspectorSection::get_minimum_size() const {
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
- if (!c->is_visible()) {
- continue;
- }
Size2 minsize = c->get_combined_minimum_size();
ms = ms.max(minsize);
}
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index b8da550d8a..ab4950f01b 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -322,7 +322,7 @@ void EditorLog::_rebuild_log() {
bool EditorLog::_check_display_message(LogMessage &p_message) {
bool filter_active = type_filter_map[p_message.type]->is_active();
String search_text = search_box->get_text();
- bool search_match = search_text.is_empty() || p_message.text.findn(search_text) > -1;
+ bool search_match = search_text.is_empty() || p_message.text.containsn(search_text);
return filter_active && search_match;
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 33b46b82bc..d7f197b569 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -544,6 +544,9 @@ void EditorNode::_update_theme(bool p_skip_creation) {
}
}
}
+
+ editor_dock_manager->update_tab_styles();
+ editor_dock_manager->set_tab_icon_max_width(theme->get_constant(SNAME("class_icon_size"), EditorStringName(Editor)));
}
void EditorNode::update_preview_themes(int p_mode) {
@@ -752,7 +755,7 @@ void EditorNode::_notification(int p_what) {
case NOTIFICATION_APPLICATION_FOCUS_OUT: {
// Save on focus loss before applying the FPS limit to avoid slowing down the saving process.
if (EDITOR_GET("interface/editor/save_on_focus_loss")) {
- _menu_option_confirm(FILE_SAVE_SCENE, false);
+ _menu_option_confirm(FILE_SAVE_SCENE_SILENTLY, false);
}
// Set a low FPS cap to decrease CPU/GPU usage while the editor is unfocused.
@@ -789,6 +792,10 @@ void EditorNode::_notification(int p_what) {
recent_scenes->reset_size();
}
+ if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/dock_tab_style")) {
+ editor_dock_manager->update_tab_styles();
+ }
+
if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/scene_tabs")) {
scene_tabs->update_scene_tabs();
}
@@ -2391,7 +2398,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
Ref<Resource> res = Object::cast_to<Resource>(current_obj);
if (p_skip_foreign && res.is_valid()) {
const int current_tab = scene_tabs->get_current_tab();
- if (res->get_path().find("::") > -1 && res->get_path().get_slice("::", 0) != editor_data.get_scene_path(current_tab)) {
+ if (res->get_path().contains("::") && res->get_path().get_slice("::", 0) != editor_data.get_scene_path(current_tab)) {
// Trying to edit resource that belongs to another scene; abort.
current_obj = nullptr;
}
@@ -2666,6 +2673,16 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_CLOSE: {
_scene_tab_closed(editor_data.get_edited_scene());
} break;
+ case FILE_SAVE_SCENE_SILENTLY: {
+ // Save scene without displaying progress dialog. Used to work around
+ // errors about parent node being busy setting up children
+ // when Save on Focus Loss kicks in.
+ Node *scene = editor_data.get_edited_scene_root();
+ if (scene && !scene->get_scene_file_path().is_empty() && DirAccess::exists(scene->get_scene_file_path().get_base_dir())) {
+ _save_scene(scene->get_scene_file_path());
+ save_editor_layout_delayed();
+ }
+ } break;
case SCENE_TAB_CLOSE:
case FILE_SAVE_SCENE: {
int scene_idx = (p_option == FILE_SAVE_SCENE) ? -1 : tab_closing_idx;
@@ -7045,22 +7062,22 @@ EditorNode::EditorNode() {
history_dock = memnew(HistoryDock);
// Scene: Top left.
- editor_dock_manager->add_dock(SceneTreeDock::get_singleton(), TTR("Scene"), EditorDockManager::DOCK_SLOT_LEFT_UR);
+ editor_dock_manager->add_dock(SceneTreeDock::get_singleton(), TTR("Scene"), EditorDockManager::DOCK_SLOT_LEFT_UR, nullptr, "PackedScene");
// Import: Top left, behind Scene.
- editor_dock_manager->add_dock(ImportDock::get_singleton(), TTR("Import"), EditorDockManager::DOCK_SLOT_LEFT_UR);
+ editor_dock_manager->add_dock(ImportDock::get_singleton(), TTR("Import"), EditorDockManager::DOCK_SLOT_LEFT_UR, nullptr, "FileAccess");
// FileSystem: Bottom left.
- editor_dock_manager->add_dock(FileSystemDock::get_singleton(), TTR("FileSystem"), EditorDockManager::DOCK_SLOT_LEFT_BR, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_filesystem_bottom_panel", TTR("Toggle FileSystem Bottom Panel"), KeyModifierMask::ALT | Key::F));
+ editor_dock_manager->add_dock(FileSystemDock::get_singleton(), TTR("FileSystem"), EditorDockManager::DOCK_SLOT_LEFT_BR, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_filesystem_bottom_panel", TTR("Toggle FileSystem Bottom Panel"), KeyModifierMask::ALT | Key::F), "Folder");
// Inspector: Full height right.
- editor_dock_manager->add_dock(InspectorDock::get_singleton(), TTR("Inspector"), EditorDockManager::DOCK_SLOT_RIGHT_UL);
+ editor_dock_manager->add_dock(InspectorDock::get_singleton(), TTR("Inspector"), EditorDockManager::DOCK_SLOT_RIGHT_UL, nullptr, "AnimationTrackList");
// Node: Full height right, behind Inspector.
- editor_dock_manager->add_dock(NodeDock::get_singleton(), TTR("Node"), EditorDockManager::DOCK_SLOT_RIGHT_UL);
+ editor_dock_manager->add_dock(NodeDock::get_singleton(), TTR("Node"), EditorDockManager::DOCK_SLOT_RIGHT_UL, nullptr, "Object");
// History: Full height right, behind Node.
- editor_dock_manager->add_dock(history_dock, TTR("History"), EditorDockManager::DOCK_SLOT_RIGHT_UL);
+ editor_dock_manager->add_dock(history_dock, TTR("History"), EditorDockManager::DOCK_SLOT_RIGHT_UL, nullptr, "History");
// Add some offsets to left_r and main hsplits to make LEFT_R and RIGHT_L docks wider than minsize.
left_r_hsplit->set_split_offset(270 * EDSCALE);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 54c84bc6a6..6b3359eaee 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -159,6 +159,7 @@ private:
FILE_NEW_INHERITED_SCENE,
FILE_OPEN_SCENE,
FILE_SAVE_SCENE,
+ FILE_SAVE_SCENE_SILENTLY,
FILE_SAVE_AS_SCENE,
FILE_SAVE_ALL_SCENES,
FILE_SAVE_AND_RUN,
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 9cb5fcc18c..816d3d7778 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2025,6 +2025,7 @@ void EditorPropertyQuaternion::_custom_value_changed(double val) {
spin[1]->set_value_no_signal(temp_q.y);
spin[2]->set_value_no_signal(temp_q.z);
spin[3]->set_value_no_signal(temp_q.w);
+ _value_changed(-1, "");
}
void EditorPropertyQuaternion::_value_changed(double val, const String &p_name) {
diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp
index a00b50c191..f23cab676c 100644
--- a/editor/editor_property_name_processor.cpp
+++ b/editor/editor_property_name_processor.cpp
@@ -63,7 +63,7 @@ bool EditorPropertyNameProcessor::is_localization_available() {
return false;
}
const Vector<String> forbidden = String("en").split(",");
- return forbidden.find(EDITOR_GET("interface/editor/editor_language")) == -1;
+ return !forbidden.has(EDITOR_GET("interface/editor/editor_language"));
}
String EditorPropertyNameProcessor::_capitalize_name(const String &p_name) const {
diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp
index f8df0f9fa8..d7a02ace24 100644
--- a/editor/editor_quick_open.cpp
+++ b/editor/editor_quick_open.cpp
@@ -160,7 +160,7 @@ float EditorQuickOpen::_score_search_result(const PackedStringArray &p_search_to
}
// Prioritize matches at the front of the path token.
- if (min_match_idx == 0 || p_path.find("/" + s) != -1) {
+ if (min_match_idx == 0 || p_path.contains("/" + s)) {
token_score += 1.0f;
}
diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp
index f13af8e4ca..22120bfc01 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -36,7 +36,7 @@
#include "editor/themes/editor_scale.h"
static bool _property_path_matches(const String &p_property_path, const String &p_filter, EditorPropertyNameProcessor::Style p_style) {
- if (p_property_path.findn(p_filter) != -1) {
+ if (p_property_path.containsn(p_filter)) {
return true;
}
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 41d328c6de..c019d46034 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -400,6 +400,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Editor
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/localize_settings", true, "")
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/dock_tab_style", 0, "Text Only,Icon Only,Text and Icon")
EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/ui_layout_direction", 0, "Based on Application Locale,Left-to-Right,Right-to-Left,Based on System Locale", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
// Display what the Auto display scale setting effectively corresponds to.
@@ -969,7 +970,7 @@ bool EditorSettings::_save_text_editor_theme(const String &p_file) {
keys.sort();
for (const String &key : keys) {
- if (key.begins_with("text_editor/theme/highlighting/") && key.find("color") >= 0) {
+ if (key.begins_with("text_editor/theme/highlighting/") && key.contains("color")) {
cf->set_value(theme_section, key.replace("text_editor/theme/highlighting/", ""), ((Color)props[key].variant).to_html());
}
}
@@ -1448,7 +1449,7 @@ void EditorSettings::load_text_editor_theme() {
// don't load if it's not already there!
if (has_setting("text_editor/theme/highlighting/" + key)) {
// make sure it is actually a color
- if (val.is_valid_html_color() && key.find("color") >= 0) {
+ if (val.is_valid_html_color() && key.contains("color")) {
props["text_editor/theme/highlighting/" + key].variant = Color::html(val); // change manually to prevent "Settings changed" console spam
}
}
@@ -1539,6 +1540,19 @@ String EditorSettings::get_editor_layouts_config() const {
float EditorSettings::get_auto_display_scale() const {
#ifdef LINUXBSD_ENABLED
if (DisplayServer::get_singleton()->get_name() == "Wayland") {
+ float main_window_scale = DisplayServer::get_singleton()->screen_get_scale(DisplayServer::SCREEN_OF_MAIN_WINDOW);
+
+ if (DisplayServer::get_singleton()->get_screen_count() == 1 || Math::fract(main_window_scale) != 0) {
+ // If we have a single screen or the screen of the window is fractional, all
+ // bets are off. At this point, let's just return the current's window scale,
+ // which is special-cased to the scale of `SCREEN_OF_MAIN_WINDOW`.
+ return main_window_scale;
+ }
+
+ // If the above branch didn't fire, fractional scaling isn't going to work
+ // properly anyways (we're need the ability to change the UI scale at runtime).
+ // At this point it's more convenient to "supersample" like we do with other
+ // platforms, hoping that the user is only using integer-scaled screens.
return DisplayServer::get_singleton()->screen_get_max_scale();
}
#endif
diff --git a/editor/editor_translation.cpp b/editor/editor_translation.cpp
index 194d78326d..77154ec344 100644
--- a/editor/editor_translation.cpp
+++ b/editor/editor_translation.cpp
@@ -156,30 +156,166 @@ void load_extractable_translations(const String &p_locale) {
}
}
-List<StringName> get_extractable_message_list() {
+Vector<Vector<String>> get_extractable_message_list() {
ExtractableTranslationList *etl = _extractable_translations;
- List<StringName> msgids;
- while (etl->data) {
- if (!strcmp(etl->lang, "source")) {
- Vector<uint8_t> data;
- data.resize(etl->uncomp_size);
- int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE);
- ERR_FAIL_COND_V_MSG(ret == -1, msgids, "Compressed file is corrupt.");
+ Vector<Vector<String>> list;
- Ref<FileAccessMemory> fa;
- fa.instantiate();
- fa->open_custom(data.ptr(), data.size());
-
- Ref<Translation> tr = TranslationLoaderPO::load_translation(fa);
+ while (etl->data) {
+ if (strcmp(etl->lang, "source")) {
+ etl++;
+ continue;
+ }
- if (tr.is_valid()) {
- tr->get_message_list(&msgids);
- break;
+ Vector<uint8_t> data;
+ data.resize(etl->uncomp_size);
+ int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE);
+ ERR_FAIL_COND_V_MSG(ret == -1, list, "Compressed file is corrupt.");
+
+ Ref<FileAccessMemory> fa;
+ fa.instantiate();
+ fa->open_custom(data.ptr(), data.size());
+
+ // Taken from TranslationLoaderPO, modified to work specifically with POTs.
+ {
+ const String path = fa->get_path();
+
+ fa->seek(0);
+
+ enum Status {
+ STATUS_NONE,
+ STATUS_READING_ID,
+ STATUS_READING_STRING,
+ STATUS_READING_CONTEXT,
+ STATUS_READING_PLURAL,
+ };
+
+ Status status = STATUS_NONE;
+
+ String msg_id;
+ String msg_id_plural;
+ String msg_context;
+
+ int line = 1;
+ bool entered_context = false;
+ bool is_eof = false;
+
+ while (!is_eof) {
+ String l = fa->get_line().strip_edges();
+ is_eof = fa->eof_reached();
+
+ // If we reached last line and it's not a content line, break, otherwise let processing that last loop.
+ if (is_eof && l.is_empty()) {
+ if (status == STATUS_READING_ID || status == STATUS_READING_CONTEXT || status == STATUS_READING_PLURAL) {
+ ERR_FAIL_V_MSG(Vector<Vector<String>>(), "Unexpected EOF while reading POT file at: " + path + ":" + itos(line));
+ } else {
+ break;
+ }
+ }
+
+ if (l.begins_with("msgctxt")) {
+ ERR_FAIL_COND_V_MSG(status != STATUS_READING_STRING && status != STATUS_READING_PLURAL, Vector<Vector<String>>(),
+ "Unexpected 'msgctxt', was expecting 'msgid_plural' or 'msgstr' before 'msgctxt' while parsing: " + path + ":" + itos(line));
+
+ // In POT files, "msgctxt" appears before "msgid". If we encounter a "msgctxt", we add what we have read
+ // and set "entered_context" to true to prevent adding twice.
+ if (!msg_id.is_empty()) {
+ Vector<String> msgs;
+ msgs.push_back(msg_id);
+ msgs.push_back(msg_context);
+ msgs.push_back(msg_id_plural);
+ list.push_back(msgs);
+ }
+ msg_context = "";
+ l = l.substr(7, l.length()).strip_edges();
+ status = STATUS_READING_CONTEXT;
+ entered_context = true;
+ }
+
+ if (l.begins_with("msgid_plural")) {
+ if (status != STATUS_READING_ID) {
+ ERR_FAIL_V_MSG(Vector<Vector<String>>(), "Unexpected 'msgid_plural', was expecting 'msgid' before 'msgid_plural' while parsing: " + path + ":" + itos(line));
+ }
+ l = l.substr(12, l.length()).strip_edges();
+ status = STATUS_READING_PLURAL;
+ } else if (l.begins_with("msgid")) {
+ ERR_FAIL_COND_V_MSG(status == STATUS_READING_ID, Vector<Vector<String>>(), "Unexpected 'msgid', was expecting 'msgstr' while parsing: " + path + ":" + itos(line));
+
+ if (!msg_id.is_empty() && !entered_context) {
+ Vector<String> msgs;
+ msgs.push_back(msg_id);
+ msgs.push_back(msg_context);
+ msgs.push_back(msg_id_plural);
+ list.push_back(msgs);
+ }
+
+ l = l.substr(5, l.length()).strip_edges();
+ status = STATUS_READING_ID;
+ // If we did not encounter msgctxt, we reset context to empty to reset it.
+ if (!entered_context) {
+ msg_context = "";
+ }
+ msg_id = "";
+ msg_id_plural = "";
+ entered_context = false;
+ }
+
+ if (l.begins_with("msgstr[")) {
+ ERR_FAIL_COND_V_MSG(status != STATUS_READING_PLURAL, Vector<Vector<String>>(),
+ "Unexpected 'msgstr[]', was expecting 'msgid_plural' before 'msgstr[]' while parsing: " + path + ":" + itos(line));
+ l = l.substr(9, l.length()).strip_edges();
+ } else if (l.begins_with("msgstr")) {
+ ERR_FAIL_COND_V_MSG(status != STATUS_READING_ID, Vector<Vector<String>>(),
+ "Unexpected 'msgstr', was expecting 'msgid' before 'msgstr' while parsing: " + path + ":" + itos(line));
+ l = l.substr(6, l.length()).strip_edges();
+ status = STATUS_READING_STRING;
+ }
+
+ if (l.is_empty() || l.begins_with("#")) {
+ line++;
+ continue; // Nothing to read or comment.
+ }
+
+ ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, Vector<Vector<String>>(), "Invalid line '" + l + "' while parsing: " + path + ":" + itos(line));
+
+ l = l.substr(1, l.length());
+ // Find final quote, ignoring escaped ones (\").
+ // The escape_next logic is necessary to properly parse things like \\"
+ // where the backslash is the one being escaped, not the quote.
+ int end_pos = -1;
+ bool escape_next = false;
+ for (int i = 0; i < l.length(); i++) {
+ if (l[i] == '\\' && !escape_next) {
+ escape_next = true;
+ continue;
+ }
+
+ if (l[i] == '"' && !escape_next) {
+ end_pos = i;
+ break;
+ }
+
+ escape_next = false;
+ }
+
+ ERR_FAIL_COND_V_MSG(end_pos == -1, Vector<Vector<String>>(), "Expected '\"' at end of message while parsing: " + path + ":" + itos(line));
+
+ l = l.substr(0, end_pos);
+ l = l.c_unescape();
+
+ if (status == STATUS_READING_ID) {
+ msg_id += l;
+ } else if (status == STATUS_READING_CONTEXT) {
+ msg_context += l;
+ } else if (status == STATUS_READING_PLURAL) {
+ msg_id_plural += l;
+ }
+
+ line++;
}
}
etl++;
}
- return msgids;
+ return list;
}
diff --git a/editor/editor_translation.h b/editor/editor_translation.h
index 4785495629..eee9e533c4 100644
--- a/editor/editor_translation.h
+++ b/editor/editor_translation.h
@@ -40,6 +40,6 @@ void load_editor_translations(const String &p_locale);
void load_property_translations(const String &p_locale);
void load_doc_translations(const String &p_locale);
void load_extractable_translations(const String &p_locale);
-List<StringName> get_extractable_message_list();
+Vector<Vector<String>> get_extractable_message_list();
#endif // EDITOR_TRANSLATION_H
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index ef77e5340b..4c7c723dd5 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -261,7 +261,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
if (p_unfold_path && current_path.begins_with(lpath) && current_path != lpath) {
subdirectory_item->set_collapsed(false);
} else {
- subdirectory_item->set_collapsed(uncollapsed_paths.find(lpath) < 0);
+ subdirectory_item->set_collapsed(!uncollapsed_paths.has(lpath));
}
if (!searched_tokens.is_empty() && _matches_all_search_tokens(dname)) {
parent_should_expand = true;
@@ -407,7 +407,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo
favorites_item->set_icon(0, get_editor_theme_icon(SNAME("Favorites")));
favorites_item->set_text(0, TTR("Favorites:"));
favorites_item->set_metadata(0, "Favorites");
- favorites_item->set_collapsed(p_uncollapsed_paths.find("Favorites") < 0);
+ favorites_item->set_collapsed(!p_uncollapsed_paths.has("Favorites"));
Vector<String> favorite_paths = EditorSettings::get_singleton()->get_favorites();
@@ -2300,7 +2300,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
TreeItem *selected = tree->get_root();
selected = tree->get_next_selected(selected);
while (selected) {
- if (p_selected.find(selected->get_metadata(0)) >= 0) {
+ if (p_selected.has(selected->get_metadata(0))) {
selected->set_collapsed(false);
}
selected = tree->get_next_selected(selected);
diff --git a/editor/import/3d/resource_importer_obj.cpp b/editor/import/3d/resource_importer_obj.cpp
index f5bf60175a..6d68e93c75 100644
--- a/editor/import/3d/resource_importer_obj.cpp
+++ b/editor/import/3d/resource_importer_obj.cpp
@@ -217,7 +217,7 @@ static Error _parse_obj(const String &p_path, List<Ref<ImporterMesh>> &r_meshes,
0x14c, // IMAGE_FILE_MACHINE_I386
0x200, // IMAGE_FILE_MACHINE_IA64
};
- ERR_FAIL_COND_V_MSG(coff_header_machines.find(first_bytes) != -1, ERR_FILE_CORRUPT, vformat("Couldn't read OBJ file '%s', it seems to be binary, corrupted, or empty.", p_path));
+ ERR_FAIL_COND_V_MSG(coff_header_machines.has(first_bytes), ERR_FILE_CORRUPT, vformat("Couldn't read OBJ file '%s', it seems to be binary, corrupted, or empty.", p_path));
f->seek(0);
Ref<ImporterMesh> mesh;
diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp
index 707be84381..36cbf253cc 100644
--- a/editor/import/3d/resource_importer_scene.cpp
+++ b/editor/import/3d/resource_importer_scene.cpp
@@ -387,7 +387,7 @@ static bool _teststr(const String &p_what, const String &p_str) {
what = what.substr(0, what.length() - 1);
}
- if (what.findn("$" + p_str) != -1) { //blender and other stuff
+ if (what.containsn("$" + p_str)) { // Blender and other stuff.
return true;
}
if (what.to_lower().ends_with("-" + p_str)) { //collada only supports "_" and "-" besides letters
@@ -410,7 +410,7 @@ static String _fixstr(const String &p_what, const String &p_str) {
String end = p_what.substr(what.length(), p_what.length() - what.length());
- if (what.findn("$" + p_str) != -1) { //blender and other stuff
+ if (what.containsn("$" + p_str)) { // Blender and other stuff.
return what.replace("$" + p_str, "") + end;
}
if (what.to_lower().ends_with("-" + p_str)) { //collada only supports "_" and "-" besides letters
@@ -2086,12 +2086,12 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor
p_options.has("generate/physics") &&
p_options["generate/physics"].operator bool();
- if (p_option.find("physics/") >= 0) {
+ if (p_option.contains("physics/")) {
// Show if need to generate collisions.
return generate_physics;
}
- if (p_option.find("decomposition/") >= 0) {
+ if (p_option.contains("decomposition/")) {
// Show if need to generate collisions.
if (generate_physics &&
// Show if convex is enabled.
@@ -2285,8 +2285,8 @@ bool ResourceImporterScene::get_internal_option_update_view_required(InternalImp
if (
p_option == "generate/physics" ||
p_option == "physics/shape_type" ||
- p_option.find("decomposition/") >= 0 ||
- p_option.find("primitive/") >= 0) {
+ p_option.contains("decomposition/") ||
+ p_option.contains("primitive/")) {
return true;
}
} break;
diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp
index a667f94a62..143de82765 100644
--- a/editor/input_event_configuration_dialog.cpp
+++ b/editor/input_event_configuration_dialog.cpp
@@ -285,7 +285,7 @@ void InputEventConfigurationDialog::_update_input_list() {
for (int i = 0; i < keycode_get_count(); i++) {
String name = keycode_get_name_by_index(i);
- if (!search_term.is_empty() && name.findn(search_term) == -1) {
+ if (!search_term.is_empty() && !name.containsn(search_term)) {
continue;
}
@@ -309,7 +309,7 @@ void InputEventConfigurationDialog::_update_input_list() {
mb->set_button_index(mouse_buttons[i]);
String desc = EventListenerLineEdit::get_event_text(mb, false);
- if (!search_term.is_empty() && desc.findn(search_term) == -1) {
+ if (!search_term.is_empty() && !desc.containsn(search_term)) {
continue;
}
@@ -332,7 +332,7 @@ void InputEventConfigurationDialog::_update_input_list() {
joyb->set_button_index((JoyButton)i);
String desc = EventListenerLineEdit::get_event_text(joyb, false);
- if (!search_term.is_empty() && desc.findn(search_term) == -1) {
+ if (!search_term.is_empty() && !desc.containsn(search_term)) {
continue;
}
@@ -358,7 +358,7 @@ void InputEventConfigurationDialog::_update_input_list() {
joym->set_axis_value(direction);
String desc = EventListenerLineEdit::get_event_text(joym, false);
- if (!search_term.is_empty() && desc.findn(search_term) == -1) {
+ if (!search_term.is_empty() && !desc.containsn(search_term)) {
continue;
}
diff --git a/editor/plugins/editor_plugin.cpp b/editor/plugins/editor_plugin.cpp
index f42a1555a2..2b3c187352 100644
--- a/editor/plugins/editor_plugin.cpp
+++ b/editor/plugins/editor_plugin.cpp
@@ -100,6 +100,11 @@ void EditorPlugin::remove_control_from_bottom_panel(Control *p_control) {
EditorNode::get_bottom_panel()->remove_item(p_control);
}
+void EditorPlugin::set_dock_tab_icon(Control *p_control, const Ref<Texture2D> &p_icon) {
+ ERR_FAIL_NULL(p_control);
+ EditorDockManager::get_singleton()->set_dock_tab_icon(p_control, p_icon);
+}
+
void EditorPlugin::add_control_to_container(CustomControlContainer p_location, Control *p_control) {
ERR_FAIL_NULL(p_control);
@@ -565,6 +570,7 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_control_from_docks", "control"), &EditorPlugin::remove_control_from_docks);
ClassDB::bind_method(D_METHOD("remove_control_from_bottom_panel", "control"), &EditorPlugin::remove_control_from_bottom_panel);
ClassDB::bind_method(D_METHOD("remove_control_from_container", "container", "control"), &EditorPlugin::remove_control_from_container);
+ ClassDB::bind_method(D_METHOD("set_dock_tab_icon", "control", "icon"), &EditorPlugin::set_dock_tab_icon);
ClassDB::bind_method(D_METHOD("add_tool_menu_item", "name", "callable"), &EditorPlugin::add_tool_menu_item);
ClassDB::bind_method(D_METHOD("add_tool_submenu_item", "name", "submenu"), &EditorPlugin::add_tool_submenu_item);
ClassDB::bind_method(D_METHOD("remove_tool_menu_item", "name"), &EditorPlugin::remove_tool_menu_item);
diff --git a/editor/plugins/editor_plugin.h b/editor/plugins/editor_plugin.h
index f45a512b89..f6c4b35407 100644
--- a/editor/plugins/editor_plugin.h
+++ b/editor/plugins/editor_plugin.h
@@ -151,6 +151,8 @@ public:
void remove_control_from_docks(Control *p_control);
void remove_control_from_bottom_panel(Control *p_control);
+ void set_dock_tab_icon(Control *p_control, const Ref<Texture2D> &p_icon);
+
void add_tool_menu_item(const String &p_name, const Callable &p_callable);
void add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu);
void remove_tool_menu_item(const String &p_name);
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index 3f86d30368..de56767929 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -912,7 +912,9 @@ void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const R
Color color = instantiated ? instantiated_color : p_albedo;
if (!selected) {
- color.a *= 0.85;
+ color.r *= 0.6;
+ color.g *= 0.6;
+ color.b *= 0.6;
}
icon->set_albedo(color);
@@ -921,9 +923,8 @@ void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const R
icon->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
icon->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
icon->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
- icon->set_cull_mode(StandardMaterial3D::CULL_DISABLED);
- icon->set_depth_draw_mode(StandardMaterial3D::DEPTH_DRAW_DISABLED);
- icon->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ icon->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA_SCISSOR);
+ icon->set_alpha_scissor_threshold(0.1);
icon->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, p_texture);
icon->set_flag(StandardMaterial3D::FLAG_FIXED_SIZE, true);
icon->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 2f479527f3..723dbf5d6c 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -374,7 +374,7 @@ void ScriptEditorQuickOpen::_update_search() {
for (int i = 0; i < functions.size(); i++) {
String file = functions[i];
- if ((search_box->get_text().is_empty() || file.findn(search_box->get_text()) != -1)) {
+ if ((search_box->get_text().is_empty() || file.containsn(search_box->get_text()))) {
TreeItem *ti = search_options->create_item(root);
ti->set_text(0, file);
if (root->get_first_child() == ti) {
@@ -742,7 +742,7 @@ void ScriptEditor::_add_recent_script(const String &p_path) {
}
Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scripts", Array());
- if (rc.find(p_path) != -1) {
+ if (rc.has(p_path)) {
rc.erase(p_path);
}
rc.push_front(p_path);
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index a28952d8e7..eef9557ca8 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -1312,7 +1312,7 @@ void SpriteFramesEditor::_update_library_impl() {
TreeItem *selected = nullptr;
for (const StringName &E : anim_names) {
String name = E;
- if (searching && name.to_lower().find(searched_string) < 0) {
+ if (searching && !name.to_lower().contains(searched_string)) {
continue;
}
TreeItem *it = animations->create_item(anim_root);
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 166ed05748..4cc88aab34 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -106,7 +106,7 @@ void ThemeItemImportTree::_update_items_tree() {
type_node->set_checked(IMPORT_ITEM_DATA, false);
type_node->set_editable(IMPORT_ITEM_DATA, true);
- bool is_matching_filter = (filter_text.is_empty() || type_name.findn(filter_text) > -1);
+ bool is_matching_filter = (filter_text.is_empty() || type_name.containsn(filter_text));
bool has_filtered_items = false;
for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {
@@ -120,7 +120,7 @@ void ThemeItemImportTree::_update_items_tree() {
for (const StringName &F : names) {
String item_name = (String)F;
- bool is_item_matching_filter = (item_name.findn(filter_text) > -1);
+ bool is_item_matching_filter = item_name.containsn(filter_text);
if (!filter_text.is_empty() && !is_matching_filter && !is_item_matching_filter) {
continue;
}
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index e3f7aa5e6d..35db52a42e 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1957,7 +1957,7 @@ void VisualShaderEditor::_update_options_menu() {
}
for (int i = 0; i < add_options.size(); i++) {
- if (!use_filter || add_options[i].name.findn(filter) != -1) {
+ if (!use_filter || add_options[i].name.containsn(filter)) {
// port type filtering
if (members_output_port_type != VisualShaderNode::PORT_TYPE_MAX || members_input_port_type != VisualShaderNode::PORT_TYPE_MAX) {
Ref<VisualShaderNode> vsn;
diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp
index 8323ae944b..76b6593f1d 100644
--- a/editor/pot_generator.cpp
+++ b/editor/pot_generator.cpp
@@ -34,7 +34,6 @@
#include "core/error/error_macros.h"
#include "editor/editor_translation.h"
#include "editor/editor_translation_parser.h"
-#include "plugins/packed_scene_translation_parser_plugin.h"
POTGenerator *POTGenerator::singleton = nullptr;
@@ -66,8 +65,6 @@ void POTGenerator::generate_pot(const String &p_file) {
// Clear all_translation_strings of the previous round.
all_translation_strings.clear();
- List<StringName> extractable_msgids = get_extractable_message_list();
-
// Collect all translatable strings according to files order in "POT Generation" setting.
for (int i = 0; i < files.size(); i++) {
Vector<String> msgids;
@@ -92,8 +89,8 @@ void POTGenerator::generate_pot(const String &p_file) {
}
if (GLOBAL_GET("internationalization/locale/translation_add_builtin_strings_to_pot")) {
- for (const StringName &extractable_msgid : extractable_msgids) {
- _add_new_msgid(extractable_msgid, "", "", "");
+ for (const Vector<String> &extractable_msgids : get_extractable_message_list()) {
+ _add_new_msgid(extractable_msgids[0], extractable_msgids[1], extractable_msgids[2], "");
}
}
diff --git a/editor/project_manager/project_list.cpp b/editor/project_manager/project_list.cpp
index d125754dd7..b7520abc99 100644
--- a/editor/project_manager/project_list.cpp
+++ b/editor/project_manager/project_list.cpp
@@ -545,7 +545,7 @@ void ProjectList::sort_projects() {
}
// When searching, display projects whose name or path contain the search term and whose tags match the searched tags.
- item_visible = !missing_tags && (search_term.is_empty() || item.project_name.findn(search_term) != -1 || search_path.findn(search_term) != -1);
+ item_visible = !missing_tags && (search_term.is_empty() || item.project_name.containsn(search_term) || search_path.containsn(search_term));
}
item.control->set_visible(item_visible);
diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp
index eef68d918a..77ab629ba6 100644
--- a/editor/property_selector.cpp
+++ b/editor/property_selector.cpp
@@ -190,7 +190,7 @@ void PropertySelector::_update_search() {
continue;
}
- if (!search_box->get_text().is_empty() && E.name.findn(search_text) == -1) {
+ if (!search_box->get_text().is_empty() && !E.name.containsn(search_text)) {
continue;
}
@@ -203,7 +203,7 @@ void PropertySelector::_update_search() {
item->set_metadata(0, E.name);
item->set_icon(0, type_icons[E.type]);
- if (!found && !search_box->get_text().is_empty() && E.name.findn(search_text) != -1) {
+ if (!found && !search_box->get_text().is_empty() && E.name.containsn(search_text)) {
item->select(0);
found = true;
}
@@ -281,7 +281,7 @@ void PropertySelector::_update_search() {
continue;
}
- if (!search_box->get_text().is_empty() && name.findn(search_text) == -1) {
+ if (!search_box->get_text().is_empty() && !name.containsn(search_text)) {
continue;
}
@@ -330,7 +330,7 @@ void PropertySelector::_update_search() {
item->set_metadata(0, name);
item->set_selectable(0, true);
- if (!found && !search_box->get_text().is_empty() && name.findn(search_text) != -1) {
+ if (!found && !search_box->get_text().is_empty() && name.containsn(search_text)) {
item->select(0);
found = true;
}
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 9fca334e7c..45c437b5f3 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -473,7 +473,7 @@ void RenameDialog::_error_handler(void *p_self, const char *p_func, const char *
String source_file = String::utf8(p_file);
// Only show first error that is related to "regex"
- if (self->has_errors || source_file.find("regex") < 0) {
+ if (self->has_errors || !source_file.contains("regex")) {
return;
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index ee2a43bd55..3a1de937e2 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1297,7 +1297,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
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) {
+ if (new_unique_names.has(name) || 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);
diff --git a/gles3_builders.py b/gles3_builders.py
index 78882f97fd..1491927feb 100644
--- a/gles3_builders.py
+++ b/gles3_builders.py
@@ -588,7 +588,7 @@ def build_gles3_header(
fd.write("\t}\n\n")
fd.write("};\n\n")
- fd.write("#endif\n\n")
+ fd.write("#endif\n")
def build_gles3_headers(target, source, env):
diff --git a/main/main.cpp b/main/main.cpp
index 2def90bc1a..1ba336221f 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -637,6 +637,7 @@ void Main::print_help(const char *p_binary) {
#endif // DISABLE_DEPRECATED
print_help_option("--doctool [path]", "Dump the engine API reference to the given <path> (defaults to current directory) in XML format, merging if existing files are found.\n", CLI_OPTION_AVAILABILITY_EDITOR);
print_help_option("--no-docbase", "Disallow dumping the base types (used with --doctool).\n", CLI_OPTION_AVAILABILITY_EDITOR);
+ print_help_option("--gdextension-docs", "Rather than dumping the engine API, generate API reference from all the GDExtensions loaded in the current project (used with --doctool).\n", CLI_OPTION_AVAILABILITY_EDITOR);
#ifdef MODULE_GDSCRIPT_ENABLED
print_help_option("--gdscript-docs <path>", "Rather than dumping the engine API, generate API reference from the inline documentation in the GDScript files found in <path> (used with --doctool).\n", CLI_OPTION_AVAILABILITY_EDITOR);
#endif
@@ -2992,7 +2993,7 @@ Error Main::setup2() {
// Dummy text driver cannot draw any text, making the editor unusable if selected.
continue;
}
- if (!text_driver_options.is_empty() && text_driver_options.find(",") == -1) {
+ if (!text_driver_options.is_empty() && !text_driver_options.contains(",")) {
// Not the first option; add a comma before it as a separator for the property hint.
text_driver_options += ",";
}
@@ -3214,6 +3215,9 @@ int Main::start() {
#ifdef TOOLS_ENABLED
} else if (E->get() == "--no-docbase") {
gen_flags.set_flag(DocTools::GENERATE_FLAG_SKIP_BASIC_TYPES);
+ } else if (E->get() == "--gdextension-docs") {
+ gen_flags.set_flag(DocTools::GENERATE_FLAG_SKIP_BASIC_TYPES);
+ gen_flags.set_flag(DocTools::GENERATE_FLAG_EXTENSION_CLASSES_ONLY);
#ifndef DISABLE_DEPRECATED
} else if (E->get() == "--convert-3to4") {
converting_project = true;
@@ -3340,29 +3344,34 @@ int Main::start() {
HashSet<String> checked_paths;
print_line("Loading docs...");
- for (int i = 0; i < _doc_data_class_path_count; i++) {
- // Custom modules are always located by absolute path.
- String path = _doc_data_class_paths[i].path;
- if (path.is_relative_path()) {
- path = doc_tool_path.path_join(path);
- }
- String name = _doc_data_class_paths[i].name;
- doc_data_classes[name] = path;
- if (!checked_paths.has(path)) {
- checked_paths.insert(path);
-
- // Create the module documentation directory if it doesn't exist
- Ref<DirAccess> da = DirAccess::create_for_path(path);
- err = da->make_dir_recursive(path);
- ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error: Can't create directory: " + path + ": " + itos(err));
-
- print_line("Loading docs from: " + path);
- err = docsrc.load_classes(path);
- ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error loading docs from: " + path + ": " + itos(err));
+ const bool gdextension_docs = gen_flags.has_flag(DocTools::GENERATE_FLAG_EXTENSION_CLASSES_ONLY);
+
+ if (!gdextension_docs) {
+ for (int i = 0; i < _doc_data_class_path_count; i++) {
+ // Custom modules are always located by absolute path.
+ String path = _doc_data_class_paths[i].path;
+ if (path.is_relative_path()) {
+ path = doc_tool_path.path_join(path);
+ }
+ String name = _doc_data_class_paths[i].name;
+ doc_data_classes[name] = path;
+ if (!checked_paths.has(path)) {
+ checked_paths.insert(path);
+
+ // Create the module documentation directory if it doesn't exist
+ Ref<DirAccess> da = DirAccess::create_for_path(path);
+ err = da->make_dir_recursive(path);
+ ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error: Can't create directory: " + path + ": " + itos(err));
+
+ print_line("Loading docs from: " + path);
+ err = docsrc.load_classes(path);
+ ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error loading docs from: " + path + ": " + itos(err));
+ }
}
}
- String index_path = doc_tool_path.path_join("doc/classes");
+ // For GDExtension docs, use a path that is compatible with Godot modules.
+ String index_path = gdextension_docs ? doc_tool_path.path_join("doc_classes") : doc_tool_path.path_join("doc/classes");
// Create the main documentation directory if it doesn't exist
Ref<DirAccess> da = DirAccess::create_for_path(index_path);
err = da->make_dir_recursive(index_path);
@@ -3383,7 +3392,7 @@ int Main::start() {
}
print_line("Generating new docs...");
- err = doc.save_classes(index_path, doc_data_classes);
+ err = doc.save_classes(index_path, doc_data_classes, !gdextension_docs);
ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error saving new docs:" + itos(err));
print_line("Deleting docs cache...");
diff --git a/misc/dist/ios_xcode/godot_ios/en.lproj/InfoPlist.strings b/misc/dist/ios_xcode/godot_ios/en.lproj/InfoPlist.strings
index 477b28ff8f..b92732c79e 100644
--- a/misc/dist/ios_xcode/godot_ios/en.lproj/InfoPlist.strings
+++ b/misc/dist/ios_xcode/godot_ios/en.lproj/InfoPlist.strings
@@ -1,2 +1 @@
/* Localized versions of Info.plist keys */
-
diff --git a/misc/error_suppressions/tsan.txt b/misc/error_suppressions/tsan.txt
index 7c3d836f6c..ac46371f8b 100644
--- a/misc/error_suppressions/tsan.txt
+++ b/misc/error_suppressions/tsan.txt
@@ -5,4 +5,3 @@ deadlock:tests/core/templates/test_command_queue.h
deadlock:modules/text_server_adv/text_server_adv.cpp
deadlock:modules/text_server_fb/text_server_fb.cpp
race:modules/navigation/nav_map.cpp
-
diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected
index 55a4e0b18c..d7bb67cfbc 100644
--- a/misc/extension_api_validation/4.2-stable.expected
+++ b/misc/extension_api_validation/4.2-stable.expected
@@ -321,7 +321,7 @@ GH-86978
--------
Validate extension JSON: Error: Field 'classes/TextEdit/methods/set_selection_mode/arguments': size changed value in new API, from 4 to 1.
-Removed optional arguments set_selection_mode, use set_selection_origin_line/column instead.
+Removed optional arguments set_selection_mode, use set_selection_origin_line/column instead.
Compatibility methods registered.
@@ -343,4 +343,4 @@ GH-91143
--------
Validate extension JSON: Error: Field 'classes/Input/methods/vibrate_handheld/arguments': size changed value in new API, from 1 to 2.
-Added optional argument. Compatibility method registered. \ No newline at end of file
+Added optional argument. Compatibility method registered.
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index cec03b7246..a4a3c768e9 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -852,7 +852,7 @@ int CSGBrushOperation::Build2DFaces::_add_vertex(const Vertex2D &p_vertex) {
}
void CSGBrushOperation::Build2DFaces::_add_vertex_idx_sorted(Vector<int> &r_vertex_indices, int p_new_vertex_index) {
- if (p_new_vertex_index >= 0 && r_vertex_indices.find(p_new_vertex_index) == -1) {
+ if (p_new_vertex_index >= 0 && !r_vertex_indices.has(p_new_vertex_index)) {
ERR_FAIL_COND_MSG(p_new_vertex_index >= vertices.size(), "Invalid vertex index.");
// The first vertex.
diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml
index 5ca1ec2228..5795dd8976 100644
--- a/modules/enet/doc_classes/ENetConnection.xml
+++ b/modules/enet/doc_classes/ENetConnection.xml
@@ -151,7 +151,7 @@
<param index="1" name="destination_port" type="int" />
<param index="2" name="packet" type="PackedByteArray" />
<description>
- Sends a [param packet] toward a destination from the address and port currently bound by this ENetConnection instance.
+ Sends a [param packet] toward a destination from the address and port currently bound by this ENetConnection instance.
This is useful as it serves to establish entries in NAT routing tables on all devices between this bound instance and the public facing internet, allowing a prospective client's connection packets to be routed backward through the NAT device(s) between the public internet and this host.
This requires forward knowledge of a prospective client's address and communication port as seen by the public internet - after any NAT devices have handled their connection request. This information can be obtained by a [url=https://en.wikipedia.org/wiki/STUN]STUN[/url] service, and must be handed off to your host by an entity that is not the prospective client. This will never work for a client behind a Symmetric NAT due to the nature of the Symmetric NAT routing algorithm, as their IP and Port cannot be known beforehand.
</description>
diff --git a/modules/gdscript/README.md b/modules/gdscript/README.md
index 865475d37d..a4367b39ff 100644
--- a/modules/gdscript/README.md
+++ b/modules/gdscript/README.md
@@ -136,4 +136,4 @@ There are many other classes in the GDScript module. Here is a brief overview of
- The [virtual machine](gdscript_vm.cpp) is essentially defined as calling `GDScriptFunction::call()`.
- Editor-related functions can be found in parts of `GDScriptLanguage`, originally declared in [`gdscript.h`](gdscript.h) but defined in [`gdscript_editor.cpp`](gdscript_editor.cpp). Code highlighting can be found in [`GDScriptSyntaxHighlighter`](editor/gdscript_highlighter.h).
- GDScript decompilation is found in [`gdscript_disassembler.cpp`](gdscript_disassembler.h), defined as `GDScriptFunction::disassemble()`.
-- Documentation generation from GDScript comments in [`GDScriptDocGen`](editor/gdscript_docgen.h) \ No newline at end of file
+- Documentation generation from GDScript comments in [`GDScriptDocGen`](editor/gdscript_docgen.h)
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 9caf772b5c..cae85d7c70 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1695,6 +1695,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
if (full) {
// If not fully constant, setting this value is detrimental to the inference.
r_type.value = a;
+ r_type.type.is_constant = true;
}
r_type.type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
r_type.type.kind = GDScriptParser::DataType::BUILTIN;
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 819611099e..09defdf8cd 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -695,7 +695,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
} else {
ScriptLanguage::LookupResult ret;
- if (symbol_identifier == "new" && parser->get_lines()[p_doc_pos.position.line].replace(" ", "").replace("\t", "").find("new(") > -1) {
+ if (symbol_identifier == "new" && parser->get_lines()[p_doc_pos.position.line].replace(" ", "").replace("\t", "").contains("new(")) {
symbol_identifier = "_init";
}
if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_required), symbol_identifier, path, nullptr, ret)) {
diff --git a/modules/gdscript/tests/scripts/analyzer/features/cast_enum_to_int.gd b/modules/gdscript/tests/scripts/analyzer/features/cast_enum_to_int.gd
index 77ef9e2073..f861cadb5d 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/cast_enum_to_int.gd
+++ b/modules/gdscript/tests/scripts/analyzer/features/cast_enum_to_int.gd
@@ -6,4 +6,3 @@ func test():
var a := Foo.A
var b := a as int + 1
print(b)
-
diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd b/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd
index 9d0324ead8..738b5f7b3a 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd
+++ b/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd
@@ -3,4 +3,3 @@ const Constants = preload("gdscript_to_preload.notest.gd")
func test():
var a := Constants.A
print(a)
-
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
index 009ab9f9ce..9c580b711d 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
{"display": "func_of_a"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
index 0fb46a4704..446198dd35 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; AnimationPlayer
{"display": "autoplay"},
{"display": "play"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
index 009ab9f9ce..9c580b711d 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
{"display": "func_of_a"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
index 0fb46a4704..446198dd35 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; AnimationPlayer
{"display": "autoplay"},
{"display": "play"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg
index 009ab9f9ce..9c580b711d 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
{"display": "func_of_a"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg
index 0fb46a4704..446198dd35 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; AnimationPlayer
{"display": "autoplay"},
{"display": "play"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
index 009ab9f9ce..9c580b711d 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
{"display": "func_of_a"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
index 0fb46a4704..446198dd35 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; AnimationPlayer
{"display": "autoplay"},
{"display": "play"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
index a72b489be6..8b68d51a89 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
@@ -4,7 +4,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
{"display": "func_of_a"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
index adf06c8707..72c0549d3b 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
@@ -4,7 +4,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; AnimationPlayer
{"display": "autoplay"},
{"display": "play"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg
index 009ab9f9ce..9c580b711d 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
{"display": "func_of_a"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg
index 0fb46a4704..446198dd35 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; AnimationPlayer
{"display": "autoplay"},
{"display": "play"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
index 009ab9f9ce..9c580b711d 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
{"display": "func_of_a"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
index 0fb46a4704..446198dd35 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
@@ -6,7 +6,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; AnimationPlayer
{"display": "autoplay"},
{"display": "play"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
index a72b489be6..8b68d51a89 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
@@ -4,7 +4,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; GDScript: class_a.notest.gd
{"display": "property_of_a"},
{"display": "func_of_a"},
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
index adf06c8707..72c0549d3b 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
@@ -4,7 +4,7 @@ include=[
{"display": "add_child"},
{"display": "owner"},
{"display": "child_entered_tree"},
-
+
; AnimationPlayer
{"display": "autoplay"},
{"display": "play"},
diff --git a/modules/gdscript/tests/scripts/lsp/lambdas.gd b/modules/gdscript/tests/scripts/lsp/lambdas.gd
index 6f5d468eea..fbee264f3b 100644
--- a/modules/gdscript/tests/scripts/lsp/lambdas.gd
+++ b/modules/gdscript/tests/scripts/lsp/lambdas.gd
@@ -7,7 +7,7 @@ var lambda_member1 := func(alpha: int, beta): return alpha + beta
# | | ^^^^^ \1:alpha -> \1:alpha
# ^^^^^^^^^^^^^^ \1 -> \1
-var lambda_member2 := func(alpha, beta: int) -> int:
+var lambda_member2 := func(alpha, beta: int) -> int:
# | | | | | |
# | | | | | |
# | | | | ^^^^ \2:beta -> \2:beta
@@ -76,7 +76,7 @@ func _ready() -> void:
# | | | | ^^^^ \local:beta -> \local:beta
# | | ^^^^^ \local:alpha -> \local:alpha
# ^^^^^^^^^^^^ \local -> \local
-
+
var value := 42
# ^^^^^ local:value -> local:value
var lambda_capture = func(): return value + some_name.length()
diff --git a/modules/gdscript/tests/scripts/lsp/local_variables.gd b/modules/gdscript/tests/scripts/lsp/local_variables.gd
index b6cc46f7da..43e8937800 100644
--- a/modules/gdscript/tests/scripts/lsp/local_variables.gd
+++ b/modules/gdscript/tests/scripts/lsp/local_variables.gd
@@ -9,7 +9,7 @@ func test_member() -> void:
# ^^^^ test -> test
test += 3
#<^^ -> test
- member += 5
+ member += 5
#<^^^^ -> member
test = return_arg(test)
# | ^^^^ -> test
@@ -22,4 +22,4 @@ func return_arg(arg: int) -> int:
arg += 2
#<^ -> arg
return arg
- # ^^^ -> arg \ No newline at end of file
+ # ^^^ -> arg
diff --git a/modules/gdscript/tests/scripts/lsp/properties.gd b/modules/gdscript/tests/scripts/lsp/properties.gd
index 8dfaee2e5b..1acaddbe2c 100644
--- a/modules/gdscript/tests/scripts/lsp/properties.gd
+++ b/modules/gdscript/tests/scripts/lsp/properties.gd
@@ -16,7 +16,7 @@ var prop3 := 42:
#<^^^ -> prop3
var prop4: int:
# ^^^^^ prop4 -> prop4
- get:
+ get:
return 42
var prop5 := 42:
# ^^^^^ prop5 -> prop5
diff --git a/modules/gdscript/tests/scripts/lsp/scopes.gd b/modules/gdscript/tests/scripts/lsp/scopes.gd
index 20b8fb9bd7..9314ab427c 100644
--- a/modules/gdscript/tests/scripts/lsp/scopes.gd
+++ b/modules/gdscript/tests/scripts/lsp/scopes.gd
@@ -68,16 +68,16 @@ func m():
match value:
# ^^^^^ -> m:value
- 13:
+ 13:
print(value)
# ^^^^^ -> m:value
- [var start, _, var end]:
+ [var start, _, var end]:
# | | ^^^ m:match:array:end -> m:match:array:end
# ^^^^^ m:match:array:start -> m:match:array:start
print(start + end)
# | | ^^^ -> m:match:array:end
# ^^^^^ -> m:match:array:start
- { "name": var name }:
+ { "name": var name }:
# ^^^^ m:match:dict:var -> m:match:dict:var
print(name)
# ^^^^ -> m:match:dict:var
@@ -87,10 +87,10 @@ func m():
# ^^^^^^^^ -> m:match:var
func m2():
- var value = 42
+ var value = 42
# ^^^^^ m2:value -> m2:value
- match value:
+ match value:
# ^^^^^ -> m2:value
{ "name": var name }:
# ^^^^ m2:match:dict:var -> m2:match:dict:var
diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd b/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd
index a278ea1154..24f4c14f50 100644
--- a/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd
+++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_patterns_with_array.gd
@@ -23,4 +23,3 @@ func test():
bar([3])
bar([4])
bar([5])
-
diff --git a/modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.gd b/modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.gd
index 35e4dbd6a0..a1a9e350b0 100644
--- a/modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/call_native_static_method_validated.gd
@@ -4,4 +4,3 @@ func test():
# Validated native static call without return value.
Node.print_orphan_nodes()
-
diff --git a/modules/gdscript/tests/test_lsp.h b/modules/gdscript/tests/test_lsp.h
index 6192272f80..b85c727bc5 100644
--- a/modules/gdscript/tests/test_lsp.h
+++ b/modules/gdscript/tests/test_lsp.h
@@ -227,7 +227,7 @@ Vector<InlineTestData> read_tests(const String &p_path) {
if (InlineTestData::try_parse(lines, i, d)) {
if (!d.name.is_empty()) {
// Safety check: names must be unique.
- if (names.find(d.name) != -1) {
+ if (names.has(d.name)) {
FAIL(vformat("Duplicated name '%s' in '%s'. Names must be unique!", d.name, p_path));
}
names.append(d.name);
diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
index d11300343a..fc184c9342 100644
--- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
@@ -77,7 +77,7 @@ void EditorSceneExporterGLTFSettings::_get_property_list(List<PropertyInfo> *p_l
for (PropertyInfo prop : _property_list) {
if (prop.name == "lossy_quality") {
String image_format = get("image_format");
- bool is_image_format_lossy = image_format == "JPEG" || image_format.findn("Lossy") != -1;
+ bool is_image_format_lossy = image_format == "JPEG" || image_format.containsn("Lossy");
prop.usage = is_image_format_lossy ? PROPERTY_USAGE_DEFAULT : PROPERTY_USAGE_STORAGE;
}
p_list->push_back(prop);
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 4c32a29ce0..575702bc54 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -7032,7 +7032,7 @@ void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> p_state) {
Vector<Ref<GLTFDocumentExtension>> GLTFDocument::all_document_extensions;
void GLTFDocument::register_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension, bool p_first_priority) {
- if (all_document_extensions.find(p_extension) == -1) {
+ if (!all_document_extensions.has(p_extension)) {
if (p_first_priority) {
all_document_extensions.insert(0, p_extension);
} else {
diff --git a/modules/gltf/skin_tool.cpp b/modules/gltf/skin_tool.cpp
index 2fb55a5f9e..a344334d93 100644
--- a/modules/gltf/skin_tool.cpp
+++ b/modules/gltf/skin_tool.cpp
@@ -57,9 +57,9 @@ bool SkinTool::_capture_nodes_in_skin(const Vector<Ref<GLTFNode>> &nodes, Ref<GL
if (found_joint) {
// Mark it if we happen to find another skins joint...
- if (current_node->joint && p_skin->joints.find(p_node_index) < 0) {
+ if (current_node->joint && !p_skin->joints.has(p_node_index)) {
p_skin->joints.push_back(p_node_index);
- } else if (p_skin->non_joints.find(p_node_index) < 0) {
+ } else if (!p_skin->non_joints.has(p_node_index)) {
p_skin->non_joints.push_back(p_node_index);
}
}
@@ -79,7 +79,7 @@ void SkinTool::_capture_nodes_for_multirooted_skin(Vector<Ref<GLTFNode>> &r_node
const SkinNodeIndex parent = r_nodes[node_index]->parent;
disjoint_set.insert(node_index);
- if (p_skin->joints.find(parent) >= 0) {
+ if (p_skin->joints.has(parent)) {
disjoint_set.create_union(parent, node_index);
}
}
@@ -109,9 +109,9 @@ void SkinTool::_capture_nodes_for_multirooted_skin(Vector<Ref<GLTFNode>> &r_node
while (r_nodes[current_node]->height > maxHeight) {
SkinNodeIndex parent = r_nodes[current_node]->parent;
- if (r_nodes[parent]->joint && p_skin->joints.find(parent) < 0) {
+ if (r_nodes[parent]->joint && !p_skin->joints.has(parent)) {
p_skin->joints.push_back(parent);
- } else if (p_skin->non_joints.find(parent) < 0) {
+ } else if (!p_skin->non_joints.has(parent)) {
p_skin->non_joints.push_back(parent);
}
@@ -138,9 +138,9 @@ void SkinTool::_capture_nodes_for_multirooted_skin(Vector<Ref<GLTFNode>> &r_node
const SkinNodeIndex current_node = roots[i];
const SkinNodeIndex parent = r_nodes[current_node]->parent;
- if (r_nodes[parent]->joint && p_skin->joints.find(parent) < 0) {
+ if (r_nodes[parent]->joint && !p_skin->joints.has(parent)) {
p_skin->joints.push_back(parent);
- } else if (p_skin->non_joints.find(parent) < 0) {
+ } else if (!p_skin->non_joints.has(parent)) {
p_skin->non_joints.push_back(parent);
}
@@ -166,7 +166,7 @@ Error SkinTool::_expand_skin(Vector<Ref<GLTFNode>> &r_nodes, Ref<GLTFSkin> p_ski
const SkinNodeIndex parent = r_nodes[node_index]->parent;
disjoint_set.insert(node_index);
- if (all_skin_nodes.find(parent) >= 0) {
+ if (all_skin_nodes.has(parent)) {
disjoint_set.create_union(parent, node_index);
}
}
@@ -216,7 +216,7 @@ Error SkinTool::_verify_skin(Vector<Ref<GLTFNode>> &r_nodes, Ref<GLTFSkin> p_ski
const SkinNodeIndex parent = r_nodes[node_index]->parent;
disjoint_set.insert(node_index);
- if (all_skin_nodes.find(parent) >= 0) {
+ if (all_skin_nodes.has(parent)) {
disjoint_set.create_union(parent, node_index);
}
}
@@ -365,7 +365,7 @@ Error SkinTool::_determine_skeletons(
for (int j = 0; j < groups.size() && i != j; ++j) {
const Vector<SkinNodeIndex> &group = groups[j];
- if (group.find(node_i_parent) >= 0) {
+ if (group.has(node_i_parent)) {
const SkinNodeIndex node_j = highest_group_members[j];
skeleton_sets.create_union(node_i, node_j);
}
@@ -393,7 +393,7 @@ Error SkinTool::_determine_skeletons(
// If any of the the skeletons nodes exist in a skin, that skin now maps to the skeleton
for (int i = 0; i < skeleton_nodes.size(); ++i) {
SkinNodeIndex skel_node_i = skeleton_nodes[i];
- if (skin->joints.find(skel_node_i) >= 0 || skin->non_joints.find(skel_node_i) >= 0) {
+ if (skin->joints.has(skel_node_i) || skin->non_joints.has(skel_node_i)) {
skin->skeleton = skel_i;
continue;
}
@@ -454,7 +454,7 @@ Error SkinTool::_reparent_non_joint_skeleton_subtrees(
subtree_set.insert(node_i);
const SkinNodeIndex parent_i = nodes[node_i]->parent;
- if (parent_i >= 0 && p_non_joints.find(parent_i) >= 0 && !nodes[parent_i]->joint) {
+ if (parent_i >= 0 && p_non_joints.has(parent_i) && !nodes[parent_i]->joint) {
subtree_set.create_union(parent_i, node_i);
}
}
diff --git a/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp b/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp
index 9960c4e07c..9b51221df6 100644
--- a/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp
+++ b/modules/interactive_music/editor/audio_stream_interactive_editor_plugin.cpp
@@ -31,13 +31,9 @@
#include "audio_stream_interactive_editor_plugin.h"
#include "../audio_stream_interactive.h"
-#include "core/input/input.h"
-#include "core/os/keyboard.h"
#include "editor/editor_node.h"
-#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
-#include "editor/themes/editor_scale.h"
#include "scene/gui/check_box.h"
#include "scene/gui/option_button.h"
#include "scene/gui/spin_box.h"
@@ -73,7 +69,7 @@ void AudioStreamInteractiveTransitionEditor::_edited() {
int filler = use_filler ? filler_clip->get_selected() - 1 : 0;
bool hold = hold_previous->is_pressed();
- EditorUndoRedoManager::get_singleton()->create_action("Edit Transitions");
+ EditorUndoRedoManager::get_singleton()->create_action(TTR("Edit Transitions"));
for (int i = 0; i < selected.size(); i++) {
if (!enabled) {
if (audio_stream_interactive->has_transition(selected[i].x, selected[i].y)) {
@@ -177,7 +173,6 @@ void AudioStreamInteractiveTransitionEditor::_update_transitions() {
};
for (int i = 0; i <= clip_count; i++) {
for (int j = 0; j <= clip_count; j++) {
- String txt;
int from = i == clip_count ? AudioStreamInteractive::CLIP_ANY : i;
int to = j == clip_count ? AudioStreamInteractive::CLIP_ANY : j;
@@ -187,32 +182,34 @@ void AudioStreamInteractiveTransitionEditor::_update_transitions() {
if (!exists) {
if (audio_stream_interactive->has_transition(AudioStreamInteractive::CLIP_ANY, to)) {
from = AudioStreamInteractive::CLIP_ANY;
- tooltip = "Using Any Clip -> " + audio_stream_interactive->get_clip_name(to) + ".";
+ tooltip = vformat(TTR("Using Any Clip -> %s."), audio_stream_interactive->get_clip_name(to));
} else if (audio_stream_interactive->has_transition(from, AudioStreamInteractive::CLIP_ANY)) {
to = AudioStreamInteractive::CLIP_ANY;
- tooltip = "Using " + audio_stream_interactive->get_clip_name(from) + " -> Any Clip.";
+ tooltip = vformat(TTR("Using %s -> Any Clip."), audio_stream_interactive->get_clip_name(from));
} else if (audio_stream_interactive->has_transition(AudioStreamInteractive::CLIP_ANY, AudioStreamInteractive::CLIP_ANY)) {
from = to = AudioStreamInteractive::CLIP_ANY;
- tooltip = "Using All CLips -> Any Clip.";
+ tooltip = TTR("Using All Clips -> Any Clip.");
} else {
- tooltip = "No transition available.";
+ tooltip = TTR("No transition available.");
}
}
+ String from_time;
+ String to_time;
if (audio_stream_interactive->has_transition(from, to)) {
icon = fade_icons[audio_stream_interactive->get_transition_fade_mode(from, to)];
switch (audio_stream_interactive->get_transition_from_time(from, to)) {
case AudioStreamInteractive::TRANSITION_FROM_TIME_IMMEDIATE: {
- txt += TTR("Immediate");
+ from_time = TTR("Immediate");
} break;
case AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BEAT: {
- txt += TTR("Next Beat");
+ from_time = TTR("Next Beat");
} break;
case AudioStreamInteractive::TRANSITION_FROM_TIME_NEXT_BAR: {
- txt += TTR("Next Bar");
+ from_time = TTR("Next Bar");
} break;
case AudioStreamInteractive::TRANSITION_FROM_TIME_END: {
- txt += TTR("Clip End");
+ from_time = TTR("Clip End");
} break;
default: {
}
@@ -220,13 +217,13 @@ void AudioStreamInteractiveTransitionEditor::_update_transitions() {
switch (audio_stream_interactive->get_transition_to_time(from, to)) {
case AudioStreamInteractive::TRANSITION_TO_TIME_SAME_POSITION: {
- txt += TTR(L"⮕ Same");
+ to_time = TTR("Same", "Transition Time Position");
} break;
case AudioStreamInteractive::TRANSITION_TO_TIME_START: {
- txt += TTR(L"⮕ Start");
+ to_time = TTR("Start", "Transition Time Position");
} break;
case AudioStreamInteractive::TRANSITION_TO_TIME_PREVIOUS_POSITION: {
- txt += TTR(L"⮕ Prev");
+ to_time = TTR("Prev", "Transition Time Position");
} break;
default: {
}
@@ -234,7 +231,7 @@ void AudioStreamInteractiveTransitionEditor::_update_transitions() {
}
rows[j]->set_icon(i, icon);
- rows[j]->set_text(i, txt);
+ rows[j]->set_text(i, to_time.is_empty() ? from_time : vformat(U"%s ⮕ %s", from_time, to_time));
rows[j]->set_tooltip_text(i, tooltip);
if (exists) {
rows[j]->set_custom_color(i, font_color);
@@ -267,10 +264,10 @@ void AudioStreamInteractiveTransitionEditor::edit(Object *p_obj) {
TreeItem *header = tree->create_item(root); // Header
int header_index = clip_count + 1;
header->set_text(header_index, TTR("From / To"));
- header->set_editable(0, false);
+ header->set_selectable(header_index, false);
filler_clip->clear();
- filler_clip->add_item("Disabled", -1);
+ filler_clip->add_item(TTR("Disabled"), -1);
Color header_color = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor));
@@ -280,7 +277,6 @@ void AudioStreamInteractiveTransitionEditor::edit(Object *p_obj) {
for (int i = 0; i <= clip_count; i++) {
int cell_index = i;
int clip_i = i == clip_count ? AudioStreamInteractive::CLIP_ANY : i;
- header->set_editable(cell_index, false);
header->set_selectable(cell_index, false);
header->set_custom_font(cell_index, header_font);
header->set_custom_font_size(cell_index, header_font_size);
@@ -332,6 +328,7 @@ AudioStreamInteractiveTransitionEditor::AudioStreamInteractiveTransitionEditor()
split = memnew(HSplitContainer);
add_child(split);
tree = memnew(Tree);
+ tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
tree->set_hide_root(true);
tree->add_theme_constant_override("draw_guides", 1);
tree->set_select_mode(Tree::SELECT_MULTI);
@@ -343,8 +340,8 @@ AudioStreamInteractiveTransitionEditor::AudioStreamInteractiveTransitionEditor()
split->add_child(edit_vb);
transition_enabled = memnew(CheckBox);
- transition_enabled->set_text(TTR("Use Transition"));
- edit_vb->add_margin_child(TTR("Transition Enabled:"), transition_enabled);
+ transition_enabled->set_text(TTR("Enabled"));
+ edit_vb->add_margin_child(TTR("Use Transition:"), transition_enabled);
transition_enabled->connect("pressed", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited));
transition_from = memnew(OptionButton);
@@ -375,6 +372,7 @@ AudioStreamInteractiveTransitionEditor::AudioStreamInteractiveTransitionEditor()
filler_clip = memnew(OptionButton);
edit_vb->add_margin_child(TTR("Filler Clip:"), filler_clip);
+ filler_clip->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
filler_clip->connect("item_selected", callable_mp(this, &AudioStreamInteractiveTransitionEditor::_edited).unbind(1));
hold_previous = memnew(CheckBox);
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
index 5c3af17e77..c4034f1f9f 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
@@ -71,7 +71,7 @@
<GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('osx')) ">macos</GodotTargetPlatform>
<GodotTargetPlatform Condition=" '$(GodotTargetPlatform)' == '' and $(RuntimeIdentifier.StartsWith('win')) ">windows</GodotTargetPlatform>
</PropertyGroup>
-
+
<!-- Auto-detect the target Godot platform if it was not specified and there's no runtime identifier information. -->
<PropertyGroup Condition=" '$(GodotTargetPlatform)' == '' ">
<GodotTargetPlatform Condition=" '$([MSBuild]::IsOsPlatform(Linux))' ">linuxbsd</GodotTargetPlatform>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets
index b51ce5cb8c..0391e9f829 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/iOSNativeAOT.targets
@@ -11,10 +11,10 @@
<XCodePath Condition=" '$(XCodePath)' == '' ">/Applications/Xcode.app/Contents/Developer</XCodePath>
<XCodePath>$([MSBuild]::EnsureTrailingSlash('$(XCodePath)'))</XCodePath>
</PropertyGroup>
-
+
<Target Name="PrepareBeforeIlcCompile"
BeforeTargets="IlcCompile">
-
+
<Copy SourceFiles="%(ResolvedRuntimePack.PackageDirectory)/runtimes/$(RuntimeIdentifier)/native/icudt.dat" DestinationFolder="$(PublishDir)"/>
<!-- We need to find the path to Xcode so we can set manual linker args to the correct SDKs
@@ -29,9 +29,9 @@
<XCodePath>$(XcodeSelect)</XCodePath>
<XCodePath>$([MSBuild]::EnsureTrailingSlash('$(XCodePath)'))</XCodePath>
</PropertyGroup>
-
+
<Message Importance="normal" Text="Found XCode at $(XcodeSelect)" Condition=" '$(FindXCode)' == 'true' "/>
-
+
<ItemGroup>
<LinkerArg Include="-mios-simulator-version-min=12.0 -isysroot %22$(XCodePath)Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk%22"
Condition=" $(RuntimeIdentifier.Contains('simulator')) "/>
@@ -54,5 +54,5 @@
</ItemGroup>
<Copy SourceFiles="@(SymbolFiles)" DestinationFolder="$(PublishDir)$(TargetName).framework.dSYM"/>
</Target>
-
+
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ClassPartialModifier.GD0001.fixed.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ClassPartialModifier.GD0001.fixed.cs
index 6ba6439d70..f5046bf34c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ClassPartialModifier.GD0001.fixed.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/GeneratedSources/ClassPartialModifier.GD0001.fixed.cs
@@ -2,5 +2,5 @@ using Godot;
public partial class ClassPartialModifier : Node
{
-
+
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ClassPartialModifier.GD0001.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ClassPartialModifier.GD0001.cs
index c8ff673b76..fb70f104aa 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ClassPartialModifier.GD0001.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/ClassPartialModifier.GD0001.cs
@@ -2,5 +2,5 @@ using Godot;
public class {|GD0001:ClassPartialModifier|} : Node
{
-
+
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs
index 1908703a71..91a376462b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0401.cs
@@ -2,7 +2,7 @@ using Godot;
// This works because it inherits from GodotObject.
[GlobalClass]
-public partial class CustomGlobalClass1 : GodotObject
+public partial class CustomGlobalClass1 : GodotObject
{
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs
index 4f7885cf37..0685d0b34a 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/GlobalClass.GD0402.cs
@@ -2,7 +2,7 @@ using Godot;
// This works because it inherits from GodotObject and it doesn't have any generic type parameter.
[GlobalClass]
-public partial class CustomGlobalClass : GodotObject
+public partial class CustomGlobalClass : GodotObject
{
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
index 2b5eecab8a..053ae36ae7 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Tests/TestData/Sources/MustBeVariant.GD0301.cs
@@ -10,7 +10,7 @@ public class MustBeVariantGD0301
// This raises a GD0301 diagnostic error: object is not Variant (and Method<T> requires a variant generic type).
Method<{|GD0301:object|}>();
}
-
+
public void MethodCallsOk()
{
// All these calls are valid because they are Variant types.
@@ -75,7 +75,7 @@ public class MustBeVariantGD0301
public void Method<[MustBeVariant] T>()
{
}
-
+
public void MustBeVariantClasses()
{
new ClassWithGenericVariant<bool>();
diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
index 7360118ee4..f23f2b9a8c 100644
--- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
@@ -7,6 +7,7 @@
<Nullable>enable</Nullable>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<SelfContained>False</SelfContained>
+ <RollForward>LatestMajor</RollForward>
</PropertyGroup>
<PropertyGroup Condition="Exists('$(SolutionDir)/../../../../bin/GodotSharp/Api/Debug/GodotSharp.dll') And ('$(GodotPlatform)' == 'windows' Or ('$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT'))">
<OutputPath>$(SolutionDir)/../../../../bin/GodotSharp/Tools</OutputPath>
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index eb75f05a23..9a76a25639 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -873,7 +873,7 @@ void BindingsGenerator::_append_text_method(StringBuilder &p_output, const TypeI
}
void BindingsGenerator::_append_text_member(StringBuilder &p_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
- if (p_link_target.find("/") >= 0) {
+ if (p_link_target.contains("/")) {
// Properties with '/' (slash) in the name are not declared in C#, so there is nothing to reference.
_append_text_undeclared(p_output, p_link_target);
} else if (!p_target_itype || !p_target_itype->is_object_type) {
@@ -1154,7 +1154,7 @@ void BindingsGenerator::_append_xml_method(StringBuilder &p_xml_output, const Ty
}
void BindingsGenerator::_append_xml_member(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
- if (p_link_target.find("/") >= 0) {
+ if (p_link_target.contains("/")) {
// Properties with '/' (slash) in the name are not declared in C#, so there is nothing to reference.
_append_xml_undeclared(p_xml_output, p_link_target);
} else if (!p_target_itype || !p_target_itype->is_object_type) {
@@ -3654,7 +3654,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
continue;
}
- if (property.name.find("/") >= 0) {
+ if (property.name.contains("/")) {
// Ignore properties with '/' (slash) in the name. These are only meant for use in the inspector.
continue;
}
diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp
index 73e53a6a07..08e7ba360a 100644
--- a/modules/multiplayer/editor/replication_editor.cpp
+++ b/modules/multiplayer/editor/replication_editor.cpp
@@ -81,7 +81,7 @@ void ReplicationEditor::_pick_node_select_recursive(TreeItem *p_item, const Stri
NodePath np = p_item->get_metadata(0);
Node *node = get_node(np);
- if (!p_filter.is_empty() && ((String)node->get_name()).findn(p_filter) != -1) {
+ if (!p_filter.is_empty() && ((String)node->get_name()).containsn(p_filter)) {
p_select_candidates.push_back(node);
}
diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp
index ba0e4f6cdd..5430a41d6d 100644
--- a/modules/openxr/action_map/openxr_action_map.cpp
+++ b/modules/openxr/action_map/openxr_action_map.cpp
@@ -59,7 +59,7 @@ void OpenXRActionMap::set_action_sets(Array p_action_sets) {
for (int i = 0; i < p_action_sets.size(); i++) {
Ref<OpenXRActionSet> action_set = p_action_sets[i];
- if (action_set.is_valid() && action_sets.find(action_set) == -1) {
+ if (action_set.is_valid() && !action_sets.has(action_set)) {
action_sets.push_back(action_set);
}
}
@@ -93,7 +93,7 @@ Ref<OpenXRActionSet> OpenXRActionMap::get_action_set(int p_idx) const {
void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) {
ERR_FAIL_COND(p_action_set.is_null());
- if (action_sets.find(p_action_set) == -1) {
+ if (!action_sets.has(p_action_set)) {
action_sets.push_back(p_action_set);
emit_changed();
}
@@ -112,7 +112,7 @@ void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) {
for (int i = 0; i < p_interaction_profiles.size(); i++) {
Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profiles[i];
- if (interaction_profile.is_valid() && interaction_profiles.find(interaction_profile) == -1) {
+ if (interaction_profile.is_valid() && !interaction_profiles.has(interaction_profile)) {
interaction_profiles.push_back(interaction_profile);
}
}
@@ -146,7 +146,7 @@ Ref<OpenXRInteractionProfile> OpenXRActionMap::get_interaction_profile(int p_idx
void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) {
ERR_FAIL_COND(p_interaction_profile.is_null());
- if (interaction_profiles.find(p_interaction_profile) == -1) {
+ if (!interaction_profiles.has(p_interaction_profile)) {
interaction_profiles.push_back(p_interaction_profile);
emit_changed();
}
diff --git a/modules/openxr/action_map/openxr_action_set.cpp b/modules/openxr/action_map/openxr_action_set.cpp
index 4855f9e4b7..d583af2b2f 100644
--- a/modules/openxr/action_map/openxr_action_set.cpp
+++ b/modules/openxr/action_map/openxr_action_set.cpp
@@ -124,7 +124,7 @@ Ref<OpenXRAction> OpenXRActionSet::get_action(const String p_name) const {
void OpenXRActionSet::add_action(Ref<OpenXRAction> p_action) {
ERR_FAIL_COND(p_action.is_null());
- if (actions.find(p_action) == -1) {
+ if (!actions.has(p_action)) {
if (p_action->action_set && p_action->action_set != this) {
// action should only relate to our action set
p_action->action_set->remove_action(p_action);
diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp
index 65ee652732..2579697d05 100644
--- a/modules/openxr/action_map/openxr_interaction_profile.cpp
+++ b/modules/openxr/action_map/openxr_interaction_profile.cpp
@@ -172,7 +172,7 @@ Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding_for_action(const Ref<
void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) {
ERR_FAIL_COND(p_binding.is_null());
- if (bindings.find(p_binding) == -1) {
+ if (!bindings.has(p_binding)) {
ERR_FAIL_COND_MSG(get_binding_for_action(p_binding->get_action()).is_valid(), "There is already a binding for this action in this interaction profile");
bindings.push_back(p_binding);
diff --git a/modules/openxr/doc_classes/OpenXRCompositionLayer.xml b/modules/openxr/doc_classes/OpenXRCompositionLayer.xml
index b9c69075e1..6f4ac00f3e 100644
--- a/modules/openxr/doc_classes/OpenXRCompositionLayer.xml
+++ b/modules/openxr/doc_classes/OpenXRCompositionLayer.xml
@@ -32,6 +32,10 @@
Enables the blending the layer using its alpha channel.
Can be combined with [member Viewport.transparent_bg] to give the layer a transparent background.
</member>
+ <member name="enable_hole_punch" type="bool" setter="set_enable_hole_punch" getter="get_enable_hole_punch" default="false">
+ Enables a technique called "hole punching", which allows putting the composition layer behind the main projection layer (i.e. setting [member sort_order] to a negative value) while "punching a hole" through everything rendered by Godot so that the layer is still visible.
+ This can be used to create the illusion that the composition layer exists in the same 3D space as everything rendered by Godot, allowing objects to appear to pass both behind or in front of the composition layer.
+ </member>
<member name="layer_viewport" type="SubViewport" setter="set_layer_viewport" getter="get_layer_viewport">
The [SubViewport] to render on the composition layer.
</member>
diff --git a/modules/openxr/extensions/openxr_composition_layer_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_extension.cpp
index 9a00cecab1..fb21c45fd8 100644
--- a/modules/openxr/extensions/openxr_composition_layer_extension.cpp
+++ b/modules/openxr/extensions/openxr_composition_layer_extension.cpp
@@ -209,6 +209,7 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos
switch (composition_layer->type) {
case XR_TYPE_COMPOSITION_LAYER_QUAD: {
XrCompositionLayerQuad *quad_layer = (XrCompositionLayerQuad *)composition_layer;
+ quad_layer->space = openxr_api->get_play_space();
quad_layer->subImage.swapchain = swapchain_info.get_swapchain();
quad_layer->subImage.imageArrayIndex = 0;
quad_layer->subImage.imageRect.offset.x = 0;
@@ -219,6 +220,7 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos
case XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR: {
XrCompositionLayerCylinderKHR *cylinder_layer = (XrCompositionLayerCylinderKHR *)composition_layer;
+ cylinder_layer->space = openxr_api->get_play_space();
cylinder_layer->subImage.swapchain = swapchain_info.get_swapchain();
cylinder_layer->subImage.imageArrayIndex = 0;
cylinder_layer->subImage.imageRect.offset.x = 0;
@@ -229,6 +231,7 @@ XrCompositionLayerBaseHeader *OpenXRViewportCompositionLayerProvider::get_compos
case XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR: {
XrCompositionLayerEquirect2KHR *equirect_layer = (XrCompositionLayerEquirect2KHR *)composition_layer;
+ equirect_layer->space = openxr_api->get_play_space();
equirect_layer->subImage.swapchain = swapchain_info.get_swapchain();
equirect_layer->subImage.imageArrayIndex = 0;
equirect_layer->subImage.imageRect.offset.x = 0;
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 0742cae26a..32512070d6 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -2302,7 +2302,7 @@ void OpenXRAPI::end_frame() {
};
result = xrEndFrame(session, &frame_end_info);
if (XR_FAILED(result)) {
- print_line("OpenXR: failed to end frame! [", get_error_string(result), "]");
+ print_line("OpenXR: rendering skipped and failed to end frame! [", get_error_string(result), "]");
return;
}
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index b92d1edb90..fbbc61a91c 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -391,7 +391,7 @@ OpenXRInterface::Action *OpenXRInterface::create_action(ActionSet *p_action_set,
// we link our actions back to our trackers so we know which actions to check when we're processing our trackers
for (int i = 0; i < p_trackers.size(); i++) {
- if (p_trackers[i]->actions.find(action) == -1) {
+ if (!p_trackers[i]->actions.has(action)) {
p_trackers[i]->actions.push_back(action);
}
}
diff --git a/modules/openxr/scene/openxr_composition_layer.cpp b/modules/openxr/scene/openxr_composition_layer.cpp
index ce883b79b3..219f176479 100644
--- a/modules/openxr/scene/openxr_composition_layer.cpp
+++ b/modules/openxr/scene/openxr_composition_layer.cpp
@@ -40,6 +40,13 @@
HashSet<SubViewport *> OpenXRCompositionLayer::viewports_in_use;
+static const char *HOLE_PUNCH_SHADER_CODE =
+ "shader_type spatial;\n"
+ "render_mode blend_mix, depth_draw_opaque, cull_back, shadow_to_opacity, shadows_disabled;\n"
+ "void fragment() {\n"
+ "\tALBEDO = vec3(0.0, 0.0, 0.0);\n"
+ "}\n";
+
OpenXRCompositionLayer::OpenXRCompositionLayer() {
openxr_api = OpenXRAPI::get_singleton();
composition_layer_extension = OpenXRCompositionLayerExtension::get_singleton();
@@ -80,6 +87,9 @@ void OpenXRCompositionLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer_viewport", "viewport"), &OpenXRCompositionLayer::set_layer_viewport);
ClassDB::bind_method(D_METHOD("get_layer_viewport"), &OpenXRCompositionLayer::get_layer_viewport);
+ ClassDB::bind_method(D_METHOD("set_enable_hole_punch", "enable"), &OpenXRCompositionLayer::set_enable_hole_punch);
+ ClassDB::bind_method(D_METHOD("get_enable_hole_punch"), &OpenXRCompositionLayer::get_enable_hole_punch);
+
ClassDB::bind_method(D_METHOD("set_sort_order", "order"), &OpenXRCompositionLayer::set_sort_order);
ClassDB::bind_method(D_METHOD("get_sort_order"), &OpenXRCompositionLayer::get_sort_order);
@@ -93,6 +103,16 @@ void OpenXRCompositionLayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "layer_viewport", PROPERTY_HINT_NODE_TYPE, "SubViewport"), "set_layer_viewport", "get_layer_viewport");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sort_order", PROPERTY_HINT_NONE, ""), "set_sort_order", "get_sort_order");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alpha_blend", PROPERTY_HINT_NONE, ""), "set_alpha_blend", "get_alpha_blend");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enable_hole_punch", PROPERTY_HINT_NONE, ""), "set_enable_hole_punch", "get_enable_hole_punch");
+}
+
+bool OpenXRCompositionLayer::_should_use_fallback_node() {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ return true;
+ } else if (openxr_session_running) {
+ return enable_hole_punch || !is_natively_supported();
+ }
+ return false;
}
void OpenXRCompositionLayer::_create_fallback_node() {
@@ -103,21 +123,27 @@ void OpenXRCompositionLayer::_create_fallback_node() {
should_update_fallback_mesh = true;
}
+void OpenXRCompositionLayer::_remove_fallback_node() {
+ ERR_FAIL_COND(fallback != nullptr);
+ remove_child(fallback);
+ fallback->queue_free();
+ fallback = nullptr;
+}
+
void OpenXRCompositionLayer::_on_openxr_session_begun() {
- if (!is_natively_supported()) {
- if (!fallback) {
- _create_fallback_node();
- }
- } else if (layer_viewport && is_visible() && is_inside_tree()) {
+ openxr_session_running = true;
+ if (layer_viewport && is_natively_supported() && is_visible() && is_inside_tree()) {
openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
}
+ if (!fallback && _should_use_fallback_node()) {
+ _create_fallback_node();
+ }
}
void OpenXRCompositionLayer::_on_openxr_session_stopping() {
- if (fallback && !Engine::get_singleton()->is_editor_hint()) {
- fallback->queue_free();
- remove_child(fallback);
- fallback = nullptr;
+ openxr_session_running = false;
+ if (fallback && !_should_use_fallback_node()) {
+ _remove_fallback_node();
} else {
openxr_layer_provider->set_viewport(RID(), Size2i());
}
@@ -152,7 +178,7 @@ void OpenXRCompositionLayer::set_layer_viewport(SubViewport *p_viewport) {
if (fallback) {
_reset_fallback_material();
- } else if (openxr_api && openxr_api->is_running() && is_visible() && is_inside_tree()) {
+ } else if (openxr_session_running && is_visible() && is_inside_tree()) {
if (layer_viewport) {
openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
} else {
@@ -165,9 +191,33 @@ SubViewport *OpenXRCompositionLayer::get_layer_viewport() const {
return layer_viewport;
}
+void OpenXRCompositionLayer::set_enable_hole_punch(bool p_enable) {
+ if (enable_hole_punch == p_enable) {
+ return;
+ }
+
+ enable_hole_punch = p_enable;
+ if (_should_use_fallback_node()) {
+ if (fallback) {
+ _reset_fallback_material();
+ } else {
+ _create_fallback_node();
+ }
+ } else if (fallback) {
+ _remove_fallback_node();
+ }
+
+ update_configuration_warnings();
+}
+
+bool OpenXRCompositionLayer::get_enable_hole_punch() const {
+ return enable_hole_punch;
+}
+
void OpenXRCompositionLayer::set_sort_order(int p_order) {
if (openxr_layer_provider) {
openxr_layer_provider->set_sort_order(p_order);
+ update_configuration_warnings();
}
}
@@ -212,15 +262,28 @@ void OpenXRCompositionLayer::_reset_fallback_material() {
return;
}
- if (layer_viewport) {
+ if (enable_hole_punch && !Engine::get_singleton()->is_editor_hint() && is_natively_supported()) {
+ Ref<ShaderMaterial> material = fallback->get_surface_override_material(0);
+ if (material.is_null()) {
+ Ref<Shader> shader;
+ shader.instantiate();
+ shader->set_code(HOLE_PUNCH_SHADER_CODE);
+
+ material.instantiate();
+ material->set_shader(shader);
+
+ fallback->set_surface_override_material(0, material);
+ }
+ } else if (layer_viewport) {
Ref<StandardMaterial3D> material = fallback->get_surface_override_material(0);
if (material.is_null()) {
material.instantiate();
material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
- material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
material->set_local_to_scene(true);
fallback->set_surface_override_material(0, material);
}
+
+ material->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, !enable_hole_punch);
material->set_transparency(get_alpha_blend() ? StandardMaterial3D::TRANSPARENCY_ALPHA : StandardMaterial3D::TRANSPARENCY_DISABLED);
Ref<ViewportTexture> texture = material->get_texture(StandardMaterial3D::TEXTURE_ALBEDO);
@@ -260,7 +323,7 @@ void OpenXRCompositionLayer::_notification(int p_what) {
}
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
- if (!fallback && openxr_api && openxr_api->is_running() && is_inside_tree()) {
+ if (!fallback && openxr_session_running && is_inside_tree()) {
if (layer_viewport && is_visible()) {
openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
} else {
@@ -277,7 +340,7 @@ void OpenXRCompositionLayer::_notification(int p_what) {
composition_layer_extension->register_viewport_composition_layer_provider(openxr_layer_provider);
}
- if (!fallback && layer_viewport && openxr_api && openxr_api->is_running() && is_visible()) {
+ if (!fallback && layer_viewport && openxr_session_running && is_visible()) {
openxr_layer_provider->set_viewport(layer_viewport->get_viewport_rid(), layer_viewport->get_size());
}
} break;
@@ -347,5 +410,9 @@ PackedStringArray OpenXRCompositionLayer::get_configuration_warnings() const {
warnings.push_back(RTR("OpenXR composition layers must have orthonormalized transforms (ie. no scale or shearing)."));
}
+ if (enable_hole_punch && get_sort_order() >= 0) {
+ warnings.push_back(RTR("Hole punching won't work as expected unless the sort order is less than zero."));
+ }
+
return warnings;
}
diff --git a/modules/openxr/scene/openxr_composition_layer.h b/modules/openxr/scene/openxr_composition_layer.h
index 9f064379d3..7998d096b6 100644
--- a/modules/openxr/scene/openxr_composition_layer.h
+++ b/modules/openxr/scene/openxr_composition_layer.h
@@ -46,13 +46,17 @@ class OpenXRCompositionLayer : public Node3D {
GDCLASS(OpenXRCompositionLayer, Node3D);
SubViewport *layer_viewport = nullptr;
+ bool enable_hole_punch = false;
MeshInstance3D *fallback = nullptr;
bool should_update_fallback_mesh = false;
+ bool openxr_session_running = false;
Dictionary extension_property_values;
+ bool _should_use_fallback_node();
void _create_fallback_node();
void _reset_fallback_material();
+ void _remove_fallback_node();
protected:
OpenXRAPI *openxr_api = nullptr;
@@ -79,6 +83,9 @@ public:
void set_layer_viewport(SubViewport *p_viewport);
SubViewport *get_layer_viewport() const;
+ void set_enable_hole_punch(bool p_enable);
+ bool get_enable_hole_punch() const;
+
void set_sort_order(int p_order);
int get_sort_order() const;
diff --git a/modules/openxr/scene/openxr_composition_layer_cylinder.cpp b/modules/openxr/scene/openxr_composition_layer_cylinder.cpp
index ae5a8da5f3..728ba71006 100644
--- a/modules/openxr/scene/openxr_composition_layer_cylinder.cpp
+++ b/modules/openxr/scene/openxr_composition_layer_cylinder.cpp
@@ -76,13 +76,6 @@ void OpenXRCompositionLayerCylinder::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "fallback_segments", PROPERTY_HINT_NONE, ""), "set_fallback_segments", "get_fallback_segments");
}
-void OpenXRCompositionLayerCylinder::_on_openxr_session_begun() {
- OpenXRCompositionLayer::_on_openxr_session_begun();
- if (openxr_api) {
- composition_layer.space = openxr_api->get_play_space();
- }
-}
-
Ref<Mesh> OpenXRCompositionLayerCylinder::_create_fallback_mesh() {
Ref<ArrayMesh> mesh;
mesh.instantiate();
diff --git a/modules/openxr/scene/openxr_composition_layer_cylinder.h b/modules/openxr/scene/openxr_composition_layer_cylinder.h
index aed0fabd78..bb1d242267 100644
--- a/modules/openxr/scene/openxr_composition_layer_cylinder.h
+++ b/modules/openxr/scene/openxr_composition_layer_cylinder.h
@@ -50,7 +50,6 @@ protected:
void _notification(int p_what);
- virtual void _on_openxr_session_begun() override;
virtual Ref<Mesh> _create_fallback_mesh() override;
public:
diff --git a/modules/openxr/scene/openxr_composition_layer_equirect.cpp b/modules/openxr/scene/openxr_composition_layer_equirect.cpp
index d67e71443c..14cfea8da6 100644
--- a/modules/openxr/scene/openxr_composition_layer_equirect.cpp
+++ b/modules/openxr/scene/openxr_composition_layer_equirect.cpp
@@ -81,13 +81,6 @@ void OpenXRCompositionLayerEquirect::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "fallback_segments", PROPERTY_HINT_NONE, ""), "set_fallback_segments", "get_fallback_segments");
}
-void OpenXRCompositionLayerEquirect::_on_openxr_session_begun() {
- OpenXRCompositionLayer::_on_openxr_session_begun();
- if (openxr_api) {
- composition_layer.space = openxr_api->get_play_space();
- }
-}
-
Ref<Mesh> OpenXRCompositionLayerEquirect::_create_fallback_mesh() {
Ref<ArrayMesh> mesh;
mesh.instantiate();
diff --git a/modules/openxr/scene/openxr_composition_layer_equirect.h b/modules/openxr/scene/openxr_composition_layer_equirect.h
index 7a002a48dc..66f8b0a91c 100644
--- a/modules/openxr/scene/openxr_composition_layer_equirect.h
+++ b/modules/openxr/scene/openxr_composition_layer_equirect.h
@@ -51,7 +51,6 @@ protected:
void _notification(int p_what);
- virtual void _on_openxr_session_begun() override;
virtual Ref<Mesh> _create_fallback_mesh() override;
public:
diff --git a/modules/openxr/scene/openxr_composition_layer_quad.cpp b/modules/openxr/scene/openxr_composition_layer_quad.cpp
index 17d57851e4..8c5b8ec26b 100644
--- a/modules/openxr/scene/openxr_composition_layer_quad.cpp
+++ b/modules/openxr/scene/openxr_composition_layer_quad.cpp
@@ -62,13 +62,6 @@ void OpenXRCompositionLayerQuad::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "quad_size", PROPERTY_HINT_NONE, ""), "set_quad_size", "get_quad_size");
}
-void OpenXRCompositionLayerQuad::_on_openxr_session_begun() {
- OpenXRCompositionLayer::_on_openxr_session_begun();
- if (openxr_api) {
- composition_layer.space = openxr_api->get_play_space();
- }
-}
-
Ref<Mesh> OpenXRCompositionLayerQuad::_create_fallback_mesh() {
Ref<QuadMesh> mesh;
mesh.instantiate();
diff --git a/modules/openxr/scene/openxr_composition_layer_quad.h b/modules/openxr/scene/openxr_composition_layer_quad.h
index d88b596984..21bb9b2d85 100644
--- a/modules/openxr/scene/openxr_composition_layer_quad.h
+++ b/modules/openxr/scene/openxr_composition_layer_quad.h
@@ -47,7 +47,6 @@ protected:
void _notification(int p_what);
- virtual void _on_openxr_session_begun() override;
virtual Ref<Mesh> _create_fallback_mesh() override;
public:
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index 4a1037431a..9f34a6ca6a 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -370,7 +370,7 @@ PackedStringArray RegEx::get_names() const {
for (uint32_t i = 0; i < count; i++) {
String name = &table[i * entry_size + 1];
- if (result.find(name) < 0) {
+ if (!result.has(name)) {
result.append(name);
}
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 7e29f984c1..8895a83089 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -389,54 +389,54 @@ class TextServerAdvanced : public TextServerExtension {
_FORCE_INLINE_ bool _get_tag_hidden(int64_t p_tag) const;
_FORCE_INLINE_ int _font_get_weight_by_name(const String &p_sty_name) const {
String sty_name = p_sty_name.replace(" ", "").replace("-", "");
- if (sty_name.find("thin") >= 0 || sty_name.find("hairline") >= 0) {
+ if (sty_name.contains("thin") || sty_name.contains("hairline")) {
return 100;
- } else if (sty_name.find("extralight") >= 0 || sty_name.find("ultralight") >= 0) {
+ } else if (sty_name.contains("extralight") || sty_name.contains("ultralight")) {
return 200;
- } else if (sty_name.find("light") >= 0) {
+ } else if (sty_name.contains("light")) {
return 300;
- } else if (sty_name.find("semilight") >= 0) {
+ } else if (sty_name.contains("semilight")) {
return 350;
- } else if (sty_name.find("regular") >= 0) {
+ } else if (sty_name.contains("regular")) {
return 400;
- } else if (sty_name.find("medium") >= 0) {
+ } else if (sty_name.contains("medium")) {
return 500;
- } else if (sty_name.find("semibold") >= 0 || sty_name.find("demibold") >= 0) {
+ } else if (sty_name.contains("semibold") || sty_name.contains("demibold")) {
return 600;
- } else if (sty_name.find("bold") >= 0) {
+ } else if (sty_name.contains("bold")) {
return 700;
- } else if (sty_name.find("extrabold") >= 0 || sty_name.find("ultrabold") >= 0) {
+ } else if (sty_name.contains("extrabold") || sty_name.contains("ultrabold")) {
return 800;
- } else if (sty_name.find("black") >= 0 || sty_name.find("heavy") >= 0) {
+ } else if (sty_name.contains("black") || sty_name.contains("heavy")) {
return 900;
- } else if (sty_name.find("extrablack") >= 0 || sty_name.find("ultrablack") >= 0) {
+ } else if (sty_name.contains("extrablack") || sty_name.contains("ultrablack")) {
return 950;
}
return 400;
}
_FORCE_INLINE_ int _font_get_stretch_by_name(const String &p_sty_name) const {
String sty_name = p_sty_name.replace(" ", "").replace("-", "");
- if (sty_name.find("ultracondensed") >= 0) {
+ if (sty_name.contains("ultracondensed")) {
return 50;
- } else if (sty_name.find("extracondensed") >= 0) {
+ } else if (sty_name.contains("extracondensed")) {
return 63;
- } else if (sty_name.find("condensed") >= 0) {
+ } else if (sty_name.contains("condensed")) {
return 75;
- } else if (sty_name.find("semicondensed") >= 0) {
+ } else if (sty_name.contains("semicondensed")) {
return 87;
- } else if (sty_name.find("semiexpanded") >= 0) {
+ } else if (sty_name.contains("semiexpanded")) {
return 113;
- } else if (sty_name.find("expanded") >= 0) {
+ } else if (sty_name.contains("expanded")) {
return 125;
- } else if (sty_name.find("extraexpanded") >= 0) {
+ } else if (sty_name.contains("extraexpanded")) {
return 150;
- } else if (sty_name.find("ultraexpanded") >= 0) {
+ } else if (sty_name.contains("ultraexpanded")) {
return 200;
}
return 100;
}
_FORCE_INLINE_ bool _is_ital_style(const String &p_sty_name) const {
- return (p_sty_name.find("italic") >= 0) || (p_sty_name.find("oblique") >= 0);
+ return p_sty_name.contains("italic") || p_sty_name.contains("oblique");
}
// Shaped text cache data.
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 31370c7da7..9ad20c7b26 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -335,54 +335,54 @@ class TextServerFallback : public TextServerExtension {
_FORCE_INLINE_ int _font_get_weight_by_name(const String &p_sty_name) const {
String sty_name = p_sty_name.replace(" ", "").replace("-", "");
- if (sty_name.find("thin") >= 0 || sty_name.find("hairline") >= 0) {
+ if (sty_name.contains("thin") || sty_name.contains("hairline")) {
return 100;
- } else if (sty_name.find("extralight") >= 0 || sty_name.find("ultralight") >= 0) {
+ } else if (sty_name.contains("extralight") || sty_name.contains("ultralight")) {
return 200;
- } else if (sty_name.find("light") >= 0) {
+ } else if (sty_name.contains("light")) {
return 300;
- } else if (sty_name.find("semilight") >= 0) {
+ } else if (sty_name.contains("semilight")) {
return 350;
- } else if (sty_name.find("regular") >= 0) {
+ } else if (sty_name.contains("regular")) {
return 400;
- } else if (sty_name.find("medium") >= 0) {
+ } else if (sty_name.contains("medium")) {
return 500;
- } else if (sty_name.find("semibold") >= 0 || sty_name.find("demibold") >= 0) {
+ } else if (sty_name.contains("semibold") || sty_name.contains("demibold")) {
return 600;
- } else if (sty_name.find("bold") >= 0) {
+ } else if (sty_name.contains("bold")) {
return 700;
- } else if (sty_name.find("extrabold") >= 0 || sty_name.find("ultrabold") >= 0) {
+ } else if (sty_name.contains("extrabold") || sty_name.contains("ultrabold")) {
return 800;
- } else if (sty_name.find("black") >= 0 || sty_name.find("heavy") >= 0) {
+ } else if (sty_name.contains("black") || sty_name.contains("heavy")) {
return 900;
- } else if (sty_name.find("extrablack") >= 0 || sty_name.find("ultrablack") >= 0) {
+ } else if (sty_name.contains("extrablack") || sty_name.contains("ultrablack")) {
return 950;
}
return 400;
}
_FORCE_INLINE_ int _font_get_stretch_by_name(const String &p_sty_name) const {
String sty_name = p_sty_name.replace(" ", "").replace("-", "");
- if (sty_name.find("ultracondensed") >= 0) {
+ if (sty_name.contains("ultracondensed")) {
return 50;
- } else if (sty_name.find("extracondensed") >= 0) {
+ } else if (sty_name.contains("extracondensed")) {
return 63;
- } else if (sty_name.find("condensed") >= 0) {
+ } else if (sty_name.contains("condensed")) {
return 75;
- } else if (sty_name.find("semicondensed") >= 0) {
+ } else if (sty_name.contains("semicondensed")) {
return 87;
- } else if (sty_name.find("semiexpanded") >= 0) {
+ } else if (sty_name.contains("semiexpanded")) {
return 113;
- } else if (sty_name.find("expanded") >= 0) {
+ } else if (sty_name.contains("expanded")) {
return 125;
- } else if (sty_name.find("extraexpanded") >= 0) {
+ } else if (sty_name.contains("extraexpanded")) {
return 150;
- } else if (sty_name.find("ultraexpanded") >= 0) {
+ } else if (sty_name.contains("ultraexpanded")) {
return 200;
}
return 100;
}
_FORCE_INLINE_ bool _is_ital_style(const String &p_sty_name) const {
- return (p_sty_name.find("italic") >= 0) || (p_sty_name.find("oblique") >= 0);
+ return p_sty_name.contains("italic") || p_sty_name.contains("oblique");
}
// Shaped text cache data.
diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp
index 95453c1ecd..70f0ea346b 100644
--- a/modules/upnp/upnp.cpp
+++ b/modules/upnp/upnp.cpp
@@ -37,10 +37,10 @@
bool UPNP::is_common_device(const String &dev) const {
return dev.is_empty() ||
- dev.find("InternetGatewayDevice") >= 0 ||
- dev.find("WANIPConnection") >= 0 ||
- dev.find("WANPPPConnection") >= 0 ||
- dev.find("rootdevice") >= 0;
+ dev.contains("InternetGatewayDevice") ||
+ dev.contains("WANIPConnection") ||
+ dev.contains("WANPPPConnection") ||
+ dev.contains("rootdevice");
}
int UPNP::discover(int timeout, int ttl, const String &device_filter) {
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 30d57cade5..eebef3f969 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -816,11 +816,11 @@ Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const Shared
}
bool EditorExportPlatformAndroid::_has_read_write_storage_permission(const Vector<String> &p_permissions) {
- return p_permissions.find("android.permission.READ_EXTERNAL_STORAGE") != -1 || p_permissions.find("android.permission.WRITE_EXTERNAL_STORAGE") != -1;
+ return p_permissions.has("android.permission.READ_EXTERNAL_STORAGE") || p_permissions.has("android.permission.WRITE_EXTERNAL_STORAGE");
}
bool EditorExportPlatformAndroid::_has_manage_external_storage_permission(const Vector<String> &p_permissions) {
- return p_permissions.find("android.permission.MANAGE_EXTERNAL_STORAGE") != -1;
+ return p_permissions.has("android.permission.MANAGE_EXTERNAL_STORAGE");
}
bool EditorExportPlatformAndroid::_uses_vulkan() {
@@ -924,7 +924,7 @@ void EditorExportPlatformAndroid::_get_permissions(const Ref<EditorExportPreset>
}
}
if (p_give_internet) {
- if (r_permissions.find("android.permission.INTERNET") == -1) {
+ if (!r_permissions.has("android.permission.INTERNET")) {
r_permissions.push_back("android.permission.INTERNET");
}
}
@@ -2716,7 +2716,7 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit
}
String package_name = p_preset->get("package/unique_name");
- if (package_name.find("$genname") >= 0 && !is_project_name_valid()) {
+ if (package_name.contains("$genname") && !is_project_name_valid()) {
// Warning only, so don't override `valid`.
err += vformat(TTR("The project name does not meet the requirement for the package name format and will be updated to \"%s\". Please explicitly specify the package name if needed."), get_valid_basename());
err += "\n";
diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotProjectManager.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotProjectManager.kt
index d0e4279eeb..68ca5697f1 100644
--- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotProjectManager.kt
+++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotProjectManager.kt
@@ -42,4 +42,3 @@ class GodotProjectManager : GodotEditor() {
// Nothing to do here.. we have yet to select a project to load.
}
}
-
diff --git a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java
index bd8c58ad69..c316812404 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java
@@ -1955,4 +1955,3 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private int mEGLContextClientVersion;
private boolean mPreserveEGLContextOnPause;
}
-
diff --git a/platform/android/java/scripts/publish-root.gradle b/platform/android/java/scripts/publish-root.gradle
index ae88487c34..31338de21e 100644
--- a/platform/android/java/scripts/publish-root.gradle
+++ b/platform/android/java/scripts/publish-root.gradle
@@ -36,4 +36,3 @@ nexusPublishing {
}
}
}
-
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index c60125c34e..764959eef3 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -586,11 +586,11 @@ Vector<String> OS_Android::get_system_font_path_for_text(const String &p_font_na
}
if (score > best_score) {
best_score = score;
- if (ret.find(root.path_join(E->get().filename)) < 0) {
+ if (!ret.has(root.path_join(E->get().filename))) {
ret.insert(0, root.path_join(E->get().filename));
}
} else if (score == best_score || E->get().script.is_empty()) {
- if (ret.find(root.path_join(E->get().filename)) < 0) {
+ if (!ret.has(root.path_join(E->get().filename))) {
ret.push_back(root.path_join(E->get().filename));
}
}
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index c35c72d093..6a452f08fa 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -400,65 +400,65 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
str.parse_utf8((const char *)pfile.ptr(), pfile.size());
Vector<String> lines = str.split("\n");
for (int i = 0; i < lines.size(); i++) {
- if (lines[i].find("$binary") != -1) {
+ if (lines[i].contains("$binary")) {
strnew += lines[i].replace("$binary", p_config.binary_name) + "\n";
- } else if (lines[i].find("$modules_buildfile") != -1) {
+ } else if (lines[i].contains("$modules_buildfile")) {
strnew += lines[i].replace("$modules_buildfile", p_config.modules_buildfile) + "\n";
- } else if (lines[i].find("$modules_fileref") != -1) {
+ } else if (lines[i].contains("$modules_fileref")) {
strnew += lines[i].replace("$modules_fileref", p_config.modules_fileref) + "\n";
- } else if (lines[i].find("$modules_buildphase") != -1) {
+ } else if (lines[i].contains("$modules_buildphase")) {
strnew += lines[i].replace("$modules_buildphase", p_config.modules_buildphase) + "\n";
- } else if (lines[i].find("$modules_buildgrp") != -1) {
+ } else if (lines[i].contains("$modules_buildgrp")) {
strnew += lines[i].replace("$modules_buildgrp", p_config.modules_buildgrp) + "\n";
- } else if (lines[i].find("$name") != -1) {
+ } else if (lines[i].contains("$name")) {
strnew += lines[i].replace("$name", p_config.pkg_name) + "\n";
- } else if (lines[i].find("$bundle_identifier") != -1) {
+ } else if (lines[i].contains("$bundle_identifier")) {
strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
- } else if (lines[i].find("$short_version") != -1) {
+ } else if (lines[i].contains("$short_version")) {
strnew += lines[i].replace("$short_version", p_preset->get_version("application/short_version")) + "\n";
- } else if (lines[i].find("$version") != -1) {
+ } else if (lines[i].contains("$version")) {
strnew += lines[i].replace("$version", p_preset->get_version("application/version")) + "\n";
- } else if (lines[i].find("$min_version") != -1) {
+ } else if (lines[i].contains("$min_version")) {
strnew += lines[i].replace("$min_version", p_preset->get("application/min_ios_version")) + "\n";
- } else if (lines[i].find("$signature") != -1) {
+ } else if (lines[i].contains("$signature")) {
strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
- } else if (lines[i].find("$team_id") != -1) {
+ } else if (lines[i].contains("$team_id")) {
strnew += lines[i].replace("$team_id", p_preset->get("application/app_store_team_id")) + "\n";
- } else if (lines[i].find("$default_build_config") != -1) {
+ } else if (lines[i].contains("$default_build_config")) {
strnew += lines[i].replace("$default_build_config", p_debug ? "Debug" : "Release") + "\n";
- } else if (lines[i].find("$export_method") != -1) {
+ } else if (lines[i].contains("$export_method")) {
int export_method = p_preset->get(p_debug ? "application/export_method_debug" : "application/export_method_release");
strnew += lines[i].replace("$export_method", export_method_string[export_method]) + "\n";
- } else if (lines[i].find("$provisioning_profile_uuid_release") != -1) {
+ } else if (lines[i].contains("$provisioning_profile_uuid_release")) {
strnew += lines[i].replace("$provisioning_profile_uuid_release", p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE)) + "\n";
- } else if (lines[i].find("$provisioning_profile_uuid_debug") != -1) {
+ } else if (lines[i].contains("$provisioning_profile_uuid_debug")) {
strnew += lines[i].replace("$provisioning_profile_uuid_debug", p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG)) + "\n";
- } else if (lines[i].find("$code_sign_style_debug") != -1) {
+ } else if (lines[i].contains("$code_sign_style_debug")) {
if (dbg_manual) {
strnew += lines[i].replace("$code_sign_style_debug", "Manual") + "\n";
} else {
strnew += lines[i].replace("$code_sign_style_debug", "Automatic") + "\n";
}
- } else if (lines[i].find("$code_sign_style_release") != -1) {
+ } else if (lines[i].contains("$code_sign_style_release")) {
if (rel_manual) {
strnew += lines[i].replace("$code_sign_style_release", "Manual") + "\n";
} else {
strnew += lines[i].replace("$code_sign_style_release", "Automatic") + "\n";
}
- } else if (lines[i].find("$provisioning_profile_uuid") != -1) {
+ } else if (lines[i].contains("$provisioning_profile_uuid")) {
String uuid = p_debug ? p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG) : p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE);
strnew += lines[i].replace("$provisioning_profile_uuid", uuid) + "\n";
- } else if (lines[i].find("$code_sign_identity_debug") != -1) {
+ } else if (lines[i].contains("$code_sign_identity_debug")) {
strnew += lines[i].replace("$code_sign_identity_debug", dbg_sign_id) + "\n";
- } else if (lines[i].find("$code_sign_identity_release") != -1) {
+ } else if (lines[i].contains("$code_sign_identity_release")) {
strnew += lines[i].replace("$code_sign_identity_release", rel_sign_id) + "\n";
- } else if (lines[i].find("$additional_plist_content") != -1) {
+ } else if (lines[i].contains("$additional_plist_content")) {
strnew += lines[i].replace("$additional_plist_content", p_config.plist_content) + "\n";
- } else if (lines[i].find("$godot_archs") != -1) {
+ } else if (lines[i].contains("$godot_archs")) {
strnew += lines[i].replace("$godot_archs", p_config.architectures) + "\n";
- } else if (lines[i].find("$linker_flags") != -1) {
+ } else if (lines[i].contains("$linker_flags")) {
strnew += lines[i].replace("$linker_flags", p_config.linker_flags) + "\n";
- } else if (lines[i].find("$targeted_device_family") != -1) {
+ } else if (lines[i].contains("$targeted_device_family")) {
String xcode_value;
switch ((int)p_preset->get("application/targeted_device_family")) {
case 0: // iPhone
@@ -472,16 +472,16 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
break;
}
strnew += lines[i].replace("$targeted_device_family", xcode_value) + "\n";
- } else if (lines[i].find("$cpp_code") != -1) {
+ } else if (lines[i].contains("$cpp_code")) {
strnew += lines[i].replace("$cpp_code", p_config.cpp_code) + "\n";
- } else if (lines[i].find("$docs_in_place") != -1) {
+ } else if (lines[i].contains("$docs_in_place")) {
strnew += lines[i].replace("$docs_in_place", ((bool)p_preset->get("user_data/accessible_from_files_app")) ? "<true/>" : "<false/>") + "\n";
- } else if (lines[i].find("$docs_sharing") != -1) {
+ } else if (lines[i].contains("$docs_sharing")) {
strnew += lines[i].replace("$docs_sharing", ((bool)p_preset->get("user_data/accessible_from_itunes_sharing")) ? "<true/>" : "<false/>") + "\n";
- } else if (lines[i].find("$entitlements_push_notifications") != -1) {
+ } else if (lines[i].contains("$entitlements_push_notifications")) {
bool is_on = p_preset->get("capabilities/push_notifications");
strnew += lines[i].replace("$entitlements_push_notifications", is_on ? "<key>aps-environment</key><string>development</string>" : "") + "\n";
- } else if (lines[i].find("$required_device_capabilities") != -1) {
+ } else if (lines[i].contains("$required_device_capabilities")) {
String capabilities;
// I've removed armv7 as we can run on 64bit only devices
@@ -503,7 +503,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
}
strnew += lines[i].replace("$required_device_capabilities", capabilities);
- } else if (lines[i].find("$interface_orientations") != -1) {
+ } else if (lines[i].contains("$interface_orientations")) {
String orientations;
const DisplayServer::ScreenOrientation screen_orientation =
DisplayServer::ScreenOrientation(int(GLOBAL_GET("display/window/handheld/orientation")));
@@ -541,35 +541,35 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
}
strnew += lines[i].replace("$interface_orientations", orientations);
- } else if (lines[i].find("$camera_usage_description") != -1) {
+ } else if (lines[i].contains("$camera_usage_description")) {
String description = p_preset->get("privacy/camera_usage_description");
strnew += lines[i].replace("$camera_usage_description", description) + "\n";
- } else if (lines[i].find("$microphone_usage_description") != -1) {
+ } else if (lines[i].contains("$microphone_usage_description")) {
String description = p_preset->get("privacy/microphone_usage_description");
strnew += lines[i].replace("$microphone_usage_description", description) + "\n";
- } else if (lines[i].find("$photolibrary_usage_description") != -1) {
+ } else if (lines[i].contains("$photolibrary_usage_description")) {
String description = p_preset->get("privacy/photolibrary_usage_description");
strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n";
- } else if (lines[i].find("$plist_launch_screen_name") != -1) {
+ } else if (lines[i].contains("$plist_launch_screen_name")) {
String value = "<key>UILaunchStoryboardName</key>\n<string>Launch Screen</string>";
strnew += lines[i].replace("$plist_launch_screen_name", value) + "\n";
- } else if (lines[i].find("$pbx_launch_screen_file_reference") != -1) {
+ } else if (lines[i].contains("$pbx_launch_screen_file_reference")) {
String value = "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"<group>\"; };";
strnew += lines[i].replace("$pbx_launch_screen_file_reference", value) + "\n";
- } else if (lines[i].find("$pbx_launch_screen_copy_files") != -1) {
+ } else if (lines[i].contains("$pbx_launch_screen_copy_files")) {
String value = "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */,";
strnew += lines[i].replace("$pbx_launch_screen_copy_files", value) + "\n";
- } else if (lines[i].find("$pbx_launch_screen_build_phase") != -1) {
+ } else if (lines[i].contains("$pbx_launch_screen_build_phase")) {
String value = "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */,";
strnew += lines[i].replace("$pbx_launch_screen_build_phase", value) + "\n";
- } else if (lines[i].find("$pbx_launch_screen_build_reference") != -1) {
+ } else if (lines[i].contains("$pbx_launch_screen_build_reference")) {
String value = "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };";
strnew += lines[i].replace("$pbx_launch_screen_build_reference", value) + "\n";
#ifndef DISABLE_DEPRECATED
- } else if (lines[i].find("$pbx_launch_image_usage_setting") != -1) {
+ } else if (lines[i].contains("$pbx_launch_image_usage_setting")) {
strnew += lines[i].replace("$pbx_launch_image_usage_setting", "") + "\n";
#endif
- } else if (lines[i].find("$launch_screen_image_mode") != -1) {
+ } else if (lines[i].contains("$launch_screen_image_mode")) {
int image_scale_mode = p_preset->get("storyboard/image_scale_mode");
String value;
@@ -586,7 +586,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
}
strnew += lines[i].replace("$launch_screen_image_mode", value) + "\n";
- } else if (lines[i].find("$launch_screen_background_color") != -1) {
+ } else if (lines[i].contains("$launch_screen_background_color")) {
bool use_custom = p_preset->get("storyboard/use_custom_bg_color");
Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : GLOBAL_GET("application/boot_splash/bg_color");
const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
@@ -599,7 +599,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
String value = value_format.format(value_dictionary, "$_");
strnew += lines[i].replace("$launch_screen_background_color", value) + "\n";
- } else if (lines[i].find("$pbx_locale_file_reference") != -1) {
+ } else if (lines[i].contains("$pbx_locale_file_reference")) {
String locale_files;
Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) {
@@ -618,7 +618,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
}
}
strnew += lines[i].replace("$pbx_locale_file_reference", locale_files);
- } else if (lines[i].find("$pbx_locale_build_reference") != -1) {
+ } else if (lines[i].contains("$pbx_locale_build_reference")) {
String locale_files;
Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) {
@@ -637,10 +637,10 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
}
}
strnew += lines[i].replace("$pbx_locale_build_reference", locale_files);
- } else if (lines[i].find("$swift_runtime_migration") != -1) {
+ } else if (lines[i].contains("$swift_runtime_migration")) {
String value = !p_config.use_swift_runtime ? "" : "LastSwiftMigration = 1250;";
strnew += lines[i].replace("$swift_runtime_migration", value) + "\n";
- } else if (lines[i].find("$swift_runtime_build_settings") != -1) {
+ } else if (lines[i].contains("$swift_runtime_build_settings")) {
String value = !p_config.use_swift_runtime ? "" : R"(
CLANG_ENABLE_MODULES = YES;
SWIFT_OBJC_BRIDGING_HEADER = "$binary/dummy.h";
@@ -648,25 +648,25 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
)";
value = value.replace("$binary", p_config.binary_name);
strnew += lines[i].replace("$swift_runtime_build_settings", value) + "\n";
- } else if (lines[i].find("$swift_runtime_fileref") != -1) {
+ } else if (lines[i].contains("$swift_runtime_fileref")) {
String value = !p_config.use_swift_runtime ? "" : R"(
90B4C2AA2680BC560039117A /* dummy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "dummy.h"; sourceTree = "<group>"; };
90B4C2B52680C7E90039117A /* dummy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "dummy.swift"; sourceTree = "<group>"; };
)";
strnew += lines[i].replace("$swift_runtime_fileref", value) + "\n";
- } else if (lines[i].find("$swift_runtime_binary_files") != -1) {
+ } else if (lines[i].contains("$swift_runtime_binary_files")) {
String value = !p_config.use_swift_runtime ? "" : R"(
90B4C2AA2680BC560039117A /* dummy.h */,
90B4C2B52680C7E90039117A /* dummy.swift */,
)";
strnew += lines[i].replace("$swift_runtime_binary_files", value) + "\n";
- } else if (lines[i].find("$swift_runtime_buildfile") != -1) {
+ } else if (lines[i].contains("$swift_runtime_buildfile")) {
String value = !p_config.use_swift_runtime ? "" : "90B4C2B62680C7E90039117A /* dummy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90B4C2B52680C7E90039117A /* dummy.swift */; };";
strnew += lines[i].replace("$swift_runtime_buildfile", value) + "\n";
- } else if (lines[i].find("$swift_runtime_build_phase") != -1) {
+ } else if (lines[i].contains("$swift_runtime_build_phase")) {
String value = !p_config.use_swift_runtime ? "" : "90B4C2B62680C7E90039117A /* dummy.swift */,";
strnew += lines[i].replace("$swift_runtime_build_phase", value) + "\n";
- } else if (lines[i].find("$priv_collection") != -1) {
+ } else if (lines[i].contains("$priv_collection")) {
bool section_opened = false;
for (uint64_t j = 0; j < sizeof(data_collect_type_info) / sizeof(data_collect_type_info[0]); ++j) {
bool data_collected = p_preset->get(vformat("privacy/collected_data/%s/collected", data_collect_type_info[j].prop_name));
@@ -710,7 +710,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
if (section_opened) {
strnew += "\t</array>\n";
}
- } else if (lines[i].find("$priv_tracking") != -1) {
+ } else if (lines[i].contains("$priv_tracking")) {
bool tracking = p_preset->get("privacy/tracking_enabled");
strnew += "\t<key>NSPrivacyTracking</key>\n";
if (tracking) {
@@ -727,7 +727,7 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
}
strnew += "\t</array>\n";
}
- } else if (lines[i].find("$priv_api_types") != -1) {
+ } else if (lines[i].contains("$priv_api_types")) {
strnew += "\t<array>\n";
for (uint64_t j = 0; j < sizeof(api_info) / sizeof(api_info[0]); ++j) {
int api_access = p_preset->get(vformat("privacy/%s_access_reasons", api_info[j].prop_name));
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index afc9d25a80..a8b8d2934a 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -309,7 +309,7 @@ def configure(env: "SConsEnvironment"):
if not env["builtin_embree"] and env["arch"] in ["x86_64", "arm64"]:
# No pkgconfig file so far, hardcode expected lib name.
- env.Append(LIBS=["embree3"])
+ env.Append(LIBS=["embree4"])
if not env["builtin_openxr"]:
env.ParseConfig("pkg-config openxr --cflags --libs")
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 827c567785..6e546c4531 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -175,7 +175,7 @@ void JoypadLinux::enumerate_joypads(udev *p_udev) {
if (devnode) {
String devnode_str = devnode;
- if (devnode_str.find(ignore_str) == -1) {
+ if (!devnode_str.contains(ignore_str)) {
open_joypad(devnode);
}
}
@@ -214,7 +214,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) {
const char *devnode = udev_device_get_devnode(dev);
if (devnode) {
String devnode_str = devnode;
- if (devnode_str.find(ignore_str) == -1) {
+ if (!devnode_str.contains(ignore_str)) {
if (action == "add") {
open_joypad(devnode);
} else if (String(action) == "remove") {
@@ -244,7 +244,7 @@ void JoypadLinux::monitor_joypads() {
continue;
}
sprintf(fname, "/dev/input/%.*s", 16, current->d_name);
- if (attached_devices.find(fname) == -1) {
+ if (!attached_devices.has(fname)) {
open_joypad(fname);
}
}
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 68b4cd7f5a..6355562feb 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -184,7 +184,7 @@ String OS_LinuxBSD::get_processor_name() const {
while (!f->eof_reached()) {
const String line = f->get_line();
- if (line.find("model name") != -1) {
+ if (line.contains("model name")) {
return line.split(":")[1].strip_edges();
}
}
@@ -269,7 +269,7 @@ String OS_LinuxBSD::get_systemd_os_release_info_value(const String &key) const {
if (f.is_valid()) {
while (!f->eof_reached()) {
const String line = f->get_line();
- if (line.find(key) != -1) {
+ if (line.contains(key)) {
String value = line.split("=")[1].strip_edges();
value = value.trim_prefix("\"");
return value.trim_suffix("\"");
diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp
index 1c3cae0435..f7995472d0 100644
--- a/platform/linuxbsd/wayland/display_server_wayland.cpp
+++ b/platform/linuxbsd/wayland/display_server_wayland.cpp
@@ -550,7 +550,15 @@ float DisplayServerWayland::screen_get_scale(int p_screen) const {
MutexLock mutex_lock(wayland_thread.mutex);
if (p_screen == SCREEN_OF_MAIN_WINDOW) {
- p_screen = window_get_current_screen();
+ // Wayland does not expose fractional scale factors at the screen-level, but
+ // some code relies on it. Since this special screen is the default and a lot
+ // of code relies on it, we'll return the window's scale, which is what we
+ // really care about. After all, we have very little use of the actual screen
+ // enumeration APIs and we're (for now) in single-window mode anyways.
+ struct wl_surface *wl_surface = wayland_thread.window_get_wl_surface(MAIN_WINDOW_ID);
+ WaylandThread::WindowState *ws = wayland_thread.wl_surface_get_window_state(wl_surface);
+
+ return wayland_thread.window_state_get_scale_factor(ws);
}
return wayland_thread.screen_get_data(p_screen).scale;
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index b76cbc126f..9174b65b1b 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -4268,6 +4268,8 @@ bool DisplayServerX11::_window_focus_check() {
}
void DisplayServerX11::process_events() {
+ ERR_FAIL_COND(!Thread::is_main_thread());
+
_THREAD_SAFE_LOCK_
#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 0041848c78..e093f01a8a 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -2985,7 +2985,7 @@ Key DisplayServerMacOS::keyboard_get_label_from_physical(Key p_keycode) const {
}
void DisplayServerMacOS::process_events() {
- _THREAD_SAFE_LOCK_
+ ERR_FAIL_COND(!Thread::is_main_thread());
while (true) {
NSEvent *event = [NSApp
@@ -3018,11 +3018,11 @@ void DisplayServerMacOS::process_events() {
if (!drop_events) {
_process_key_events();
- _THREAD_SAFE_UNLOCK_
Input::get_singleton()->flush_buffered_events();
- _THREAD_SAFE_LOCK_
}
+ _THREAD_SAFE_LOCK_
+
for (KeyValue<WindowID, WindowData> &E : windows) {
WindowData &wd = E.value;
if (wd.mpass) {
@@ -3051,7 +3051,7 @@ void DisplayServerMacOS::process_events() {
}
void DisplayServerMacOS::force_process_and_drop_events() {
- _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND(!Thread::is_main_thread());
drop_events = true;
process_events();
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 5f52d33318..96d64ef209 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -650,42 +650,42 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_pres
str.parse_utf8((const char *)plist.ptr(), plist.size());
Vector<String> lines = str.split("\n");
for (int i = 0; i < lines.size(); i++) {
- if (lines[i].find("$binary") != -1) {
+ if (lines[i].contains("$binary")) {
strnew += lines[i].replace("$binary", p_binary) + "\n";
- } else if (lines[i].find("$name") != -1) {
+ } else if (lines[i].contains("$name")) {
strnew += lines[i].replace("$name", GLOBAL_GET("application/config/name")) + "\n";
- } else if (lines[i].find("$bundle_identifier") != -1) {
+ } else if (lines[i].contains("$bundle_identifier")) {
strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
- } else if (lines[i].find("$short_version") != -1) {
+ } else if (lines[i].contains("$short_version")) {
strnew += lines[i].replace("$short_version", p_preset->get_version("application/short_version")) + "\n";
- } else if (lines[i].find("$version") != -1) {
+ } else if (lines[i].contains("$version")) {
strnew += lines[i].replace("$version", p_preset->get_version("application/version")) + "\n";
- } else if (lines[i].find("$signature") != -1) {
+ } else if (lines[i].contains("$signature")) {
strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
- } else if (lines[i].find("$app_category") != -1) {
+ } else if (lines[i].contains("$app_category")) {
String cat = p_preset->get("application/app_category");
strnew += lines[i].replace("$app_category", cat.to_lower()) + "\n";
- } else if (lines[i].find("$copyright") != -1) {
+ } else if (lines[i].contains("$copyright")) {
strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n";
- } else if (lines[i].find("$min_version") != -1) {
+ } else if (lines[i].contains("$min_version")) {
strnew += lines[i].replace("$min_version", p_preset->get("application/min_macos_version")) + "\n";
- } else if (lines[i].find("$highres") != -1) {
+ } else if (lines[i].contains("$highres")) {
strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "\t<true/>" : "\t<false/>") + "\n";
- } else if (lines[i].find("$additional_plist_content") != -1) {
+ } else if (lines[i].contains("$additional_plist_content")) {
strnew += lines[i].replace("$additional_plist_content", p_preset->get("application/additional_plist_content")) + "\n";
- } else if (lines[i].find("$platfbuild") != -1) {
+ } else if (lines[i].contains("$platfbuild")) {
strnew += lines[i].replace("$platfbuild", p_preset->get("xcode/platform_build")) + "\n";
- } else if (lines[i].find("$sdkver") != -1) {
+ } else if (lines[i].contains("$sdkver")) {
strnew += lines[i].replace("$sdkver", p_preset->get("xcode/sdk_version")) + "\n";
- } else if (lines[i].find("$sdkname") != -1) {
+ } else if (lines[i].contains("$sdkname")) {
strnew += lines[i].replace("$sdkname", p_preset->get("xcode/sdk_name")) + "\n";
- } else if (lines[i].find("$sdkbuild") != -1) {
+ } else if (lines[i].contains("$sdkbuild")) {
strnew += lines[i].replace("$sdkbuild", p_preset->get("xcode/sdk_build")) + "\n";
- } else if (lines[i].find("$xcodever") != -1) {
+ } else if (lines[i].contains("$xcodever")) {
strnew += lines[i].replace("$xcodever", p_preset->get("xcode/xcode_version")) + "\n";
- } else if (lines[i].find("$xcodebuild") != -1) {
+ } else if (lines[i].contains("$xcodebuild")) {
strnew += lines[i].replace("$xcodebuild", p_preset->get("xcode/xcode_build")) + "\n";
- } else if (lines[i].find("$usage_descriptions") != -1) {
+ } else if (lines[i].contains("$usage_descriptions")) {
String descriptions;
if (!((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) {
descriptions += "\t<key>NSMicrophoneUsageDescription</key>\n";
@@ -1081,7 +1081,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
continue;
}
- if (extensions_to_sign.find(current_file.get_extension()) > -1) {
+ if (extensions_to_sign.has(current_file.get_extension())) {
int ftype = MachO::get_filetype(current_file_path);
Error code_sign_error{ _code_sign(p_preset, current_file_path, (ftype == 2 || ftype == 5) ? p_helper_ent_path : p_ent_path, false, (ftype == 2 || ftype == 5)) };
if (code_sign_error != OK) {
@@ -1202,7 +1202,7 @@ Error EditorExportPlatformMacOS::_copy_and_sign_files(Ref<DirAccess> &dir_access
// If it is a directory, find and sign all dynamic libraries.
err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_helper_ent_path, p_should_error_on_non_code_sign);
} else {
- if (extensions_to_sign.find(p_in_app_path.get_extension()) > -1) {
+ if (extensions_to_sign.has(p_in_app_path.get_extension())) {
int ftype = MachO::get_filetype(p_in_app_path);
err = _code_sign(p_preset, p_in_app_path, (ftype == 2 || ftype == 5) ? p_helper_ent_path : p_ent_path, false, (ftype == 2 || ftype == 5));
}
@@ -1260,7 +1260,7 @@ Error EditorExportPlatformMacOS::_create_pkg(const Ref<EditorExportPreset> &p_pr
}
print_verbose("productbuild returned: " + str);
- if (str.find("productbuild: error:") != -1) {
+ if (str.contains("productbuild: error:")) {
add_message(EXPORT_MESSAGE_ERROR, TTR("PKG Creation"), TTR("`productbuild` failed."));
return FAILED;
}
@@ -1292,8 +1292,8 @@ Error EditorExportPlatformMacOS::_create_dmg(const String &p_dmg_path, const Str
}
print_verbose("hdiutil returned: " + str);
- if (str.find("create failed") != -1) {
- if (str.find("File exists") != -1) {
+ if (str.contains("create failed")) {
+ if (str.contains("File exists")) {
add_message(EXPORT_MESSAGE_ERROR, TTR("DMG Creation"), TTR("`hdiutil create` failed - file exists."));
} else {
add_message(EXPORT_MESSAGE_ERROR, TTR("DMG Creation"), TTR("`hdiutil create` failed."));
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 94c368c504..e79d16629e 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -2962,30 +2962,28 @@ String DisplayServerWindows::keyboard_get_layout_name(int p_index) const {
}
void DisplayServerWindows::process_events() {
- _THREAD_SAFE_LOCK_
-
- MSG msg;
+ ERR_FAIL_COND(!Thread::is_main_thread());
if (!drop_events) {
joypad->process_joypads();
}
+ _THREAD_SAFE_LOCK_
+ MSG msg = {};
while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
+ _THREAD_SAFE_UNLOCK_
if (!drop_events) {
_process_key_events();
- _THREAD_SAFE_UNLOCK_
Input::get_singleton()->flush_buffered_events();
- } else {
- _THREAD_SAFE_UNLOCK_
}
}
void DisplayServerWindows::force_process_and_drop_events() {
- _THREAD_SAFE_METHOD_
+ ERR_FAIL_COND(!Thread::is_main_thread());
drop_events = true;
process_events();
@@ -4664,10 +4662,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WM_TIMER: {
if (wParam == windows[window_id].move_timer_id) {
+ _THREAD_SAFE_UNLOCK_
_process_key_events();
if (!Main::is_iterating()) {
Main::iteration();
}
+ _THREAD_SAFE_LOCK_
} else if (wParam == windows[window_id].activate_timer_id) {
_process_activate_event(window_id);
KillTimer(windows[window_id].hWnd, windows[window_id].activate_timer_id);
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index a3c86611a4..6ce9d27dc5 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -347,7 +347,7 @@ String EditorExportPlatformWindows::get_export_option_warning(const EditorExport
PackedStringArray version_array = file_version.split(".", false);
if (version_array.size() != 4 || !version_array[0].is_valid_int() ||
!version_array[1].is_valid_int() || !version_array[2].is_valid_int() ||
- !version_array[3].is_valid_int() || file_version.find("-") > -1) {
+ !version_array[3].is_valid_int() || file_version.contains("-")) {
return TTR("Invalid file version.");
}
}
@@ -357,7 +357,7 @@ String EditorExportPlatformWindows::get_export_option_warning(const EditorExport
PackedStringArray version_array = product_version.split(".", false);
if (version_array.size() != 4 || !version_array[0].is_valid_int() ||
!version_array[1].is_valid_int() || !version_array[2].is_valid_int() ||
- !version_array[3].is_valid_int() || product_version.find("-") > -1) {
+ !version_array[3].is_valid_int() || product_version.contains("-")) {
return TTR("Invalid product version.");
}
}
@@ -569,13 +569,13 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
DirAccess::remove_file_or_error(tmp_icon_path);
}
- if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
+ if (err != OK || str.contains("not found") || str.contains("not recognized")) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > rcedit), or disable \"Application > Modify Resources\" in the export preset."));
return err;
}
print_line("rcedit (" + p_path + "): " + str);
- if (str.find("Fatal error") != -1) {
+ if (str.contains("Fatal error")) {
add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), vformat(TTR("rcedit failed to modify executable: %s."), str));
return FAILED;
}
@@ -718,7 +718,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
String str;
Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true);
- if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
+ if (err != OK || str.contains("not found") || str.contains("not recognized")) {
#ifdef WINDOWS_ENABLED
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable. Configure signtool path in the Editor Settings (Export > Windows > signtool), or disable \"Codesign\" in the export preset."));
#else
@@ -729,9 +729,9 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
print_line("codesign (" + p_path + "): " + str);
#ifndef WINDOWS_ENABLED
- if (str.find("SignTool Error") != -1) {
+ if (str.contains("SignTool Error")) {
#else
- if (str.find("Failed") != -1) {
+ if (str.contains("Failed")) {
#endif
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Signtool failed to sign executable: %s."), str));
return FAILED;
diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis
index e0d3cfe13a..14536fa130 100644
--- a/platform/windows/godot.natvis
+++ b/platform/windows/godot.natvis
@@ -15,7 +15,7 @@
<Item Name="[size]">_p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Item>
<ArrayItems>
<Size>_p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Size>
- <ValuePointer>(Variant *) _p->array._cowdata._ptr</ValuePointer>
+ <ValuePointer>(Variant *) _p->array._cowdata._ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py
index fc52e39456..dd480571ba 100644
--- a/platform/windows/platform_windows_builders.py
+++ b/platform/windows/platform_windows_builders.py
@@ -5,13 +5,16 @@ from detect import get_mingw_tool
def make_debug_mingw(target, source, env):
- objcopy = get_mingw_tool("objcopy", env["mingw_prefix"], env["arch"])
- strip = get_mingw_tool("strip", env["mingw_prefix"], env["arch"])
+ dst = str(target[0])
+ # Force separate debug symbols if executable size is larger than 1.9 GB.
+ if env["separate_debug_symbols"] or os.stat(dst).st_size >= 2040109465:
+ objcopy = get_mingw_tool("objcopy", env["mingw_prefix"], env["arch"])
+ strip = get_mingw_tool("strip", env["mingw_prefix"], env["arch"])
- if not objcopy or not strip:
- print('`separate_debug_symbols` requires both "objcopy" and "strip" to function.')
- return
+ if not objcopy or not strip:
+ print('`separate_debug_symbols` requires both "objcopy" and "strip" to function.')
+ return
- os.system("{0} --only-keep-debug {1} {1}.debugsymbols".format(objcopy, target[0]))
- os.system("{0} --strip-debug --strip-unneeded {1}".format(strip, target[0]))
- os.system("{0} --add-gnu-debuglink={1}.debugsymbols {1}".format(objcopy, target[0]))
+ os.system("{0} --only-keep-debug {1} {1}.debugsymbols".format(objcopy, dst))
+ os.system("{0} --strip-debug --strip-unneeded {1}".format(strip, dst))
+ os.system("{0} --add-gnu-debuglink={1}.debugsymbols {1}".format(objcopy, dst))
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index 446ed794ed..521013d600 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -61,7 +61,7 @@ protected:
static LightmapRaycaster *(*create_function)();
public:
- // compatible with embree3 rays
+ // Compatible with embree4 rays.
struct __aligned(16) Ray {
const static unsigned int INVALID_GEOMETRY_ID = ((unsigned int)-1); // from rtcore_common.h
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 2ddccb0253..72b5b53b19 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -253,7 +253,7 @@ void Skeleton3D::_update_process_order() {
int parent_bone_idx = bonesptr[i].parent;
// Check to see if this node is already added to the parent.
- if (bonesptr[parent_bone_idx].child_bones.find(i) < 0) {
+ if (!bonesptr[parent_bone_idx].child_bones.has(i)) {
// Add the child node.
bonesptr[parent_bone_idx].child_bones.push_back(i);
} else {
diff --git a/scene/gui/aspect_ratio_container.cpp b/scene/gui/aspect_ratio_container.cpp
index 711dd13781..1663a7d602 100644
--- a/scene/gui/aspect_ratio_container.cpp
+++ b/scene/gui/aspect_ratio_container.cpp
@@ -35,16 +35,10 @@
Size2 AspectRatioContainer::get_minimum_size() const {
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
- if (!c->is_visible()) {
- continue;
- }
Size2 minsize = c->get_combined_minimum_size();
ms = ms.max(minsize);
}
@@ -107,13 +101,10 @@ void AspectRatioContainer::_notification(int p_what) {
bool rtl = is_layout_rtl();
Size2 size = get_size();
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
// Temporary fix for editor crash.
TextureRect *trect = Object::cast_to<TextureRect>(c);
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index 2728126e64..88f65ca1bc 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -55,11 +55,8 @@ void BoxContainer::_resort() {
HashMap<Control *, _MinSizeCache> min_size_cache;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible_in_tree()) {
- continue;
- }
- if (c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(get_child(i));
+ if (!c) {
continue;
}
@@ -109,11 +106,8 @@ void BoxContainer::_resort() {
float error = 0.0; // Keep track of accumulated error in pixels
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible_in_tree()) {
- continue;
- }
- if (c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(get_child(i));
+ if (!c) {
continue;
}
@@ -201,11 +195,8 @@ void BoxContainer::_resort() {
}
for (int i = start; i != end; i += delta) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible_in_tree()) {
- continue;
- }
- if (c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(get_child(i));
+ if (!c) {
continue;
}
@@ -252,17 +243,10 @@ Size2 BoxContainer::get_minimum_size() const {
bool first = true;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
-
- if (!c->is_visible()) {
- continue;
- }
Size2i size = c->get_combined_minimum_size();
diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp
index acdeae289b..1af33d2814 100644
--- a/scene/gui/center_container.cpp
+++ b/scene/gui/center_container.cpp
@@ -36,16 +36,10 @@ Size2 CenterContainer::get_minimum_size() const {
}
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
- if (!c->is_visible()) {
- continue;
- }
Size2 minsize = c->get_combined_minimum_size();
ms = ms.max(minsize);
}
@@ -81,14 +75,10 @@ void CenterContainer::_notification(int p_what) {
case NOTIFICATION_SORT_CHILDREN: {
Size2 size = get_size();
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
-
Size2 minsize = c->get_combined_minimum_size();
Point2 ofs = use_top_left ? (-minsize * 0.5).floor() : ((size - minsize) / 2.0).floor();
fit_child_in_rect(c, Rect2(ofs, minsize));
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index c6e66c95c6..5db8d69eef 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -141,6 +141,14 @@ void Container::queue_sort() {
pending_sort = true;
}
+Control *Container::as_sortable_control(Node *p_node) const {
+ Control *c = Object::cast_to<Control>(p_node);
+ if (!c || !c->is_visible_in_tree() || c->is_set_as_top_level()) {
+ return nullptr;
+ }
+ return c;
+}
+
Vector<int> Container::get_allowed_size_flags_horizontal() const {
Vector<int> flags;
if (GDVIRTUAL_CALL(_get_allowed_size_flags_horizontal, flags)) {
diff --git a/scene/gui/container.h b/scene/gui/container.h
index 94c3c540d7..405220cee6 100644
--- a/scene/gui/container.h
+++ b/scene/gui/container.h
@@ -42,6 +42,8 @@ class Container : public Control {
protected:
void queue_sort();
+ Control *as_sortable_control(Node *p_node) const;
+
virtual void add_child_notify(Node *p_child) override;
virtual void move_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp
index f8128a9dc6..ceffd9d103 100644
--- a/scene/gui/flow_container.cpp
+++ b/scene/gui/flow_container.cpp
@@ -63,11 +63,8 @@ void FlowContainer::_resort() {
// First pass for line wrapping and minimum size calculation.
for (int i = 0; i < get_child_count(); i++) {
- Control *child = Object::cast_to<Control>(get_child(i));
- if (!child || !child->is_visible()) {
- continue;
- }
- if (child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i));
+ if (!child) {
continue;
}
@@ -138,11 +135,8 @@ void FlowContainer::_resort() {
ofs.y = 0;
for (int i = 0; i < get_child_count(); i++) {
- Control *child = Object::cast_to<Control>(get_child(i));
- if (!child || !child->is_visible()) {
- continue;
- }
- if (child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i));
+ if (!child) {
continue;
}
Size2i child_size = children_minsize_cache[child];
@@ -256,17 +250,10 @@ Size2 FlowContainer::get_minimum_size() const {
Size2i minimum;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
-
- if (!c->is_visible()) {
- continue;
- }
Size2i size = c->get_combined_minimum_size();
diff --git a/scene/gui/graph_element.cpp b/scene/gui/graph_element.cpp
index 9c13a3ad9e..e231b05d7f 100644
--- a/scene/gui/graph_element.cpp
+++ b/scene/gui/graph_element.cpp
@@ -49,14 +49,10 @@ void GraphElement::_resort() {
Size2 size = get_size();
for (int i = 0; i < get_child_count(); i++) {
- Control *child = Object::cast_to<Control>(get_child(i));
- if (!child || !child->is_visible_in_tree()) {
- continue;
- }
- if (child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i));
+ if (!child) {
continue;
}
-
fit_child_in_rect(child, Rect2(Point2(), size));
}
}
@@ -65,10 +61,7 @@ Size2 GraphElement::get_minimum_size() const {
Size2 minsize;
for (int i = 0; i < get_child_count(); i++) {
Control *child = Object::cast_to<Control>(get_child(i));
- if (!child) {
- continue;
- }
- if (child->is_set_as_top_level()) {
+ if (!child || child->is_set_as_top_level()) {
continue;
}
diff --git a/scene/gui/graph_frame.cpp b/scene/gui/graph_frame.cpp
index ca9f7e6fcf..8cd7dbbeb5 100644
--- a/scene/gui/graph_frame.cpp
+++ b/scene/gui/graph_frame.cpp
@@ -160,14 +160,10 @@ void GraphFrame::_resort() {
Point2 offset = Point2(sb_panel->get_margin(SIDE_LEFT), sb_panel->get_margin(SIDE_TOP) + titlebar_min_size.height + sb_titlebar->get_minimum_size().height);
for (int i = 0; i < get_child_count(false); i++) {
- Control *child = Object::cast_to<Control>(get_child(i, false));
- if (!child || !child->is_visible_in_tree()) {
+ Control *child = as_sortable_control(get_child(i, false));
+ if (!child) {
continue;
}
- if (child->is_set_as_top_level()) {
- continue;
- }
-
fit_child_in_rect(child, Rect2(offset, size));
}
}
@@ -325,8 +321,8 @@ Size2 GraphFrame::get_minimum_size() const {
Size2 minsize = titlebar_hbox->get_minimum_size() + sb_titlebar->get_minimum_size();
for (int i = 0; i < get_child_count(false); i++) {
- Control *child = Object::cast_to<Control>(get_child(i, false));
- if (!child || !child->is_visible() || child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i, false));
+ if (!child) {
continue;
}
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index d035515b51..75ac5c5135 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -175,9 +175,8 @@ void GraphNode::_resort() {
HashMap<Control *, _MinSizeCache> min_size_cache;
for (int i = 0; i < get_child_count(false); i++) {
- Control *child = Object::cast_to<Control>(get_child(i, false));
-
- if (!child || !child->is_visible_in_tree() || child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i, false));
+ if (!child) {
continue;
}
@@ -218,8 +217,8 @@ void GraphNode::_resort() {
bool refit_successful = true;
for (int i = 0; i < get_child_count(false); i++) {
- Control *child = Object::cast_to<Control>(get_child(i, false));
- if (!child || !child->is_visible_in_tree() || child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i, false));
+ if (!child) {
continue;
}
@@ -256,8 +255,8 @@ void GraphNode::_resort() {
int width = new_size.width - sb_panel->get_minimum_size().width;
int valid_children_idx = 0;
for (int i = 0; i < get_child_count(false); i++) {
- Control *child = Object::cast_to<Control>(get_child(i, false));
- if (!child || !child->is_visible_in_tree() || child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i, false));
+ if (!child) {
continue;
}
@@ -614,8 +613,8 @@ Size2 GraphNode::get_minimum_size() const {
Size2 minsize = titlebar_hbox->get_minimum_size() + sb_titlebar->get_minimum_size();
for (int i = 0; i < get_child_count(false); i++) {
- Control *child = Object::cast_to<Control>(get_child(i, false));
- if (!child || !child->is_visible() || child->is_set_as_top_level()) {
+ Control *child = as_sortable_control(get_child(i, false));
+ if (!child) {
continue;
}
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index a4baf3bb8d..a67bba786b 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -44,11 +44,8 @@ void GridContainer::_notification(int p_what) {
// Compute the per-column/per-row data.
int valid_controls_index = 0;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible_in_tree()) {
- continue;
- }
- if (c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(get_child(i));
+ if (!c) {
continue;
}
@@ -186,8 +183,8 @@ void GridContainer::_notification(int p_what) {
valid_controls_index = 0;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible_in_tree()) {
+ Control *c = as_sortable_control(get_child(i));
+ if (!c) {
continue;
}
int row = valid_controls_index / columns;
@@ -282,8 +279,8 @@ Size2 GridContainer::get_minimum_size() const {
int valid_controls_index = 0;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible()) {
+ Control *c = as_sortable_control(get_child(i));
+ if (!c) {
continue;
}
int row = valid_controls_index / columns;
diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp
index 6d331afbb5..91e6c1f092 100644
--- a/scene/gui/margin_container.cpp
+++ b/scene/gui/margin_container.cpp
@@ -36,16 +36,10 @@ Size2 MarginContainer::get_minimum_size() const {
Size2 max;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
- if (!c->is_visible()) {
- continue;
- }
Size2 s = c->get_combined_minimum_size();
if (s.width > max.width) {
@@ -103,13 +97,10 @@ void MarginContainer::_notification(int p_what) {
Size2 s = get_size();
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
int w = s.width - theme_cache.margin_left - theme_cache.margin_right;
int h = s.height - theme_cache.margin_top - theme_cache.margin_bottom;
diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp
index ef85919859..76fde26b26 100644
--- a/scene/gui/panel_container.cpp
+++ b/scene/gui/panel_container.cpp
@@ -35,11 +35,8 @@
Size2 PanelContainer::get_minimum_size() const {
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible()) {
- continue;
- }
- if (c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(get_child(i));
+ if (!c) {
continue;
}
@@ -87,11 +84,8 @@ void PanelContainer::_notification(int p_what) {
}
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible_in_tree()) {
- continue;
- }
- if (c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(get_child(i));
+ if (!c) {
continue;
}
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 4f49f60d70..6f5d0cdcfb 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -43,11 +43,8 @@ Size2 ScrollContainer::get_minimum_size() const {
largest_child_min_size = Size2();
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible()) {
- continue;
- }
- if (c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(get_child(i));
+ if (!c) {
continue;
}
if (c == h_scroll || c == v_scroll) {
@@ -308,11 +305,8 @@ void ScrollContainer::_reposition_children() {
}
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
- if (!c || !c->is_visible()) {
- continue;
- }
- if (c->is_set_as_top_level()) {
+ Control *c = as_sortable_control(get_child(i));
+ if (!c) {
continue;
}
if (c == h_scroll || c == v_scroll) {
@@ -542,13 +536,10 @@ PackedStringArray ScrollContainer::get_configuration_warnings() const {
int found = 0;
for (int i = 0; i < get_child_count(); i++) {
- Control *c = Object::cast_to<Control>(get_child(i));
+ Control *c = as_sortable_control(get_child(i));
if (!c) {
continue;
}
- if (c->is_set_as_top_level()) {
- continue;
- }
if (c == h_scroll || c == v_scroll) {
continue;
}
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 5f4586a6d5..98b1db4a96 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -127,10 +127,7 @@ Control *SplitContainer::get_containable_child(int p_idx) const {
for (int i = 0; i < get_child_count(false); i++) {
Control *c = Object::cast_to<Control>(get_child(i, false));
- if (!c || !c->is_visible()) {
- continue;
- }
- if (c->is_set_as_top_level()) {
+ if (!c || !c->is_visible() || c->is_set_as_top_level()) {
continue;
}
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index bbe5ddf1c3..dc48945d9b 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -526,7 +526,7 @@ void TextureProgressBar::_notification(int p_what) {
Vector<Point2> points;
for (const float &f : pts) {
Point2 uv = unit_val_to_uv(f);
- if (uvs.find(uv) >= 0) {
+ if (uvs.has(uv)) {
continue;
}
points.push_back(progress_offset + Point2(uv.x * s.x, uv.y * s.y));
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index df0bb365e5..e2de585a69 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -2828,7 +2828,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int
return -1;
}
- if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + theme_cache.item_margin))) {
+ if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x < (x_ofs + theme_cache.item_margin))) {
if (enable_recursive_folding && p_mod->is_shift_pressed()) {
p_item->set_collapsed_recursive(!p_item->is_collapsed());
} else {
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 0f89784369..3469b806a6 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -239,7 +239,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
String new_request;
for (const String &E : rheaders) {
- if (E.findn("Location: ") != -1) {
+ if (E.containsn("Location: ")) {
new_request = E.substr(9, E.length()).strip_edges();
}
}
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 827273132c..e54209c1dd 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2930,8 +2930,10 @@ void Node::_duplicate_properties_node(const Node *p_root, const Node *p_original
}
}
- for (int i = 0; i < p_copy->get_child_count(); i++) {
- _duplicate_properties_node(p_root, p_original->get_child(i), p_copy->get_child(i));
+ for (int i = 0; i < p_original->get_child_count(); i++) {
+ Node *copy_child = p_copy->get_child(i);
+ ERR_FAIL_NULL_MSG(copy_child, "Child node disappeared while duplicating.");
+ _duplicate_properties_node(p_root, p_original->get_child(i), copy_child);
}
}
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 73f3009fd1..8b5e438aea 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1880,7 +1880,7 @@ void ArrayMesh::set_blend_shape_name(int p_index, const StringName &p_name) {
do {
shape_name = String(p_name) + " " + itos(count);
count++;
- } while (blend_shapes.find(shape_name) != -1);
+ } while (blend_shapes.has(shape_name));
}
blend_shapes.write[p_index] = shape_name;
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index b5333d91c6..051ed59632 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -618,7 +618,7 @@ Ref<AudioStreamPlayback> AudioStreamRandomizer::instance_playback_sequential() {
if (entry.stream.is_null()) {
continue;
}
- if (local_pool.find(entry.stream) != -1) {
+ if (local_pool.has(entry.stream)) {
WARN_PRINT("Duplicate stream in sequential playback pool");
continue;
}
diff --git a/servers/physics_server_2d_wrap_mt.cpp b/servers/physics_server_2d_wrap_mt.cpp
index 4548bb91cb..8e9f7aa8fc 100644
--- a/servers/physics_server_2d_wrap_mt.cpp
+++ b/servers/physics_server_2d_wrap_mt.cpp
@@ -32,45 +32,37 @@
#include "core/os/os.h"
-void PhysicsServer2DWrapMT::thread_exit() {
- exit = true;
+void PhysicsServer2DWrapMT::_assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id) {
+ server_thread = Thread::get_caller_id();
+ server_task_id = p_pump_task_id;
}
-void PhysicsServer2DWrapMT::thread_step(real_t p_delta) {
- physics_server_2d->step(p_delta);
- step_sem.post();
+void PhysicsServer2DWrapMT::_thread_exit() {
+ exit = true;
}
-void PhysicsServer2DWrapMT::thread_loop() {
- server_thread = Thread::get_caller_id();
-
- physics_server_2d->init();
-
- command_queue.set_pump_task_id(server_task_id);
+void PhysicsServer2DWrapMT::_thread_loop() {
while (!exit) {
WorkerThreadPool::get_singleton()->yield();
command_queue.flush_all();
}
-
- command_queue.flush_all();
-
- physics_server_2d->finish();
}
/* EVENT QUEUING */
void PhysicsServer2DWrapMT::step(real_t p_step) {
if (create_thread) {
- command_queue.push(this, &PhysicsServer2DWrapMT::thread_step, p_step);
+ command_queue.push(physics_server_2d, &PhysicsServer2D::step, p_step);
} else {
- command_queue.flush_all(); // Flush all pending from other threads.
physics_server_2d->step(p_step);
}
}
void PhysicsServer2DWrapMT::sync() {
if (create_thread) {
- step_sem.wait();
+ command_queue.sync();
+ } else {
+ command_queue.flush_all(); // Flush all pending from other threads.
}
physics_server_2d->sync();
}
@@ -85,21 +77,26 @@ void PhysicsServer2DWrapMT::end_sync() {
void PhysicsServer2DWrapMT::init() {
if (create_thread) {
- exit = false;
- server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer2DWrapMT::thread_loop), true);
- step_sem.post();
+ WorkerThreadPool::TaskID tid = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer2DWrapMT::_thread_loop), true);
+ command_queue.set_pump_task_id(tid);
+ command_queue.push(this, &PhysicsServer2DWrapMT::_assign_mt_ids, tid);
+ command_queue.push_and_sync(physics_server_2d, &PhysicsServer2D::init);
+ DEV_ASSERT(server_task_id == tid);
} else {
+ server_thread = Thread::MAIN_ID;
physics_server_2d->init();
}
}
void PhysicsServer2DWrapMT::finish() {
if (create_thread) {
- command_queue.push(this, &PhysicsServer2DWrapMT::thread_exit);
+ command_queue.push(physics_server_2d, &PhysicsServer2D::finish);
+ command_queue.push(this, &PhysicsServer2DWrapMT::_thread_exit);
if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id);
server_task_id = WorkerThreadPool::INVALID_TASK_ID;
}
+ server_thread = Thread::MAIN_ID;
} else {
physics_server_2d->finish();
}
@@ -108,9 +105,6 @@ void PhysicsServer2DWrapMT::finish() {
PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread) {
physics_server_2d = p_contained;
create_thread = p_create_thread;
- if (!create_thread) {
- server_thread = Thread::MAIN_ID;
- }
}
PhysicsServer2DWrapMT::~PhysicsServer2DWrapMT() {
diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h
index 5e2b3b4086..f0c36a906f 100644
--- a/servers/physics_server_2d_wrap_mt.h
+++ b/servers/physics_server_2d_wrap_mt.h
@@ -53,17 +53,14 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D {
mutable CommandQueueMT command_queue;
- void thread_loop();
-
Thread::ID server_thread = Thread::UNASSIGNED_ID;
WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID;
bool exit = false;
- Semaphore step_sem;
bool create_thread = false;
- void thread_step(real_t p_delta);
-
- void thread_exit();
+ void _assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id);
+ void _thread_exit();
+ void _thread_loop();
public:
#define ServerName PhysicsServer2D
diff --git a/servers/physics_server_3d_wrap_mt.cpp b/servers/physics_server_3d_wrap_mt.cpp
index f8f60281a7..95b71217c4 100644
--- a/servers/physics_server_3d_wrap_mt.cpp
+++ b/servers/physics_server_3d_wrap_mt.cpp
@@ -32,45 +32,37 @@
#include "core/os/os.h"
-void PhysicsServer3DWrapMT::thread_exit() {
- exit = true;
+void PhysicsServer3DWrapMT::_assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id) {
+ server_thread = Thread::get_caller_id();
+ server_task_id = p_pump_task_id;
}
-void PhysicsServer3DWrapMT::thread_step(real_t p_delta) {
- physics_server_3d->step(p_delta);
- step_sem.post();
+void PhysicsServer3DWrapMT::_thread_exit() {
+ exit = true;
}
-void PhysicsServer3DWrapMT::thread_loop() {
- server_thread = Thread::get_caller_id();
-
- physics_server_3d->init();
-
- command_queue.set_pump_task_id(server_task_id);
+void PhysicsServer3DWrapMT::_thread_loop() {
while (!exit) {
WorkerThreadPool::get_singleton()->yield();
command_queue.flush_all();
}
-
- command_queue.flush_all(); // flush all
-
- physics_server_3d->finish();
}
/* EVENT QUEUING */
void PhysicsServer3DWrapMT::step(real_t p_step) {
if (create_thread) {
- command_queue.push(this, &PhysicsServer3DWrapMT::thread_step, p_step);
+ command_queue.push(physics_server_3d, &PhysicsServer3D::step, p_step);
} else {
- command_queue.flush_all(); // Flush all pending from other threads.
physics_server_3d->step(p_step);
}
}
void PhysicsServer3DWrapMT::sync() {
if (create_thread) {
- step_sem.wait();
+ command_queue.sync();
+ } else {
+ command_queue.flush_all(); // Flush all pending from other threads.
}
physics_server_3d->sync();
}
@@ -85,21 +77,26 @@ void PhysicsServer3DWrapMT::end_sync() {
void PhysicsServer3DWrapMT::init() {
if (create_thread) {
- exit = false;
- server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer3DWrapMT::thread_loop), true);
- step_sem.post();
+ WorkerThreadPool::TaskID tid = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer3DWrapMT::_thread_loop), true);
+ command_queue.set_pump_task_id(tid);
+ command_queue.push(this, &PhysicsServer3DWrapMT::_assign_mt_ids, tid);
+ command_queue.push_and_sync(physics_server_3d, &PhysicsServer3D::init);
+ DEV_ASSERT(server_task_id == tid);
} else {
+ server_thread = Thread::MAIN_ID;
physics_server_3d->init();
}
}
void PhysicsServer3DWrapMT::finish() {
if (create_thread) {
- command_queue.push(this, &PhysicsServer3DWrapMT::thread_exit);
+ command_queue.push(physics_server_3d, &PhysicsServer3D::finish);
+ command_queue.push(this, &PhysicsServer3DWrapMT::_thread_exit);
if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id);
server_task_id = WorkerThreadPool::INVALID_TASK_ID;
}
+ server_thread = Thread::MAIN_ID;
} else {
physics_server_3d->finish();
}
@@ -108,9 +105,6 @@ void PhysicsServer3DWrapMT::finish() {
PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread) {
physics_server_3d = p_contained;
create_thread = p_create_thread;
- if (!create_thread) {
- server_thread = Thread::MAIN_ID;
- }
}
PhysicsServer3DWrapMT::~PhysicsServer3DWrapMT() {
diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h
index 22f3ee0e45..0909c46b55 100644
--- a/servers/physics_server_3d_wrap_mt.h
+++ b/servers/physics_server_3d_wrap_mt.h
@@ -52,17 +52,15 @@ class PhysicsServer3DWrapMT : public PhysicsServer3D {
mutable CommandQueueMT command_queue;
- void thread_loop();
-
Thread::ID server_thread = Thread::UNASSIGNED_ID;
WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID;
bool exit = false;
- Semaphore step_sem;
bool create_thread = false;
- void thread_step(real_t p_delta);
-
- void thread_exit();
+ void _assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id);
+ void _thread_exit();
+ void _thread_step(real_t p_delta);
+ void _thread_loop();
public:
#define ServerName PhysicsServer3D
diff --git a/servers/rendering/renderer_rd/shaders/samplers_inc.glsl b/servers/rendering/renderer_rd/shaders/samplers_inc.glsl
index 3f6172795e..ae5dbd4761 100644
--- a/servers/rendering/renderer_rd/shaders/samplers_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/samplers_inc.glsl
@@ -9,4 +9,4 @@ layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 7) uniform sampler SAMP
layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 8) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT;
layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 9) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT;
layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 10) uniform sampler SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
-layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 11) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT; \ No newline at end of file
+layout(set = 0, binding = SAMPLERS_BINDING_FIRST_INDEX + 11) uniform sampler SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index e739ffa535..884f8adb8c 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -678,7 +678,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
#endif // _3D_DISABLED
if (Engine::get_singleton()->is_editor_hint()) {
- set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
+ RSG::texture_storage->set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
}
if (sorted_active_viewports_dirty) {
@@ -1521,10 +1521,6 @@ void RendererViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time,
}
}
-void RendererViewport::set_default_clear_color(const Color &p_color) {
- RSG::texture_storage->set_default_clear_color(p_color);
-}
-
void RendererViewport::viewport_set_canvas_cull_mask(RID p_viewport, uint32_t p_canvas_cull_mask) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_NULL(viewport);
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index 8bdce04c50..b36fc7f57f 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -303,7 +303,6 @@ public:
void handle_timestamp(String p_timestamp, uint64_t p_cpu_time, uint64_t p_gpu_time);
- void set_default_clear_color(const Color &p_color);
void draw_viewports(bool p_swap_buffers);
bool free(RID p_rid);
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 1ee5362f2c..31fc51efaa 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -671,9 +671,9 @@ RID RenderingDevice::texture_create(const TextureFormat &p_format, const Texture
TextureFormat format = p_format;
if (format.shareable_formats.size()) {
- ERR_FAIL_COND_V_MSG(format.shareable_formats.find(format.format) == -1, RID(),
+ ERR_FAIL_COND_V_MSG(!format.shareable_formats.has(format.format), RID(),
"If supplied a list of shareable formats, the current format must be present in the list");
- ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && format.shareable_formats.find(p_view.format_override) == -1, RID(),
+ ERR_FAIL_COND_V_MSG(p_view.format_override != DATA_FORMAT_MAX && !format.shareable_formats.has(p_view.format_override), RID(),
"If supplied a list of shareable formats, the current view format override must be present in the list");
}
@@ -854,7 +854,7 @@ RID RenderingDevice::texture_create_shared(const TextureView &p_view, RID p_with
} else {
ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
- ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(),
+ ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(),
"Format override is not in the list of allowed shareable formats for original texture.");
tv.format = p_view.format_override;
}
@@ -984,7 +984,7 @@ RID RenderingDevice::texture_create_shared_from_slice(const TextureView &p_view,
} else {
ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
- ERR_FAIL_COND_V_MSG(texture.allowed_shared_formats.find(p_view.format_override) == -1, RID(),
+ ERR_FAIL_COND_V_MSG(!texture.allowed_shared_formats.has(p_view.format_override), RID(),
"Format override is not in the list of allowed shareable formats for original texture.");
tv.format = p_view.format_override;
}
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index 7e5ccee0e3..51ff009eaf 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -69,8 +69,6 @@ void RenderingServerDefault::request_frame_drawn_callback(const Callable &p_call
}
void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
- changes = 0;
-
RSG::rasterizer->begin_frame(frame_step);
TIMESTAMP_BEGIN()
@@ -102,19 +100,11 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
RSG::canvas->update_visibility_notifiers();
RSG::scene->update_visibility_notifiers();
- while (frame_drawn_callbacks.front()) {
- Callable c = frame_drawn_callbacks.front()->get();
- Variant result;
- Callable::CallError ce;
- c.callp(nullptr, 0, result, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- String err = Variant::get_callable_error_text(c, nullptr, 0, ce);
- ERR_PRINT("Error calling frame drawn function: " + err);
- }
-
- frame_drawn_callbacks.pop_front();
+ if (create_thread) {
+ callable_mp(this, &RenderingServerDefault::_run_post_draw_steps).call_deferred();
+ } else {
+ _run_post_draw_steps();
}
- RS::get_singleton()->emit_signal(SNAME("frame_post_draw"));
if (RSG::utilities->get_captured_timestamps_count()) {
Vector<FrameProfileArea> new_profile;
@@ -194,6 +184,23 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
RSG::utilities->update_memory_info();
}
+void RenderingServerDefault::_run_post_draw_steps() {
+ while (frame_drawn_callbacks.front()) {
+ Callable c = frame_drawn_callbacks.front()->get();
+ Variant result;
+ Callable::CallError ce;
+ c.callp(nullptr, 0, result, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ String err = Variant::get_callable_error_text(c, nullptr, 0, ce);
+ ERR_PRINT("Error calling frame drawn function: " + err);
+ }
+
+ frame_drawn_callbacks.pop_front();
+ }
+
+ emit_signal(SNAME("frame_post_draw"));
+}
+
double RenderingServerDefault::get_frame_setup_time_cpu() const {
return frame_setup_time;
}
@@ -203,7 +210,25 @@ bool RenderingServerDefault::has_changed() const {
}
void RenderingServerDefault::_init() {
+ RSG::threaded = create_thread;
+
+ RSG::canvas = memnew(RendererCanvasCull);
+ RSG::viewport = memnew(RendererViewport);
+ RendererSceneCull *sr = memnew(RendererSceneCull);
+ RSG::camera_attributes = memnew(RendererCameraAttributes);
+ RSG::scene = sr;
+ RSG::rasterizer = RendererCompositor::create();
+ RSG::utilities = RSG::rasterizer->get_utilities();
RSG::rasterizer->initialize();
+ RSG::light_storage = RSG::rasterizer->get_light_storage();
+ RSG::material_storage = RSG::rasterizer->get_material_storage();
+ RSG::mesh_storage = RSG::rasterizer->get_mesh_storage();
+ RSG::particles_storage = RSG::rasterizer->get_particles_storage();
+ RSG::texture_storage = RSG::rasterizer->get_texture_storage();
+ RSG::gi = RSG::rasterizer->get_gi();
+ RSG::fog = RSG::rasterizer->get_fog();
+ RSG::canvas_render = RSG::rasterizer->get_canvas();
+ sr->set_scene_render(RSG::rasterizer->get_scene());
}
void RenderingServerDefault::_finish() {
@@ -212,26 +237,38 @@ void RenderingServerDefault::_finish() {
}
RSG::canvas->finalize();
+ memdelete(RSG::canvas);
RSG::rasterizer->finalize();
+ memdelete(RSG::viewport);
+ memdelete(RSG::rasterizer);
+ memdelete(RSG::scene);
+ memdelete(RSG::camera_attributes);
}
void RenderingServerDefault::init() {
if (create_thread) {
print_verbose("RenderingServerWrapMT: Starting render thread");
DisplayServer::get_singleton()->release_rendering_thread();
- server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &RenderingServerDefault::_thread_loop), true);
+ WorkerThreadPool::TaskID tid = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &RenderingServerDefault::_thread_loop), true);
+ command_queue.set_pump_task_id(tid);
+ command_queue.push(this, &RenderingServerDefault::_assign_mt_ids, tid);
+ command_queue.push_and_sync(this, &RenderingServerDefault::_init);
+ DEV_ASSERT(server_task_id == tid);
} else {
+ server_thread = Thread::MAIN_ID;
_init();
}
}
void RenderingServerDefault::finish() {
if (create_thread) {
+ command_queue.push(this, &RenderingServerDefault::_finish);
command_queue.push(this, &RenderingServerDefault::_thread_exit);
if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) {
WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id);
server_task_id = WorkerThreadPool::INVALID_TASK_ID;
}
+ server_thread = Thread::MAIN_ID;
} else {
_finish();
}
@@ -268,17 +305,12 @@ Vector<RenderingServer::FrameProfileArea> RenderingServerDefault::get_frame_prof
/* TESTING */
-void RenderingServerDefault::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {
- redraw_request();
- RSG::rasterizer->set_boot_image(p_image, p_color, p_scale, p_use_filter);
-}
-
Color RenderingServerDefault::get_default_clear_color() {
return RSG::texture_storage->get_default_clear_color();
}
void RenderingServerDefault::set_default_clear_color(const Color &p_color) {
- RSG::viewport->set_default_clear_color(p_color);
+ RSG::texture_storage->set_default_clear_color(p_color);
}
#ifndef DISABLE_DEPRECATED
@@ -327,29 +359,23 @@ Size2i RenderingServerDefault::get_maximum_viewport_size() const {
}
}
-void RenderingServerDefault::_thread_exit() {
- exit = true;
+void RenderingServerDefault::_assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id) {
+ server_thread = Thread::get_caller_id();
+ server_task_id = p_pump_task_id;
}
-void RenderingServerDefault::_thread_draw(bool p_swap_buffers, double frame_step) {
- _draw(p_swap_buffers, frame_step);
+void RenderingServerDefault::_thread_exit() {
+ exit = true;
}
void RenderingServerDefault::_thread_loop() {
- server_thread = Thread::get_caller_id();
-
DisplayServer::get_singleton()->gl_window_make_current(DisplayServer::MAIN_WINDOW_ID); // Move GL to this thread.
- _init();
- command_queue.set_pump_task_id(server_task_id);
while (!exit) {
WorkerThreadPool::get_singleton()->yield();
command_queue.flush_all();
}
- command_queue.flush_all();
-
- _finish();
DisplayServer::get_singleton()->release_rendering_thread();
}
@@ -366,7 +392,9 @@ void RenderingServerDefault::set_physics_interpolation_enabled(bool p_enabled) {
/* EVENT QUEUING */
void RenderingServerDefault::sync() {
- if (!create_thread) {
+ if (create_thread) {
+ command_queue.sync();
+ } else {
command_queue.flush_all(); // Flush all pending from other threads.
}
}
@@ -375,8 +403,9 @@ void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) {
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Manually triggering the draw function from the RenderingServer can only be done on the main thread. Call this function from the main thread or use call_deferred().");
// Needs to be done before changes is reset to 0, to not force the editor to redraw.
RS::get_singleton()->emit_signal(SNAME("frame_pre_draw"));
+ changes = 0;
if (create_thread) {
- command_queue.push(this, &RenderingServerDefault::_thread_draw, p_swap_buffers, frame_step);
+ command_queue.push(this, &RenderingServerDefault::_draw, p_swap_buffers, frame_step);
} else {
_draw(p_swap_buffers, frame_step);
}
@@ -390,36 +419,7 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) {
RenderingServer::init();
create_thread = p_create_thread;
- if (!create_thread) {
- server_thread = Thread::MAIN_ID;
- }
-
- RSG::threaded = create_thread;
-
- RSG::canvas = memnew(RendererCanvasCull);
- RSG::viewport = memnew(RendererViewport);
- RendererSceneCull *sr = memnew(RendererSceneCull);
- RSG::camera_attributes = memnew(RendererCameraAttributes);
- RSG::scene = sr;
- RSG::rasterizer = RendererCompositor::create();
- RSG::utilities = RSG::rasterizer->get_utilities();
- RSG::light_storage = RSG::rasterizer->get_light_storage();
- RSG::material_storage = RSG::rasterizer->get_material_storage();
- RSG::mesh_storage = RSG::rasterizer->get_mesh_storage();
- RSG::particles_storage = RSG::rasterizer->get_particles_storage();
- RSG::texture_storage = RSG::rasterizer->get_texture_storage();
- RSG::gi = RSG::rasterizer->get_gi();
- RSG::fog = RSG::rasterizer->get_fog();
- RSG::canvas_render = RSG::rasterizer->get_canvas();
- sr->set_scene_render(RSG::rasterizer->get_scene());
-
- frame_profile_frame = 0;
}
RenderingServerDefault::~RenderingServerDefault() {
- memdelete(RSG::canvas);
- memdelete(RSG::viewport);
- memdelete(RSG::rasterizer);
- memdelete(RSG::scene);
- memdelete(RSG::camera_attributes);
}
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index bb2f3d94ce..d0b6bc492d 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -63,7 +63,7 @@ class RenderingServerDefault : public RenderingServer {
static void _changes_changed() {}
- uint64_t frame_profile_frame;
+ uint64_t frame_profile_frame = 0;
Vector<FrameProfileArea> frame_profile;
double frame_setup_time = 0;
@@ -76,18 +76,17 @@ class RenderingServerDefault : public RenderingServer {
mutable CommandQueueMT command_queue;
- void _thread_loop();
-
- Thread::ID server_thread = Thread::UNASSIGNED_ID;
+ Thread::ID server_thread = Thread::MAIN_ID;
WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID;
bool exit = false;
bool create_thread = false;
- void _thread_draw(bool p_swap_buffers, double frame_step);
-
+ void _assign_mt_ids(WorkerThreadPool::TaskID p_pump_task_id);
void _thread_exit();
+ void _thread_loop();
void _draw(bool p_swap_buffers, double frame_step);
+ void _run_post_draw_steps();
void _init();
void _finish();
@@ -998,9 +997,22 @@ public:
FUNC1(global_shader_parameters_load_settings, bool)
FUNC0(global_shader_parameters_clear)
+ /* COMPOSITOR */
+
#undef server_name
#undef ServerName
+#define ServerName RendererCompositor
+#define server_name RSG::rasterizer
+
+ FUNC4S(set_boot_image, const Ref<Image> &, const Color &, bool, bool)
+
/* STATUS INFORMATION */
+
+#undef server_name
+#undef ServerName
+
+ /* UTILITIES */
+
#define ServerName RendererUtilities
#define server_name RSG::utilities
FUNC0RC(String, get_video_adapter_name)
@@ -1056,7 +1068,7 @@ public:
virtual void call_on_render_thread(const Callable &p_callable) override {
if (Thread::get_caller_id() == server_thread) {
command_queue.flush_if_pending();
- _call_on_render_thread(p_callable);
+ p_callable.call();
} else {
command_queue.push(this, &RenderingServerDefault::_call_on_render_thread, p_callable);
}
@@ -1066,7 +1078,6 @@ public:
virtual double get_frame_setup_time_cpu() const override;
- virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) override;
virtual Color get_default_clear_color() override;
virtual void set_default_clear_color(const Color &p_color) override;
diff --git a/tests/core/math/test_math_funcs.h b/tests/core/math/test_math_funcs.h
index 0a9d9c97d9..68540e4d61 100644
--- a/tests/core/math/test_math_funcs.h
+++ b/tests/core/math/test_math_funcs.h
@@ -381,6 +381,9 @@ TEST_CASE_TEMPLATE("[Math] remap", T, float, double) {
CHECK(Math::remap((T)-100.0, (T)-100.0, (T)-200.0, (T)0.0, (T)-1000.0) == doctest::Approx((T)0.0));
CHECK(Math::remap((T)-200.0, (T)-100.0, (T)-200.0, (T)0.0, (T)-1000.0) == doctest::Approx((T)-1000.0));
CHECK(Math::remap((T)-250.0, (T)-100.0, (T)-200.0, (T)0.0, (T)-1000.0) == doctest::Approx((T)-1500.0));
+
+ // Note: undefined behavior can happen when `p_istart == p_istop`. We don't bother testing this as it will
+ // vary between hardware and compilers properly implementing IEEE 754.
}
TEST_CASE_TEMPLATE("[Math] angle_difference", T, float, double) {
diff --git a/tests/core/object/test_class_db.h b/tests/core/object/test_class_db.h
index fb62d0f056..381d759e5b 100644
--- a/tests/core/object/test_class_db.h
+++ b/tests/core/object/test_class_db.h
@@ -195,12 +195,12 @@ struct Context {
}
bool has_type(const TypeReference &p_type_ref) const {
- if (builtin_types.find(p_type_ref.name) >= 0) {
+ if (builtin_types.has(p_type_ref.name)) {
return true;
}
if (p_type_ref.is_enum) {
- if (enum_types.find(p_type_ref.name) >= 0) {
+ if (enum_types.has(p_type_ref.name)) {
return true;
}
@@ -355,7 +355,7 @@ void validate_property(const Context &p_context, const ExposedClass &p_class, co
const ArgumentData &idx_arg = getter->arguments.front()->get();
if (idx_arg.type.name != p_context.names_cache.int_type) {
// If not an int, it can be an enum
- TEST_COND(p_context.enum_types.find(idx_arg.type.name) < 0,
+ TEST_COND(!p_context.enum_types.has(idx_arg.type.name),
"Invalid type '", idx_arg.type.name, "' for index argument of property getter: '", p_class.name, ".", String(p_prop.name), "'.");
}
}
@@ -367,7 +367,7 @@ void validate_property(const Context &p_context, const ExposedClass &p_class, co
if (idx_arg.type.name != p_context.names_cache.int_type) {
// Assume the index parameter is an enum
// If not an int, it can be an enum
- TEST_COND(p_context.enum_types.find(idx_arg.type.name) < 0,
+ TEST_COND(!p_context.enum_types.has(idx_arg.type.name),
"Invalid type '", idx_arg.type.name, "' for index argument of property setter: '", p_class.name, ".", String(p_prop.name), "'.");
}
}
@@ -736,7 +736,7 @@ void add_exposed_classes(Context &r_context) {
for (const StringName &E : K.value.constants) {
const StringName &constant_name = E;
- TEST_FAIL_COND(String(constant_name).find("::") != -1,
+ TEST_FAIL_COND(String(constant_name).contains("::"),
"Enum constant contains '::', check bindings to remove the scope: '",
String(class_name), ".", String(enum_.name), ".", String(constant_name), "'.");
int64_t *value = class_info->constant_map.getptr(constant_name);
@@ -758,7 +758,7 @@ void add_exposed_classes(Context &r_context) {
for (const String &E : constants) {
const String &constant_name = E;
- TEST_FAIL_COND(constant_name.find("::") != -1,
+ TEST_FAIL_COND(constant_name.contains("::"),
"Constant contains '::', check bindings to remove the scope: '",
String(class_name), ".", constant_name, "'.");
int64_t *value = class_info->constant_map.getptr(StringName(E));
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index 64f03e5879..cf57183a02 100644
--- a/tests/core/string/test_string.h
+++ b/tests/core/string/test_string.h
@@ -297,6 +297,19 @@ TEST_CASE("[String] Contains") {
CHECK(!s.contains(String("\\char_test.tscn")));
}
+TEST_CASE("[String] Contains case insensitive") {
+ String s = "C:\\Godot\\project\\string_test.tscn";
+ CHECK(s.containsn("Godot"));
+ CHECK(s.containsn("godot"));
+ CHECK(s.containsn(String("Project\\string_test")));
+ CHECK(s.containsn(String("\\string_Test.tscn")));
+
+ CHECK(!s.containsn("Godoh"));
+ CHECK(!s.containsn("godoh"));
+ CHECK(!s.containsn(String("project\\string test")));
+ CHECK(!s.containsn(String("\\char_test.tscn")));
+}
+
TEST_CASE("[String] Test chr") {
CHECK(String::chr('H') == "H");
CHECK(String::chr(0x3012)[0] == 0x3012);
@@ -360,18 +373,37 @@ TEST_CASE("[String] Substr") {
TEST_CASE("[String] Find") {
String s = "Pretty Woman Woman";
- CHECK(s.find("tty") == 3);
- CHECK(s.find("Wo", 9) == 13);
- CHECK(s.find("Revenge of the Monster Truck") == -1);
- CHECK(s.rfind("man") == 15);
-}
-
-TEST_CASE("[String] Find no case") {
+ MULTICHECK_STRING_EQ(s, find, "tty", 3);
+ MULTICHECK_STRING_EQ(s, find, "Revenge of the Monster Truck", -1);
+ MULTICHECK_STRING_INT_EQ(s, find, "Wo", 9, 13);
+ MULTICHECK_STRING_EQ(s, find, "", -1);
+ MULTICHECK_STRING_EQ(s, find, "Pretty Woman Woman", 0);
+ MULTICHECK_STRING_EQ(s, find, "WOMAN", -1);
+ MULTICHECK_STRING_INT_EQ(s, find, "", 9, -1);
+
+ MULTICHECK_STRING_EQ(s, rfind, "", -1);
+ MULTICHECK_STRING_EQ(s, rfind, "foo", -1);
+ MULTICHECK_STRING_EQ(s, rfind, "Pretty Woman Woman", 0);
+ MULTICHECK_STRING_EQ(s, rfind, "man", 15);
+ MULTICHECK_STRING_EQ(s, rfind, "WOMAN", -1);
+ MULTICHECK_STRING_INT_EQ(s, rfind, "", 15, -1);
+}
+
+TEST_CASE("[String] Find case insensitive") {
String s = "Pretty Whale Whale";
- CHECK(s.findn("WHA") == 7);
- CHECK(s.findn("WHA", 9) == 13);
- CHECK(s.findn("Revenge of the Monster SawFish") == -1);
- CHECK(s.rfindn("WHA") == 13);
+ MULTICHECK_STRING_EQ(s, findn, "WHA", 7);
+ MULTICHECK_STRING_INT_EQ(s, findn, "WHA", 9, 13);
+ MULTICHECK_STRING_EQ(s, findn, "Revenge of the Monster SawFish", -1);
+ MULTICHECK_STRING_EQ(s, findn, "", -1);
+ MULTICHECK_STRING_EQ(s, findn, "wha", 7);
+ MULTICHECK_STRING_EQ(s, findn, "Wha", 7);
+ MULTICHECK_STRING_INT_EQ(s, findn, "", 3, -1);
+
+ MULTICHECK_STRING_EQ(s, rfindn, "WHA", 13);
+ MULTICHECK_STRING_EQ(s, rfindn, "", -1);
+ MULTICHECK_STRING_EQ(s, rfindn, "wha", 13);
+ MULTICHECK_STRING_EQ(s, rfindn, "Wha", 13);
+ MULTICHECK_STRING_INT_EQ(s, rfindn, "", 13, -1);
}
TEST_CASE("[String] Find MK") {
@@ -392,11 +424,9 @@ TEST_CASE("[String] Find MK") {
TEST_CASE("[String] Find and replace") {
String s = "Happy Birthday, Anna!";
- s = s.replace("Birthday", "Halloween");
- CHECK(s == "Happy Halloween, Anna!");
-
- s = s.replace_first("H", "W");
- CHECK(s == "Wappy Halloween, Anna!");
+ MULTICHECK_STRING_STRING_EQ(s, replace, "Birthday", "Halloween", "Happy Halloween, Anna!");
+ MULTICHECK_STRING_STRING_EQ(s, replace_first, "y", "Y", "HappY Birthday, Anna!");
+ MULTICHECK_STRING_STRING_EQ(s, replacen, "Y", "Y", "HappY BirthdaY, Anna!");
}
TEST_CASE("[String] Insertion") {
@@ -557,51 +587,76 @@ TEST_CASE("[String] String to float") {
TEST_CASE("[String] Slicing") {
String s = "Mars,Jupiter,Saturn,Uranus";
-
const char *slices[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
- for (int i = 0; i < s.get_slice_count(","); i++) {
- CHECK(s.get_slice(",", i) == slices[i]);
- }
+ MULTICHECK_GET_SLICE(s, ",", slices);
+}
+
+TEST_CASE("[String] Begins with") {
+ // Test cases for true:
+ MULTICHECK_STRING_EQ(String("res://foobar"), begins_with, "res://", true);
+ MULTICHECK_STRING_EQ(String("abc"), begins_with, "abc", true);
+ MULTICHECK_STRING_EQ(String("abc"), begins_with, "", true);
+ MULTICHECK_STRING_EQ(String(""), begins_with, "", true);
+
+ // Test cases for false:
+ MULTICHECK_STRING_EQ(String("res"), begins_with, "res://", false);
+ MULTICHECK_STRING_EQ(String("abcdef"), begins_with, "foo", false);
+ MULTICHECK_STRING_EQ(String("abc"), begins_with, "ax", false);
+ MULTICHECK_STRING_EQ(String(""), begins_with, "abc", false);
+
+ // Test "const char *" version also with nullptr.
+ String s("foo");
+ bool state = s.begins_with(nullptr) == false;
+ CHECK_MESSAGE(state, "nullptr check failed");
+
+ String empty("");
+ state = empty.begins_with(nullptr) == false;
+ CHECK_MESSAGE(state, "nullptr check with empty string failed");
+}
+
+TEST_CASE("[String] Ends with") {
+ // Test cases for true:
+ MULTICHECK_STRING_EQ(String("res://foobar"), ends_with, "foobar", true);
+ MULTICHECK_STRING_EQ(String("abc"), ends_with, "abc", true);
+ MULTICHECK_STRING_EQ(String("abc"), ends_with, "", true);
+ MULTICHECK_STRING_EQ(String(""), ends_with, "", true);
+
+ // Test cases for false:
+ MULTICHECK_STRING_EQ(String("res"), ends_with, "res://", false);
+ MULTICHECK_STRING_EQ(String("abcdef"), ends_with, "foo", false);
+ MULTICHECK_STRING_EQ(String("abc"), ends_with, "ax", false);
+ MULTICHECK_STRING_EQ(String(""), ends_with, "abc", false);
+
+ // Test "const char *" version also with nullptr.
+ String s("foo");
+ bool state = s.ends_with(nullptr) == false;
+ CHECK_MESSAGE(state, "nullptr check failed");
+
+ String empty("");
+ state = empty.ends_with(nullptr) == false;
+ CHECK_MESSAGE(state, "nullptr check with empty string failed");
}
TEST_CASE("[String] Splitting") {
String s = "Mars,Jupiter,Saturn,Uranus";
- Vector<String> l;
-
const char *slices_l[3] = { "Mars", "Jupiter", "Saturn,Uranus" };
- const char *slices_r[3] = { "Mars,Jupiter", "Saturn", "Uranus" };
- const char *slices_3[4] = { "t", "e", "s", "t" };
+ MULTICHECK_SPLIT(s, split, ",", true, 2, slices_l, 3);
- l = s.split(",", true, 2);
- CHECK(l.size() == 3);
- for (int i = 0; i < l.size(); i++) {
- CHECK(l[i] == slices_l[i]);
- }
-
- l = s.rsplit(",", true, 2);
- CHECK(l.size() == 3);
- for (int i = 0; i < l.size(); i++) {
- CHECK(l[i] == slices_r[i]);
- }
+ const char *slices_r[3] = { "Mars,Jupiter", "Saturn", "Uranus" };
+ MULTICHECK_SPLIT(s, rsplit, ",", true, 2, slices_r, 3);
s = "test";
- l = s.split();
- CHECK(l.size() == 4);
- for (int i = 0; i < l.size(); i++) {
- CHECK(l[i] == slices_3[i]);
- }
+ const char *slices_3[4] = { "t", "e", "s", "t" };
+ MULTICHECK_SPLIT(s, split, "", true, 0, slices_3, 4);
s = "";
- l = s.split();
- CHECK(l.size() == 1);
- CHECK(l[0] == "");
-
- l = s.split("", false);
- CHECK(l.size() == 0);
+ const char *slices_4[1] = { "" };
+ MULTICHECK_SPLIT(s, split, "", true, 0, slices_4, 1);
+ MULTICHECK_SPLIT(s, split, "", false, 0, slices_4, 0);
s = "Mars Jupiter Saturn Uranus";
const char *slices_s[4] = { "Mars", "Jupiter", "Saturn", "Uranus" };
- l = s.split_spaces();
+ Vector<String> l = s.split_spaces();
for (int i = 0; i < l.size(); i++) {
CHECK(l[i] == slices_s[i]);
}
@@ -644,69 +699,6 @@ TEST_CASE("[String] Splitting") {
}
}
-struct test_27_data {
- char const *data;
- char const *part;
- bool expected;
-};
-
-TEST_CASE("[String] Begins with") {
- test_27_data tc[] = {
- // Test cases for true:
- { "res://foobar", "res://", true },
- { "abc", "abc", true },
- { "abc", "", true },
- { "", "", true },
- // Test cases for false:
- { "res", "res://", false },
- { "abcdef", "foo", false },
- { "abc", "ax", false },
- { "", "abc", false }
- };
- size_t count = sizeof(tc) / sizeof(tc[0]);
- bool state = true;
- for (size_t i = 0; i < count; ++i) {
- String s = tc[i].data;
- state = s.begins_with(tc[i].part) == tc[i].expected;
- CHECK_MESSAGE(state, "first check failed at: ", i);
-
- String sb = tc[i].part;
- state = s.begins_with(sb) == tc[i].expected;
- CHECK_MESSAGE(state, "second check failed at: ", i);
- }
-
- // Test "const char *" version also with nullptr.
- String s("foo");
- state = s.begins_with(nullptr) == false;
- CHECK_MESSAGE(state, "nullptr check failed");
-
- String empty("");
- state = empty.begins_with(nullptr) == false;
- CHECK_MESSAGE(state, "nullptr check with empty string failed");
-}
-
-TEST_CASE("[String] Ends with") {
- test_27_data tc[] = {
- // test cases for true:
- { "res://foobar", "foobar", true },
- { "abc", "abc", true },
- { "abc", "", true },
- { "", "", true },
- // test cases for false:
- { "res", "res://", false },
- { "", "abc", false },
- { "abcdef", "foo", false },
- { "abc", "xc", false }
- };
- size_t count = sizeof(tc) / sizeof(tc[0]);
- for (size_t i = 0; i < count; ++i) {
- String s = tc[i].data;
- String sb = tc[i].part;
- bool state = s.ends_with(sb) == tc[i].expected;
- CHECK_MESSAGE(state, "check failed at: ", i);
- }
-}
-
TEST_CASE("[String] format") {
const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\"";
@@ -1498,39 +1490,62 @@ TEST_CASE("[String] Cyrillic to_lower()") {
}
TEST_CASE("[String] Count and countn functionality") {
-#define COUNT_TEST(x) \
- { \
- bool success = x; \
- state = state && success; \
- }
+ String s = String("");
+ MULTICHECK_STRING_EQ(s, count, "Test", 0);
- bool state = true;
+ s = "Test";
+ MULTICHECK_STRING_EQ(s, count, "", 0);
- COUNT_TEST(String("").count("Test") == 0);
- COUNT_TEST(String("Test").count("") == 0);
- COUNT_TEST(String("Test").count("test") == 0);
- COUNT_TEST(String("Test").count("TEST") == 0);
- COUNT_TEST(String("TEST").count("TEST") == 1);
- COUNT_TEST(String("Test").count("Test") == 1);
- COUNT_TEST(String("aTest").count("Test") == 1);
- COUNT_TEST(String("Testa").count("Test") == 1);
- COUNT_TEST(String("TestTestTest").count("Test") == 3);
- COUNT_TEST(String("TestTestTest").count("TestTest") == 1);
- COUNT_TEST(String("TestGodotTestGodotTestGodot").count("Test") == 3);
-
- COUNT_TEST(String("TestTestTestTest").count("Test", 4, 8) == 1);
- COUNT_TEST(String("TestTestTestTest").count("Test", 4, 12) == 2);
- COUNT_TEST(String("TestTestTestTest").count("Test", 4, 16) == 3);
- COUNT_TEST(String("TestTestTestTest").count("Test", 4) == 3);
-
- COUNT_TEST(String("Test").countn("test") == 1);
- COUNT_TEST(String("Test").countn("TEST") == 1);
- COUNT_TEST(String("testTest-Testatest").countn("tEst") == 4);
- COUNT_TEST(String("testTest-TeStatest").countn("tEsT", 4, 16) == 2);
+ s = "Test";
+ MULTICHECK_STRING_EQ(s, count, "test", 0);
- CHECK(state);
+ s = "Test";
+ MULTICHECK_STRING_EQ(s, count, "TEST", 0);
+
+ s = "TEST";
+ MULTICHECK_STRING_EQ(s, count, "TEST", 1);
+
+ s = "Test";
+ MULTICHECK_STRING_EQ(s, count, "Test", 1);
+
+ s = "aTest";
+ MULTICHECK_STRING_EQ(s, count, "Test", 1);
+
+ s = "Testa";
+ MULTICHECK_STRING_EQ(s, count, "Test", 1);
+
+ s = "TestTestTest";
+ MULTICHECK_STRING_EQ(s, count, "Test", 3);
+
+ s = "TestTestTest";
+ MULTICHECK_STRING_EQ(s, count, "TestTest", 1);
+
+ s = "TestGodotTestGodotTestGodot";
+ MULTICHECK_STRING_EQ(s, count, "Test", 3);
+
+ s = "TestTestTestTest";
+ MULTICHECK_STRING_INT_INT_EQ(s, count, "Test", 4, 8, 1);
+
+ s = "TestTestTestTest";
+ MULTICHECK_STRING_INT_INT_EQ(s, count, "Test", 4, 12, 2);
+
+ s = "TestTestTestTest";
+ MULTICHECK_STRING_INT_INT_EQ(s, count, "Test", 4, 16, 3);
+
+ s = "TestTestTestTest";
+ MULTICHECK_STRING_INT_EQ(s, count, "Test", 4, 3);
+
+ s = "Test";
+ MULTICHECK_STRING_EQ(s, countn, "test", 1);
+
+ s = "Test";
+ MULTICHECK_STRING_EQ(s, countn, "TEST", 1);
+
+ s = "testTest-Testatest";
+ MULTICHECK_STRING_EQ(s, countn, "tEst", 4);
-#undef COUNT_TEST
+ s = "testTest-TeStatest";
+ MULTICHECK_STRING_INT_INT_EQ(s, countn, "tEsT", 4, 16, 2);
}
TEST_CASE("[String] Bigrams") {
@@ -1703,9 +1718,19 @@ TEST_CASE("[String] Strip edges") {
TEST_CASE("[String] Trim") {
String s = "aaaTestbbb";
- CHECK(s.trim_prefix("aaa") == "Testbbb");
- CHECK(s.trim_suffix("bbb") == "aaaTest");
- CHECK(s.trim_suffix("Test") == s);
+ MULTICHECK_STRING_EQ(s, trim_prefix, "aaa", "Testbbb");
+ MULTICHECK_STRING_EQ(s, trim_prefix, "Test", s);
+ MULTICHECK_STRING_EQ(s, trim_prefix, "", s);
+ MULTICHECK_STRING_EQ(s, trim_prefix, "aaaTestbbb", "");
+ MULTICHECK_STRING_EQ(s, trim_prefix, "bbb", s);
+ MULTICHECK_STRING_EQ(s, trim_prefix, "AAA", s);
+
+ MULTICHECK_STRING_EQ(s, trim_suffix, "bbb", "aaaTest");
+ MULTICHECK_STRING_EQ(s, trim_suffix, "Test", s);
+ MULTICHECK_STRING_EQ(s, trim_suffix, "", s);
+ MULTICHECK_STRING_EQ(s, trim_suffix, "aaaTestbbb", "");
+ MULTICHECK_STRING_EQ(s, trim_suffix, "aaa", s);
+ MULTICHECK_STRING_EQ(s, trim_suffix, "BBB", s);
}
TEST_CASE("[String] Right/Left") {
diff --git a/tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl b/tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl
index 58ddd08cdd..8ad5a23eb5 100644
--- a/tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl
+++ b/tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl
@@ -48,4 +48,3 @@ protected:
};
#endif
-
diff --git a/tests/test_macros.h b/tests/test_macros.h
index 25e48c1e05..10f4c59a90 100644
--- a/tests/test_macros.h
+++ b/tests/test_macros.h
@@ -406,4 +406,71 @@ public:
#define SIGNAL_CHECK_FALSE(m_signal) CHECK(SignalWatcher::get_singleton()->check_false(m_signal));
#define SIGNAL_DISCARD(m_signal) SignalWatcher::get_singleton()->discard_signal(m_signal);
+#define MULTICHECK_STRING_EQ(m_obj, m_func, m_param1, m_eq) \
+ CHECK(m_obj.m_func(m_param1) == m_eq); \
+ CHECK(m_obj.m_func(U##m_param1) == m_eq); \
+ CHECK(m_obj.m_func(L##m_param1) == m_eq); \
+ CHECK(m_obj.m_func(String(m_param1)) == m_eq);
+
+#define MULTICHECK_STRING_INT_EQ(m_obj, m_func, m_param1, m_param2, m_eq) \
+ CHECK(m_obj.m_func(m_param1, m_param2) == m_eq); \
+ CHECK(m_obj.m_func(U##m_param1, m_param2) == m_eq); \
+ CHECK(m_obj.m_func(L##m_param1, m_param2) == m_eq); \
+ CHECK(m_obj.m_func(String(m_param1), m_param2) == m_eq);
+
+#define MULTICHECK_STRING_INT_INT_EQ(m_obj, m_func, m_param1, m_param2, m_param3, m_eq) \
+ CHECK(m_obj.m_func(m_param1, m_param2, m_param3) == m_eq); \
+ CHECK(m_obj.m_func(U##m_param1, m_param2, m_param3) == m_eq); \
+ CHECK(m_obj.m_func(L##m_param1, m_param2, m_param3) == m_eq); \
+ CHECK(m_obj.m_func(String(m_param1), m_param2, m_param3) == m_eq);
+
+#define MULTICHECK_STRING_STRING_EQ(m_obj, m_func, m_param1, m_param2, m_eq) \
+ CHECK(m_obj.m_func(m_param1, m_param2) == m_eq); \
+ CHECK(m_obj.m_func(U##m_param1, U##m_param2) == m_eq); \
+ CHECK(m_obj.m_func(L##m_param1, L##m_param2) == m_eq); \
+ CHECK(m_obj.m_func(String(m_param1), String(m_param2)) == m_eq);
+
+#define MULTICHECK_GET_SLICE(m_obj, m_param1, m_slices) \
+ for (int i = 0; i < m_obj.get_slice_count(m_param1); ++i) { \
+ CHECK(m_obj.get_slice(m_param1, i) == m_slices[i]); \
+ } \
+ for (int i = 0; i < m_obj.get_slice_count(U##m_param1); ++i) { \
+ CHECK(m_obj.get_slice(U##m_param1, i) == m_slices[i]); \
+ } \
+ for (int i = 0; i < m_obj.get_slice_count(L##m_param1); ++i) { \
+ CHECK(m_obj.get_slice(L##m_param1, i) == m_slices[i]); \
+ } \
+ for (int i = 0; i < m_obj.get_slice_count(String(m_param1)); ++i) { \
+ CHECK(m_obj.get_slice(String(m_param1), i) == m_slices[i]); \
+ }
+
+#define MULTICHECK_SPLIT(m_obj, m_func, m_param1, m_param2, m_param3, m_slices, m_expected_size) \
+ do { \
+ Vector<String> string_list; \
+ \
+ string_list = m_obj.m_func(m_param1, m_param2, m_param3); \
+ CHECK(m_expected_size == string_list.size()); \
+ for (int i = 0; i < string_list.size(); ++i) { \
+ CHECK(string_list[i] == m_slices[i]); \
+ } \
+ \
+ string_list = m_obj.m_func(U##m_param1, m_param2, m_param3); \
+ CHECK(m_expected_size == string_list.size()); \
+ for (int i = 0; i < string_list.size(); ++i) { \
+ CHECK(string_list[i] == m_slices[i]); \
+ } \
+ \
+ string_list = m_obj.m_func(L##m_param1, m_param2, m_param3); \
+ CHECK(m_expected_size == string_list.size()); \
+ for (int i = 0; i < string_list.size(); ++i) { \
+ CHECK(string_list[i] == m_slices[i]); \
+ } \
+ \
+ string_list = m_obj.m_func(String(m_param1), m_param2, m_param3); \
+ CHECK(m_expected_size == string_list.size()); \
+ for (int i = 0; i < string_list.size(); ++i) { \
+ CHECK(string_list[i] == m_slices[i]); \
+ } \
+ } while (0)
+
#endif // TEST_MACROS_H
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 69d8113e64..41fc21b469 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -242,7 +242,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
String name = String(p_in.m_name);
String suite_name = String(p_in.m_test_suite);
- if (name.find("[SceneTree]") != -1 || name.find("[Editor]") != -1) {
+ if (name.contains("[SceneTree]") || name.contains("[Editor]")) {
memnew(MessageQueue);
memnew(Input);
@@ -291,7 +291,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
}
#ifdef TOOLS_ENABLED
- if (name.find("[Editor]") != -1) {
+ if (name.contains("[Editor]")) {
Engine::get_singleton()->set_editor_hint(true);
EditorPaths::create();
EditorSettings::create();
@@ -301,7 +301,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
return;
}
- if (name.find("Audio") != -1) {
+ if (name.contains("Audio")) {
// The last driver index should always be the dummy driver.
int dummy_idx = AudioDriverManager::get_driver_count() - 1;
AudioDriverManager::initialize(dummy_idx);
@@ -311,7 +311,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
}
#ifndef _3D_DISABLED
- if (suite_name.find("[Navigation]") != -1 && navigation_server_2d == nullptr && navigation_server_3d == nullptr) {
+ if (suite_name.contains("[Navigation]") && navigation_server_2d == nullptr && navigation_server_3d == nullptr) {
ERR_PRINT_OFF;
navigation_server_3d = NavigationServer3DManager::new_default_server();
navigation_server_2d = NavigationServer2DManager::new_default_server();