Forráskód Böngészése

Rename String `plus_file` to `path_join`

Aaron Franke 2 éve
szülő
commit
10a56981dc
100 módosított fájl, 519 hozzáadás és 519 törlés
  1. 14 14
      core/config/project_settings.cpp
  2. 2 2
      core/extension/native_extension.cpp
  3. 7 7
      core/io/dir_access.cpp
  4. 1 1
      core/io/file_access_pack.cpp
  5. 3 3
      core/io/resource_format_binary.cpp
  6. 1 1
      core/io/resource_importer.cpp
  7. 1 1
      core/io/resource_uid.cpp
  8. 1 1
      core/string/ustring.cpp
  9. 1 1
      core/string/ustring.h
  10. 1 1
      core/variant/variant_call.cpp
  11. 1 1
      doc/classes/ProjectSettings.xml
  12. 2 2
      doc/classes/String.xml
  13. 2 2
      drivers/gles3/shader_gles3.cpp
  14. 14 14
      drivers/unix/dir_access_unix.cpp
  15. 5 5
      drivers/unix/os_unix.cpp
  16. 6 6
      drivers/windows/dir_access_windows.cpp
  17. 4 4
      editor/create_dialog.cpp
  18. 2 2
      editor/doc_tools.cpp
  19. 1 1
      editor/editor_autoload_settings.cpp
  20. 1 1
      editor/editor_dir_dialog.cpp
  21. 8 8
      editor/editor_feature_profile.cpp
  22. 13 13
      editor/editor_file_dialog.cpp
  23. 15 15
      editor/editor_file_system.cpp
  24. 5 5
      editor/editor_folding.cpp
  25. 2 2
      editor/editor_help.cpp
  26. 3 3
      editor/editor_log.cpp
  27. 12 12
      editor/editor_node.cpp
  28. 14 14
      editor/editor_paths.cpp
  29. 2 2
      editor/editor_plugin_settings.cpp
  30. 1 1
      editor/editor_resource_preview.cpp
  31. 16 16
      editor/editor_settings.cpp
  32. 2 2
      editor/editor_vcs_interface.cpp
  33. 4 4
      editor/export/editor_export_platform.cpp
  34. 2 2
      editor/export/editor_export_platform_pc.cpp
  35. 1 1
      editor/export/editor_export_plugin.cpp
  36. 16 16
      editor/export/export_template_manager.cpp
  37. 14 14
      editor/filesystem_dock.cpp
  38. 2 2
      editor/find_in_files.cpp
  39. 2 2
      editor/import/collada.cpp
  40. 5 5
      editor/import/resource_importer_obj.cpp
  41. 1 1
      editor/import/resource_importer_shader_file.cpp
  42. 3 3
      editor/import/scene_import_settings.cpp
  43. 2 2
      editor/plugin_config_dialog.cpp
  44. 4 4
      editor/plugins/asset_library_editor_plugin.cpp
  45. 1 1
      editor/plugins/editor_preview_plugins.cpp
  46. 5 5
      editor/plugins/script_editor_plugin.cpp
  47. 1 1
      editor/plugins/script_text_editor.cpp
  48. 2 2
      editor/plugins/shader_editor_plugin.cpp
  49. 2 2
      editor/project_converter_3_to_4.cpp
  50. 13 13
      editor/project_manager.cpp
  51. 1 1
      editor/scene_create_dialog.cpp
  52. 10 10
      editor/scene_tree_dock.cpp
  53. 2 2
      editor/script_create_dialog.cpp
  54. 4 4
      main/main.cpp
  55. 3 3
      modules/gdscript/gdscript.cpp
  56. 2 2
      modules/gdscript/gdscript_analyzer.cpp
  57. 2 2
      modules/gdscript/language_server/gdscript_workspace.cpp
  58. 3 3
      modules/gdscript/tests/gdscript_test_runner.cpp
  59. 7 7
      modules/gltf/editor/editor_scene_importer_blend.cpp
  60. 1 1
      modules/gltf/editor/editor_scene_importer_fbx.cpp
  61. 4 4
      modules/gltf/gltf_document.cpp
  62. 2 2
      modules/mono/csharp_script.cpp
  63. 3 3
      modules/mono/editor/bindings_generator.cpp
  64. 2 2
      modules/mono/editor/code_completion.cpp
  65. 1 1
      modules/mono/editor/editor_internal_calls.cpp
  66. 39 39
      modules/mono/godotsharp_dirs.cpp
  67. 10 10
      modules/mono/mono_gd/gd_mono.cpp
  68. 1 1
      modules/mono/utils/path_utils.cpp
  69. 1 1
      platform/android/dir_access_jandroid.cpp
  70. 17 17
      platform/android/export/export_plugin.cpp
  71. 1 1
      platform/android/export/godot_plugin_config.cpp
  72. 1 1
      platform/android/os_android.cpp
  73. 18 18
      platform/ios/export/export_plugin.cpp
  74. 4 4
      platform/ios/export/export_plugin.h
  75. 7 7
      platform/ios/export/godot_plugin_config.cpp
  76. 7 7
      platform/linuxbsd/os_linuxbsd.cpp
  77. 1 1
      platform/macos/dir_access_macos.mm
  78. 41 41
      platform/macos/export/codesign.cpp
  79. 16 16
      platform/macos/export/export_plugin.cpp
  80. 6 6
      platform/macos/os_macos.mm
  81. 2 2
      platform/uwp/export/app_packager.cpp
  82. 1 1
      platform/uwp/export/export_plugin.h
  83. 2 2
      platform/web/api/web_tools_editor_plugin.cpp
  84. 4 4
      platform/web/export/editor_http_server.h
  85. 9 9
      platform/web/export/export_plugin.cpp
  86. 4 4
      platform/windows/os_windows.cpp
  87. 8 8
      scene/gui/file_dialog.cpp
  88. 2 2
      scene/main/scene_tree.cpp
  89. 2 2
      scene/resources/font.cpp
  90. 3 3
      scene/resources/resource_format_text.cpp
  91. 1 1
      servers/movie_writer/movie_writer.cpp
  92. 1 1
      servers/rendering/renderer_rd/renderer_compositor_rd.cpp
  93. 2 2
      servers/rendering/renderer_rd/shader_rd.cpp
  94. 1 1
      tests/core/io/test_config_file.h
  95. 2 2
      tests/core/io/test_image.h
  96. 8 8
      tests/core/io/test_pck_packer.h
  97. 2 2
      tests/core/io/test_resource.h
  98. 1 1
      tests/core/string/test_string.h
  99. 3 3
      tests/scene/test_audio_stream_wav.h
  100. 1 1
      tests/test_utils.cpp

+ 14 - 14
core/config/project_settings.cpp

@@ -72,7 +72,7 @@ String ProjectSettings::get_safe_project_name() const {
 }
 
 String ProjectSettings::get_imported_files_path() const {
-	return get_project_data_path().plus_file("imported");
+	return get_project_data_path().path_join("imported");
 }
 
 // Returns the features that a project must have when opened with this build of Godot.
@@ -157,12 +157,12 @@ String ProjectSettings::localize_path(const String &p_path) const {
 		// in an absolute path that just happens to contain this string but points to a
 		// different folder (e.g. "/my/project" as resource_path would be contained in
 		// "/my/project_data", even though the latter is not part of res://.
-		// `plus_file("")` is an easy way to ensure we have a trailing '/'.
-		const String res_path = resource_path.plus_file("");
+		// `path_join("")` is an easy way to ensure we have a trailing '/'.
+		const String res_path = resource_path.path_join("");
 
 		// DirAccess::get_current_dir() is not guaranteed to return a path that with a trailing '/',
 		// so we must make sure we have it as well in order to compare with 'res_path'.
-		cwd = cwd.plus_file("");
+		cwd = cwd.path_join("");
 
 		if (!cwd.begins_with(res_path)) {
 			return p_path;
@@ -472,7 +472,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
 		if (err == OK && !p_ignore_override) {
 			// Load override from location of the main pack
 			// Optional, we don't mind if it fails
-			_load_settings_text(p_main_pack.get_base_dir().plus_file("override.cfg"));
+			_load_settings_text(p_main_pack.get_base_dir().path_join("override.cfg"));
 		}
 		return err;
 	}
@@ -500,14 +500,14 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
 #ifdef MACOS_ENABLED
 		if (!found) {
 			// Attempt to load PCK from macOS .app bundle resources.
-			found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_filename + ".pck"));
+			found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_filename + ".pck"));
 		}
 #endif
 
 		if (!found) {
 			// Try to load data pack at the location of the executable.
 			// As mentioned above, we have two potential names to attempt.
-			found = _load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) || _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck"));
+			found = _load_resource_pack(exec_dir.path_join(exec_basename + ".pck")) || _load_resource_pack(exec_dir.path_join(exec_filename + ".pck"));
 		}
 
 		if (!found) {
@@ -523,7 +523,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
 				// Load overrides from the PCK and the executable location.
 				// Optional, we don't mind if either fails.
 				_load_settings_text("res://override.cfg");
-				_load_settings_text(exec_path.get_base_dir().plus_file("override.cfg"));
+				_load_settings_text(exec_path.get_base_dir().path_join("override.cfg"));
 			}
 			return err;
 		}
@@ -556,10 +556,10 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
 		// Set the resource path early so things can be resolved when loading.
 		resource_path = current_dir;
 		resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
-		err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
+		err = _load_settings_text_or_binary(current_dir.path_join("project.godot"), current_dir.path_join("project.binary"));
 		if (err == OK && !p_ignore_override) {
 			// Optional, we don't mind if it fails.
-			_load_settings_text(current_dir.plus_file("override.cfg"));
+			_load_settings_text(current_dir.path_join("override.cfg"));
 			found = true;
 			break;
 		}
@@ -685,7 +685,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
 			// If we're loading a project.godot from source code, we can operate some
 			// ProjectSettings conversions if need be.
 			_convert_to_last_version(config_version);
-			last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+			last_save_time = FileAccess::get_modified_time(get_resource_path().path_join("project.godot"));
 			return OK;
 		}
 		ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted.");
@@ -764,9 +764,9 @@ void ProjectSettings::clear(const String &p_name) {
 }
 
 Error ProjectSettings::save() {
-	Error error = save_custom(get_resource_path().plus_file("project.godot"));
+	Error error = save_custom(get_resource_path().path_join("project.godot"));
 	if (error == OK) {
-		last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+		last_save_time = FileAccess::get_modified_time(get_resource_path().path_join("project.godot"));
 	}
 	return error;
 }
@@ -911,7 +911,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
 		}
 	}
 	// Check for the existence of a csproj file.
-	if (FileAccess::exists(get_resource_path().plus_file(get_safe_project_name() + ".csproj"))) {
+	if (FileAccess::exists(get_resource_path().path_join(get_safe_project_name() + ".csproj"))) {
 		// If there is a csproj file, add the C# feature if it doesn't already exist.
 		if (!project_features.has("C#")) {
 			project_features.append("C#");

+ 2 - 2
core/extension/native_extension.cpp

@@ -36,7 +36,7 @@
 #include "core/os/os.h"
 
 String NativeExtension::get_extension_list_config_file() {
-	return ProjectSettings::get_singleton()->get_project_data_path().plus_file("extension_list.cfg");
+	return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg");
 }
 
 class NativeExtensionMethodBind : public MethodBind {
@@ -421,7 +421,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St
 	}
 
 	if (!library_path.is_resource_file() && !library_path.is_absolute_path()) {
-		library_path = p_path.get_base_dir().plus_file(library_path);
+		library_path = p_path.get_base_dir().path_join(library_path);
 	}
 
 	Ref<NativeExtension> lib;

+ 7 - 7
core/io/dir_access.cpp

@@ -106,7 +106,7 @@ static Error _erase_recursive(DirAccess *da) {
 			if (err) {
 				return err;
 			}
-			err = da->remove(da->get_current_dir().plus_file(E));
+			err = da->remove(da->get_current_dir().path_join(E));
 			if (err) {
 				return err;
 			}
@@ -116,7 +116,7 @@ static Error _erase_recursive(DirAccess *da) {
 	}
 
 	for (const String &E : files) {
-		Error err = da->remove(da->get_current_dir().plus_file(E));
+		Error err = da->remove(da->get_current_dir().path_join(E));
 		if (err) {
 			return err;
 		}
@@ -138,7 +138,7 @@ Error DirAccess::make_dir_recursive(String p_dir) {
 
 	if (p_dir.is_relative_path()) {
 		//append current
-		full_dir = get_current_dir().plus_file(p_dir);
+		full_dir = get_current_dir().path_join(p_dir);
 
 	} else {
 		full_dir = p_dir;
@@ -172,7 +172,7 @@ Error DirAccess::make_dir_recursive(String p_dir) {
 
 	String curpath = base;
 	for (int i = 0; i < subdirs.size(); i++) {
-		curpath = curpath.plus_file(subdirs[i]);
+		curpath = curpath.path_join(subdirs[i]);
 		Error err = make_dir(curpath);
 		if (err != OK && err != ERR_ALREADY_EXISTS) {
 			ERR_FAIL_V_MSG(err, "Could not create directory: " + curpath);
@@ -354,8 +354,8 @@ Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod
 	String n = get_next();
 	while (!n.is_empty()) {
 		if (n != "." && n != "..") {
-			if (p_copy_links && is_link(get_current_dir().plus_file(n))) {
-				create_link(read_link(get_current_dir().plus_file(n)), p_to + n);
+			if (p_copy_links && is_link(get_current_dir().path_join(n))) {
+				create_link(read_link(get_current_dir().path_join(n)), p_to + n);
 			} else if (current_is_dir()) {
 				dirs.push_back(n);
 			} else {
@@ -364,7 +364,7 @@ Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod
 					list_dir_end();
 					return ERR_BUG;
 				}
-				Error err = copy(get_current_dir().plus_file(n), p_to + rel_path, p_chmod_flags);
+				Error err = copy(get_current_dir().path_join(n), p_to + rel_path, p_chmod_flags);
 				if (err) {
 					list_dir_end();
 					return err;

+ 1 - 1
core/io/file_access_pack.cpp

@@ -520,7 +520,7 @@ String DirAccessPack::get_current_dir(bool p_include_drive) const {
 
 	while (pd->parent) {
 		pd = pd->parent;
-		p = pd->name.plus_file(p);
+		p = pd->name.path_join(p);
 	}
 
 	return "res://" + p;

+ 3 - 3
core/io/resource_format_binary.cpp

@@ -421,7 +421,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
 
 					if (!path.contains("://") && path.is_relative_path()) {
 						// path is relative to file being loaded, so convert to a resource path
-						path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path));
+						path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().path_join(path));
 					}
 
 					if (remaps.find(path)) {
@@ -683,7 +683,7 @@ Error ResourceLoaderBinary::load() {
 
 		if (!path.contains("://") && path.is_relative_path()) {
 			// path is relative to file being loaded, so convert to a resource path
-			path = ProjectSettings::get_singleton()->localize_path(path.get_base_dir().plus_file(external_resources[i].path));
+			path = ProjectSettings::get_singleton()->localize_path(path.get_base_dir().path_join(external_resources[i].path));
 		}
 
 		external_resources.write[i].path = path; //remap happens here, not on load because on load it can actually be used for filesystem dock resource remap
@@ -1329,7 +1329,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
 
 		bool relative = false;
 		if (!path.begins_with("res://")) {
-			path = local_path.plus_file(path).simplify_path();
+			path = local_path.path_join(path).simplify_path();
 			relative = true;
 		}
 

+ 1 - 1
core/io/resource_importer.cpp

@@ -421,7 +421,7 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_extension(const St
 }
 
 String ResourceFormatImporter::get_import_base_path(const String &p_for_file) const {
-	return ProjectSettings::get_singleton()->get_imported_files_path().plus_file(p_for_file.get_file() + "-" + p_for_file.md5_text());
+	return ProjectSettings::get_singleton()->get_imported_files_path().path_join(p_for_file.get_file() + "-" + p_for_file.md5_text());
 }
 
 bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) const {

+ 1 - 1
core/io/resource_uid.cpp

@@ -39,7 +39,7 @@ static constexpr uint32_t char_count = ('z' - 'a');
 static constexpr uint32_t base = char_count + ('9' - '0');
 
 String ResourceUID::get_cache_file() {
-	return ProjectSettings::get_singleton()->get_project_data_path().plus_file("uid_cache.bin");
+	return ProjectSettings::get_singleton()->get_project_data_path().path_join("uid_cache.bin");
 }
 
 String ResourceUID::id_to_text(ID p_id) const {

+ 1 - 1
core/string/ustring.cpp

@@ -4451,7 +4451,7 @@ String String::get_extension() const {
 	return substr(pos + 1, length());
 }
 
-String String::plus_file(const String &p_file) const {
+String String::path_join(const String &p_file) const {
 	if (is_empty()) {
 		return p_file;
 	}

+ 1 - 1
core/string/ustring.h

@@ -370,7 +370,7 @@ public:
 	String rstrip(const String &p_chars) const;
 	String get_extension() const;
 	String get_basename() const;
-	String plus_file(const String &p_file) const;
+	String path_join(const String &p_file) const;
 	char32_t unicode_at(int p_idx) const;
 
 	void erase(int p_pos, int p_chars);

+ 1 - 1
core/variant/variant_call.cpp

@@ -1523,7 +1523,7 @@ static void _register_variant_builtin_methods() {
 	bind_method(String, rstrip, sarray("chars"), varray());
 	bind_method(String, get_extension, sarray(), varray());
 	bind_method(String, get_basename, sarray(), varray());
-	bind_method(String, plus_file, sarray("file"), varray());
+	bind_method(String, path_join, sarray("file"), varray());
 	bind_method(String, unicode_at, sarray("at"), varray());
 	bind_method(String, indent, sarray("prefix"), varray());
 	bind_method(String, dedent, sarray(), varray());

+ 1 - 1
doc/classes/ProjectSettings.xml

@@ -100,7 +100,7 @@
 				    # `path` will contain the absolute path to `hello.txt` next to the executable.
 				    # This is *not* identical to using `ProjectSettings.globalize_path()` with a `res://` path,
 				    # but is close enough in spirit.
-				    path = OS.get_executable_path().get_base_dir().plus_file("hello.txt")
+				    path = OS.get_executable_path().get_base_dir().path_join("hello.txt")
 				[/codeblock]
 			</description>
 		</method>

+ 2 - 2
doc/classes/String.xml

@@ -566,11 +566,11 @@
 				Formats a number to have an exact number of [param digits] before the decimal point.
 			</description>
 		</method>
-		<method name="plus_file" qualifiers="const">
+		<method name="path_join" qualifiers="const">
 			<return type="String" />
 			<param index="0" name="file" type="String" />
 			<description>
-				If the string is a path, this concatenates [param file] at the end of the string as a subpath. E.g. [code]"this/is".plus_file("path") == "this/is/path"[/code].
+				If the string is a path, this concatenates [param file] at the end of the string as a subpath. E.g. [code]"this/is".path_join("path") == "this/is/path"[/code].
 			</description>
 		</method>
 		<method name="repeat" qualifiers="const">

+ 2 - 2
drivers/gles3/shader_gles3.cpp

@@ -472,7 +472,7 @@ String ShaderGLES3::_version_get_sha1(Version *p_version) const {
 bool ShaderGLES3::_load_from_cache(Version *p_version) {
 #if 0
 	String sha1 = _version_get_sha1(p_version);
-	String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+	String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache";
 
 	Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ);
 	if (f.is_null()) {
@@ -538,7 +538,7 @@ bool ShaderGLES3::_load_from_cache(Version *p_version) {
 void ShaderGLES3::_save_to_cache(Version *p_version) {
 #if 0
 	String sha1 = _version_get_sha1(p_version);
-	String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+	String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache";
 
 	Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE);
 	ERR_FAIL_COND(f.is_null());

+ 14 - 14
drivers/unix/dir_access_unix.cpp

@@ -69,7 +69,7 @@ bool DirAccessUnix::file_exists(String p_file) {
 	GLOBAL_LOCK_FUNCTION
 
 	if (p_file.is_relative_path()) {
-		p_file = current_dir.plus_file(p_file);
+		p_file = current_dir.path_join(p_file);
 	}
 
 	p_file = fix_path(p_file);
@@ -88,7 +88,7 @@ bool DirAccessUnix::dir_exists(String p_dir) {
 	GLOBAL_LOCK_FUNCTION
 
 	if (p_dir.is_relative_path()) {
-		p_dir = get_current_dir().plus_file(p_dir);
+		p_dir = get_current_dir().path_join(p_dir);
 	}
 
 	p_dir = fix_path(p_dir);
@@ -103,7 +103,7 @@ bool DirAccessUnix::is_readable(String p_dir) {
 	GLOBAL_LOCK_FUNCTION
 
 	if (p_dir.is_relative_path()) {
-		p_dir = get_current_dir().plus_file(p_dir);
+		p_dir = get_current_dir().path_join(p_dir);
 	}
 
 	p_dir = fix_path(p_dir);
@@ -114,7 +114,7 @@ bool DirAccessUnix::is_writable(String p_dir) {
 	GLOBAL_LOCK_FUNCTION
 
 	if (p_dir.is_relative_path()) {
-		p_dir = get_current_dir().plus_file(p_dir);
+		p_dir = get_current_dir().path_join(p_dir);
 	}
 
 	p_dir = fix_path(p_dir);
@@ -123,7 +123,7 @@ bool DirAccessUnix::is_writable(String p_dir) {
 
 uint64_t DirAccessUnix::get_modified_time(String p_file) {
 	if (p_file.is_relative_path()) {
-		p_file = current_dir.plus_file(p_file);
+		p_file = current_dir.path_join(p_file);
 	}
 
 	p_file = fix_path(p_file);
@@ -159,7 +159,7 @@ String DirAccessUnix::get_next() {
 	// known if it points to a directory. stat() will resolve the link
 	// for us.
 	if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) {
-		String f = current_dir.plus_file(fname);
+		String f = current_dir.path_join(fname);
 
 		struct stat flags;
 		if (stat(f.utf8().get_data(), &flags) == 0) {
@@ -315,7 +315,7 @@ Error DirAccessUnix::make_dir(String p_dir) {
 	GLOBAL_LOCK_FUNCTION
 
 	if (p_dir.is_relative_path()) {
-		p_dir = get_current_dir().plus_file(p_dir);
+		p_dir = get_current_dir().path_join(p_dir);
 	}
 
 	p_dir = fix_path(p_dir);
@@ -350,7 +350,7 @@ Error DirAccessUnix::change_dir(String p_dir) {
 	// try_dir is the directory we are trying to change into
 	String try_dir = "";
 	if (p_dir.is_relative_path()) {
-		String next_dir = current_dir.plus_file(p_dir);
+		String next_dir = current_dir.path_join(p_dir);
 		next_dir = next_dir.simplify_path();
 		try_dir = next_dir;
 	} else {
@@ -394,13 +394,13 @@ String DirAccessUnix::get_current_dir(bool p_include_drive) const {
 
 Error DirAccessUnix::rename(String p_path, String p_new_path) {
 	if (p_path.is_relative_path()) {
-		p_path = get_current_dir().plus_file(p_path);
+		p_path = get_current_dir().path_join(p_path);
 	}
 
 	p_path = fix_path(p_path);
 
 	if (p_new_path.is_relative_path()) {
-		p_new_path = get_current_dir().plus_file(p_new_path);
+		p_new_path = get_current_dir().path_join(p_new_path);
 	}
 
 	p_new_path = fix_path(p_new_path);
@@ -410,7 +410,7 @@ Error DirAccessUnix::rename(String p_path, String p_new_path) {
 
 Error DirAccessUnix::remove(String p_path) {
 	if (p_path.is_relative_path()) {
-		p_path = get_current_dir().plus_file(p_path);
+		p_path = get_current_dir().path_join(p_path);
 	}
 
 	p_path = fix_path(p_path);
@@ -429,7 +429,7 @@ Error DirAccessUnix::remove(String p_path) {
 
 bool DirAccessUnix::is_link(String p_file) {
 	if (p_file.is_relative_path()) {
-		p_file = get_current_dir().plus_file(p_file);
+		p_file = get_current_dir().path_join(p_file);
 	}
 
 	p_file = fix_path(p_file);
@@ -444,7 +444,7 @@ bool DirAccessUnix::is_link(String p_file) {
 
 String DirAccessUnix::read_link(String p_file) {
 	if (p_file.is_relative_path()) {
-		p_file = get_current_dir().plus_file(p_file);
+		p_file = get_current_dir().path_join(p_file);
 	}
 
 	p_file = fix_path(p_file);
@@ -461,7 +461,7 @@ String DirAccessUnix::read_link(String p_file) {
 
 Error DirAccessUnix::create_link(String p_source, String p_target) {
 	if (p_target.is_relative_path()) {
-		p_target = get_current_dir().plus_file(p_target);
+		p_target = get_current_dir().path_join(p_target);
 	}
 
 	p_source = fix_path(p_source);

+ 5 - 5
drivers/unix/os_unix.cpp

@@ -454,12 +454,12 @@ Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle
 
 	if (!FileAccess::exists(path)) {
 		// This code exists so GDExtension can load .so files from within the executable path.
-		path = get_executable_path().get_base_dir().plus_file(p_path.get_file());
+		path = get_executable_path().get_base_dir().path_join(p_path.get_file());
 	}
 
 	if (!FileAccess::exists(path)) {
 		// This code exists so GDExtension can load .so files from a standard unix location.
-		path = get_executable_path().get_base_dir().plus_file("../lib").plus_file(p_path.get_file());
+		path = get_executable_path().get_base_dir().path_join("../lib").path_join(p_path.get_file());
 	}
 
 	p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
@@ -526,13 +526,13 @@ String OS_Unix::get_user_data_dir() const {
 			if (custom_dir.is_empty()) {
 				custom_dir = appname;
 			}
-			return get_data_path().plus_file(custom_dir);
+			return get_data_path().path_join(custom_dir);
 		} else {
-			return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file(appname);
+			return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname);
 		}
 	}
 
-	return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file("[unnamed project]");
+	return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]");
 }
 
 String OS_Unix::get_executable_path() const {

+ 6 - 6
drivers/windows/dir_access_windows.cpp

@@ -157,7 +157,7 @@ Error DirAccessWindows::make_dir(String p_dir) {
 
 	p_dir = fix_path(p_dir);
 	if (p_dir.is_relative_path()) {
-		p_dir = current_dir.plus_file(p_dir);
+		p_dir = current_dir.path_join(p_dir);
 	}
 
 	p_dir = p_dir.replace("/", "\\");
@@ -213,7 +213,7 @@ bool DirAccessWindows::file_exists(String p_file) {
 	GLOBAL_LOCK_FUNCTION
 
 	if (!p_file.is_absolute_path()) {
-		p_file = get_current_dir().plus_file(p_file);
+		p_file = get_current_dir().path_join(p_file);
 	}
 
 	p_file = fix_path(p_file);
@@ -232,7 +232,7 @@ bool DirAccessWindows::dir_exists(String p_dir) {
 	GLOBAL_LOCK_FUNCTION
 
 	if (p_dir.is_relative_path()) {
-		p_dir = get_current_dir().plus_file(p_dir);
+		p_dir = get_current_dir().path_join(p_dir);
 	}
 
 	p_dir = fix_path(p_dir);
@@ -247,13 +247,13 @@ bool DirAccessWindows::dir_exists(String p_dir) {
 
 Error DirAccessWindows::rename(String p_path, String p_new_path) {
 	if (p_path.is_relative_path()) {
-		p_path = get_current_dir().plus_file(p_path);
+		p_path = get_current_dir().path_join(p_path);
 	}
 
 	p_path = fix_path(p_path);
 
 	if (p_new_path.is_relative_path()) {
-		p_new_path = get_current_dir().plus_file(p_new_path);
+		p_new_path = get_current_dir().path_join(p_new_path);
 	}
 
 	p_new_path = fix_path(p_new_path);
@@ -291,7 +291,7 @@ Error DirAccessWindows::rename(String p_path, String p_new_path) {
 
 Error DirAccessWindows::remove(String p_path) {
 	if (p_path.is_relative_path()) {
-		p_path = get_current_dir().plus_file(p_path);
+		p_path = get_current_dir().path_join(p_path);
 	}
 
 	p_path = fix_path(p_path);

+ 4 - 4
editor/create_dialog.cpp

@@ -383,7 +383,7 @@ void CreateDialog::_confirmed() {
 	}
 
 	{
-		Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE);
+		Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("create_recent." + base_type), FileAccess::WRITE);
 		if (f.is_valid()) {
 			f->store_line(selected_item);
 
@@ -660,7 +660,7 @@ void CreateDialog::_save_and_update_favorite_list() {
 	TreeItem *root = favorites->create_item();
 
 	{
-		Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE);
+		Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites." + base_type), FileAccess::WRITE);
 		if (f.is_valid()) {
 			for (int i = 0; i < favorite_list.size(); i++) {
 				String l = favorite_list[i];
@@ -686,7 +686,7 @@ void CreateDialog::_save_and_update_favorite_list() {
 
 void CreateDialog::_load_favorites_and_history() {
 	String dir = EditorPaths::get_singleton()->get_project_settings_dir();
-	Ref<FileAccess> f = FileAccess::open(dir.plus_file("create_recent." + base_type), FileAccess::READ);
+	Ref<FileAccess> f = FileAccess::open(dir.path_join("create_recent." + base_type), FileAccess::READ);
 	if (f.is_valid()) {
 		while (!f->eof_reached()) {
 			String l = f->get_line().strip_edges();
@@ -698,7 +698,7 @@ void CreateDialog::_load_favorites_and_history() {
 		}
 	}
 
-	f = FileAccess::open(dir.plus_file("favorites." + base_type), FileAccess::READ);
+	f = FileAccess::open(dir.path_join("favorites." + base_type), FileAccess::READ);
 	if (f.is_valid()) {
 		while (!f->eof_reached()) {
 			String l = f->get_line().strip_edges();

+ 2 - 2
editor/doc_tools.cpp

@@ -1071,7 +1071,7 @@ Error DocTools::load_classes(const String &p_dir) {
 	while (!path.is_empty()) {
 		if (!da->current_is_dir() && path.ends_with("xml")) {
 			Ref<XMLParser> parser = memnew(XMLParser);
-			Error err2 = parser->open(p_dir.plus_file(path));
+			Error err2 = parser->open(p_dir.path_join(path));
 			if (err2) {
 				return err2;
 			}
@@ -1380,7 +1380,7 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
 		}
 
 		Error err;
-		String save_file = save_path.plus_file(c.name + ".xml");
+		String save_file = save_path.path_join(c.name + ".xml");
 		Ref<FileAccess> f = FileAccess::open(save_file, FileAccess::WRITE, &err);
 
 		ERR_CONTINUE_MSG(err != OK, "Can't write doc file: " + save_file + ".");

+ 1 - 1
editor/editor_autoload_settings.cpp

@@ -164,7 +164,7 @@ void EditorAutoloadSettings::_autoload_add() {
 		if (!fpath.ends_with("/")) {
 			fpath = fpath.get_base_dir();
 		}
-		dialog->config("Node", fpath.plus_file(vformat("%s.gd", autoload_add_name->get_text().camelcase_to_underscore())), false, false);
+		dialog->config("Node", fpath.path_join(vformat("%s.gd", autoload_add_name->get_text().camelcase_to_underscore())), false, false);
 		dialog->popup_centered();
 	} else {
 		if (autoload_add(autoload_add_name->get_text(), autoload_add_path->get_text())) {

+ 1 - 1
editor/editor_dir_dialog.cpp

@@ -172,7 +172,7 @@ void EditorDirDialog::_make_dir_confirm() {
 		mkdirerr->popup_centered(Size2(250, 80) * EDSCALE);
 	} else {
 		opened_paths.insert(dir);
-		//reload(dir.plus_file(makedirname->get_text()));
+		//reload(dir.path_join(makedirname->get_text()));
 		EditorFileSystem::get_singleton()->scan_changes(); //we created a dir, so rescan changes
 	}
 	makedirname->set_text(""); // reset label

+ 8 - 8
editor/editor_feature_profile.cpp

@@ -315,7 +315,7 @@ void EditorFeatureProfileManager::_notification(int p_what) {
 			current_profile = EDITOR_GET("_default_feature_profile");
 			if (!current_profile.is_empty()) {
 				current.instantiate();
-				Error err = current->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(current_profile + ".profile"));
+				Error err = current->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(current_profile + ".profile"));
 				if (err != OK) {
 					ERR_PRINT("Error loading default feature profile: " + current_profile);
 					current_profile = String();
@@ -346,7 +346,7 @@ void EditorFeatureProfileManager::_update_profile_list(const String &p_select_pr
 	if (p_select_profile.is_empty()) { //default, keep
 		if (profile_list->get_selected() >= 0) {
 			selected_profile = profile_list->get_item_metadata(profile_list->get_selected());
-			if (!FileAccess::exists(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(selected_profile + ".profile"))) {
+			if (!FileAccess::exists(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(selected_profile + ".profile"))) {
 				selected_profile = String(); //does not exist
 			}
 		}
@@ -475,7 +475,7 @@ void EditorFeatureProfileManager::_create_new_profile() {
 		EditorNode::get_singleton()->show_warning(TTR("Profile must be a valid filename and must not contain '.'"));
 		return;
 	}
-	String file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(name + ".profile");
+	String file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(name + ".profile");
 	if (FileAccess::exists(file)) {
 		EditorNode::get_singleton()->show_warning(TTR("Profile with this name already exists."));
 		return;
@@ -754,8 +754,8 @@ void EditorFeatureProfileManager::_update_selected_profile() {
 	} else {
 		//reload edited, if different from current
 		edited.instantiate();
-		Error err = edited->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(profile + ".profile"));
-		ERR_FAIL_COND_MSG(err != OK, "Error when loading editor feature profile from file '" + EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(profile + ".profile") + "'.");
+		Error err = edited->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(profile + ".profile"));
+		ERR_FAIL_COND_MSG(err != OK, "Error when loading editor feature profile from file '" + EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(profile + ".profile") + "'.");
 	}
 
 	updating_features = true;
@@ -810,7 +810,7 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths
 			return;
 		}
 
-		String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(basefile);
+		String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(basefile);
 
 		if (FileAccess::exists(dst_file)) {
 			EditorNode::get_singleton()->show_warning(vformat(TTR("Profile '%s' already exists. Remove it first before importing, import aborted."), basefile.get_basename()));
@@ -825,7 +825,7 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths
 		Error err = profile->load_from_file(p_paths[i]);
 		ERR_CONTINUE(err != OK);
 		String basefile = p_paths[i].get_file();
-		String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(basefile);
+		String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(basefile);
 		profile->save_to_file(dst_file);
 	}
 
@@ -849,7 +849,7 @@ void EditorFeatureProfileManager::_save_and_update() {
 	ERR_FAIL_COND(edited_path.is_empty());
 	ERR_FAIL_COND(edited.is_null());
 
-	edited->save_to_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(edited_path + ".profile"));
+	edited->save_to_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(edited_path + ".profile"));
 
 	if (edited == current) {
 		update_timer->start();

+ 13 - 13
editor/editor_file_dialog.cpp

@@ -251,7 +251,7 @@ void EditorFileDialog::_file_submitted(const String &p_file) {
 }
 
 void EditorFileDialog::_save_confirm_pressed() {
-	String f = dir_access->get_current_dir().plus_file(file->get_text());
+	String f = dir_access->get_current_dir().path_join(file->get_text());
 	_save_to_recent();
 	hide();
 	emit_signal(SNAME("file_selected"), f);
@@ -284,7 +284,7 @@ void EditorFileDialog::_post_popup() {
 	}
 
 	if (is_visible() && !get_current_file().is_empty()) {
-		_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+		_request_single_thumbnail(get_current_dir().path_join(get_current_file()));
 	}
 
 	if (is_visible()) {
@@ -381,7 +381,7 @@ void EditorFileDialog::_action_pressed() {
 		Vector<String> files;
 		for (int i = 0; i < item_list->get_item_count(); i++) {
 			if (item_list->is_selected(i)) {
-				files.push_back(fbase.plus_file(item_list->get_item_text(i)));
+				files.push_back(fbase.path_join(item_list->get_item_text(i)));
 			}
 		}
 
@@ -395,7 +395,7 @@ void EditorFileDialog::_action_pressed() {
 	}
 
 	String file_text = file->get_text();
-	String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().plus_file(file_text);
+	String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().path_join(file_text);
 
 	if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) {
 		_save_to_recent();
@@ -410,7 +410,7 @@ void EditorFileDialog::_action_pressed() {
 			if (item_list->is_selected(i)) {
 				Dictionary d = item_list->get_item_metadata(i);
 				if (d["dir"]) {
-					path = path.plus_file(d["name"]);
+					path = path.path_join(d["name"]);
 
 					break;
 				}
@@ -461,7 +461,7 @@ void EditorFileDialog::_action_pressed() {
 				if (!valid && filterSliceCount > 0) {
 					String str = (flt.get_slice(",", 0).strip_edges());
 					f += str.substr(1, str.length() - 1);
-					_request_single_thumbnail(get_current_dir().plus_file(f.get_file()));
+					_request_single_thumbnail(get_current_dir().path_join(f.get_file()));
 					file->set_text(f.get_file());
 					valid = true;
 				}
@@ -505,7 +505,7 @@ void EditorFileDialog::_item_selected(int p_item) {
 
 	if (!d["dir"]) {
 		file->set_text(d["name"]);
-		_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+		_request_single_thumbnail(get_current_dir().path_join(get_current_file()));
 	} else if (mode == FILE_MODE_OPEN_DIR) {
 		set_ok_button_text(TTR("Select This Folder"));
 	}
@@ -523,7 +523,7 @@ void EditorFileDialog::_multi_selected(int p_item, bool p_selected) {
 
 	if (!d["dir"] && p_selected) {
 		file->set_text(d["name"]);
-		_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+		_request_single_thumbnail(get_current_dir().path_join(get_current_file()));
 	}
 
 	get_ok_button()->set_disabled(_is_open_should_be_disabled());
@@ -830,7 +830,7 @@ void EditorFileDialog::update_file_list() {
 
 		Dictionary d;
 		d["name"] = dir_name;
-		d["path"] = cdir.plus_file(dir_name);
+		d["path"] = cdir.path_join(dir_name);
 		d["dir"] = true;
 
 		item_list->set_item_metadata(-1, d);
@@ -879,7 +879,7 @@ void EditorFileDialog::update_file_list() {
 			item_list->add_item(files.front()->get());
 
 			if (get_icon_func) {
-				Ref<Texture2D> icon = get_icon_func(cdir.plus_file(files.front()->get()));
+				Ref<Texture2D> icon = get_icon_func(cdir.path_join(files.front()->get()));
 				if (display_mode == DISPLAY_THUMBNAILS) {
 					item_list->set_item_icon(-1, file_thumbnail);
 					item_list->set_item_tag_icon(-1, icon);
@@ -891,7 +891,7 @@ void EditorFileDialog::update_file_list() {
 			Dictionary d;
 			d["name"] = files.front()->get();
 			d["dir"] = false;
-			String fullpath = cdir.plus_file(files.front()->get());
+			String fullpath = cdir.path_join(files.front()->get());
 			d["path"] = fullpath;
 			item_list->set_item_metadata(-1, d);
 
@@ -995,7 +995,7 @@ String EditorFileDialog::get_current_file() const {
 }
 
 String EditorFileDialog::get_current_path() const {
-	return dir_access->get_current_dir().plus_file(file->get_text());
+	return dir_access->get_current_dir().path_join(file->get_text());
 }
 
 void EditorFileDialog::set_current_dir(const String &p_dir) {
@@ -1014,7 +1014,7 @@ void EditorFileDialog::set_current_file(const String &p_file) {
 	_focus_file_text();
 
 	if (is_visible()) {
-		_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+		_request_single_thumbnail(get_current_dir().path_join(get_current_file()));
 	}
 }
 

+ 15 - 15
editor/editor_file_system.cpp

@@ -99,7 +99,7 @@ String EditorFileSystemDirectory::get_path() const {
 	String p;
 	const EditorFileSystemDirectory *d = this;
 	while (d->parent) {
-		p = d->name.plus_file(p);
+		p = d->name.path_join(p);
 		d = d->parent;
 	}
 
@@ -110,7 +110,7 @@ String EditorFileSystemDirectory::get_file_path(int p_idx) const {
 	String file = get_file(p_idx);
 	const EditorFileSystemDirectory *d = this;
 	while (d->parent) {
-		file = d->name.plus_file(file);
+		file = d->name.path_join(file);
 		d = d->parent;
 	}
 
@@ -219,7 +219,7 @@ void EditorFileSystem::_scan_filesystem() {
 
 	String project = ProjectSettings::get_singleton()->get_resource_path();
 
-	String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME);
+	String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join(CACHE_FILE_NAME);
 	{
 		Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::READ);
 
@@ -261,7 +261,7 @@ void EditorFileSystem::_scan_filesystem() {
 					String file;
 
 					file = name;
-					name = cpath.plus_file(name);
+					name = cpath.path_join(name);
 
 					FileCache fc;
 					fc.type = split[1];
@@ -289,7 +289,7 @@ void EditorFileSystem::_scan_filesystem() {
 		}
 	}
 
-	String update_cache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4");
+	String update_cache = EditorPaths::get_singleton()->get_project_settings_dir().path_join("filesystem_update4");
 
 	if (FileAccess::exists(update_cache)) {
 		{
@@ -332,7 +332,7 @@ void EditorFileSystem::_scan_filesystem() {
 void EditorFileSystem::_save_filesystem_cache() {
 	group_file_cache.clear();
 
-	String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME);
+	String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join(CACHE_FILE_NAME);
 
 	Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::WRITE);
 	ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + fscache + "'. Check user write permissions.");
@@ -758,7 +758,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
 				continue;
 			}
 
-			if (_should_skip_directory(cd.plus_file(f))) {
+			if (_should_skip_directory(cd.path_join(f))) {
 				continue;
 			}
 
@@ -822,7 +822,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
 		EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
 		fi->file = E->get();
 
-		String path = cd.plus_file(fi->file);
+		String path = cd.path_join(fi->file);
 
 		FileCache *fc = file_cache.getptr(path);
 		uint64_t mt = FileAccess::get_modified_time(path);
@@ -982,7 +982,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
 
 				int idx = p_dir->find_dir_index(f);
 				if (idx == -1) {
-					if (_should_skip_directory(cd.plus_file(f))) {
+					if (_should_skip_directory(cd.path_join(f))) {
 						continue;
 					}
 
@@ -991,7 +991,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
 					efd->parent = p_dir;
 					efd->name = f;
 					Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
-					d->change_dir(cd.plus_file(f));
+					d->change_dir(cd.path_join(f));
 					_scan_new_dir(efd, d, p_progress.get_sub(1, 1));
 
 					ItemAction ia;
@@ -1017,7 +1017,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
 					EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
 					fi->file = f;
 
-					String path = cd.plus_file(fi->file);
+					String path = cd.path_join(fi->file);
 					fi->modified_time = FileAccess::get_modified_time(path);
 					fi->import_modified_time = 0;
 					fi->type = ResourceLoader::get_resource_type(path);
@@ -1066,7 +1066,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
 			continue;
 		}
 
-		String path = cd.plus_file(p_dir->files[i]->file);
+		String path = cd.path_join(p_dir->files[i]->file);
 
 		if (import_extensions.has(p_dir->files[i]->file.get_extension().to_lower())) {
 			//check here if file must be imported or not
@@ -1452,7 +1452,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p
 
 void EditorFileSystem::_save_late_updated_files() {
 	//files that already existed, and were modified, need re-scanning for dependencies upon project restart. This is done via saving this special file
-	String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4");
+	String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join("filesystem_update4");
 	Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::WRITE);
 	ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + fscache + "'. Check user write permissions.");
 	for (const String &E : late_update_files) {
@@ -2198,12 +2198,12 @@ bool EditorFileSystem::_should_skip_directory(const String &p_path) {
 		return true;
 	}
 
-	if (FileAccess::exists(p_path.plus_file("project.godot"))) {
+	if (FileAccess::exists(p_path.path_join("project.godot"))) {
 		// skip if another project inside this
 		return true;
 	}
 
-	if (FileAccess::exists(p_path.plus_file(".gdignore"))) {
+	if (FileAccess::exists(p_path.path_join(".gdignore"))) {
 		// skip if a `.gdignore` file is inside this
 		return true;
 	}

+ 5 - 5
editor/editor_folding.cpp

@@ -56,7 +56,7 @@ void EditorFolding::save_resource_folding(const Ref<Resource> &p_resource, const
 	config->set_value("folding", "sections_unfolded", unfolds);
 
 	String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
-	file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+	file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
 	config->save(file);
 }
 
@@ -74,7 +74,7 @@ void EditorFolding::load_resource_folding(Ref<Resource> p_resource, const String
 	config.instantiate();
 
 	String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
-	file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+	file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
 
 	if (config->load(file) != OK) {
 		return;
@@ -150,7 +150,7 @@ void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path
 	config->set_value("folding", "nodes_folded", nodes_folded);
 
 	String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
-	file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+	file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
 	config->save(file);
 }
 
@@ -160,7 +160,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
 
 	String path = EditorPaths::get_singleton()->get_project_settings_dir();
 	String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
-	file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+	file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
 
 	if (config->load(file) != OK) {
 		return;
@@ -214,7 +214,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
 
 bool EditorFolding::has_folding_data(const String &p_path) {
 	String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
-	file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+	file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
 	return FileAccess::exists(file);
 }
 

+ 2 - 2
editor/editor_help.cpp

@@ -1929,7 +1929,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
 			}
 			String image = bbcode.substr(brk_end + 1, end - brk_end - 1);
 
-			Ref<Texture2D> texture = ResourceLoader::load(base_path.plus_file(image), "Texture2D");
+			Ref<Texture2D> texture = ResourceLoader::load(base_path.path_join(image), "Texture2D");
 			if (texture.is_valid()) {
 				p_rt->add_image(texture);
 			}
@@ -1946,7 +1946,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
 		} else if (tag.begins_with("font=")) {
 			String fnt = tag.substr(5, tag.length());
 
-			Ref<Font> font = ResourceLoader::load(base_path.plus_file(fnt), "Font");
+			Ref<Font> font = ResourceLoader::load(base_path.path_join(fnt), "Font");
 			if (font.is_valid()) {
 				p_rt->push_font(font);
 			} else {

+ 3 - 3
editor/editor_log.cpp

@@ -131,7 +131,7 @@ void EditorLog::_save_state() {
 	Ref<ConfigFile> config;
 	config.instantiate();
 	// Load and amend existing config if it exists.
-	config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+	config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
 
 	const String section = "editor_log";
 	for (const KeyValue<MessageType, LogFilter *> &E : type_filter_map) {
@@ -141,7 +141,7 @@ void EditorLog::_save_state() {
 	config->set_value(section, "collapse", collapse);
 	config->set_value(section, "show_search", search_box->is_visible());
 
-	config->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+	config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
 }
 
 void EditorLog::_load_state() {
@@ -149,7 +149,7 @@ void EditorLog::_load_state() {
 
 	Ref<ConfigFile> config;
 	config.instantiate();
-	config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+	config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
 
 	// Run the below code even if config->load returns an error, since we want the defaults to be set even if the file does not exist yet.
 	const String section = "editor_log";

+ 12 - 12
editor/editor_node.cpp

@@ -1096,7 +1096,7 @@ void EditorNode::_scan_external_changes() {
 		}
 	}
 
-	String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("project.godot");
+	String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().path_join("project.godot");
 	if (FileAccess::get_modified_time(project_settings_path) > ProjectSettings::get_singleton()->get_last_saved_time()) {
 		TreeItem *ti = disk_changed_list->create_item(r);
 		ti->set_text(0, "project.godot");
@@ -1393,7 +1393,7 @@ void EditorNode::_get_scene_metadata(const String &p_file) {
 		return;
 	}
 
-	String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
+	String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
 
 	Ref<ConfigFile> cf;
 	cf.instantiate();
@@ -1425,7 +1425,7 @@ void EditorNode::_set_scene_metadata(const String &p_file, int p_idx) {
 		return;
 	}
 
-	String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
+	String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
 
 	Ref<ConfigFile> cf;
 	cf.instantiate();
@@ -1621,7 +1621,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
 			// Save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5.
 			String temp_path = EditorPaths::get_singleton()->get_cache_dir();
 			String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text();
-			cache_base = temp_path.plus_file("resthumb-" + cache_base);
+			cache_base = temp_path.path_join("resthumb-" + cache_base);
 
 			// Does not have it, try to load a cached thumbnail.
 			String file = cache_base + ".png";
@@ -2908,7 +2908,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
 			OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir());
 		} break;
 		case FILE_EXPLORE_ANDROID_BUILD_TEMPLATES: {
-			OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().plus_file("android"));
+			OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().path_join("android"));
 		} break;
 		case FILE_QUIT:
 		case RUN_PROJECT_MANAGER:
@@ -3445,7 +3445,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
 
 	// Only try to load the script if it has a name. Else, the plugin has no init script.
 	if (script_path.length() > 0) {
-		script_path = addon_path.get_base_dir().plus_file(script_path);
+		script_path = addon_path.get_base_dir().path_join(script_path);
 		script = ResourceLoader::load(script_path);
 
 		if (script.is_null()) {
@@ -4730,13 +4730,13 @@ void EditorNode::_save_docks() {
 	Ref<ConfigFile> config;
 	config.instantiate();
 	// Load and amend existing config if it exists.
-	config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+	config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
 
 	_save_docks_to_config(config, "docks");
 	_save_open_scenes_to_config(config, "EditorNode");
 	editor_data.get_plugin_window_layout(config);
 
-	config->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+	config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
 }
 
 void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) {
@@ -4800,7 +4800,7 @@ void EditorNode::_dock_split_dragged(int ofs) {
 void EditorNode::_load_docks() {
 	Ref<ConfigFile> config;
 	config.instantiate();
-	Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+	Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
 	if (err != OK) {
 		// No config.
 		if (overridden_default_layout >= 0) {
@@ -5033,7 +5033,7 @@ bool EditorNode::has_scenes_in_session() {
 	}
 	Ref<ConfigFile> config;
 	config.instantiate();
-	Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+	Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
 	if (err != OK) {
 		return false;
 	}
@@ -5685,7 +5685,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str
 
 	for (int i = 0; i < p_files.size(); i++) {
 		String from = p_files[i];
-		String to = to_path.plus_file(from.get_file());
+		String to = to_path.path_join(from.get_file());
 
 		if (dir->dir_exists(from)) {
 			Vector<String> sub_files;
@@ -5700,7 +5700,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str
 					continue;
 				}
 
-				sub_files.push_back(from.plus_file(next_file));
+				sub_files.push_back(from.path_join(next_file));
 				next_file = sub_dir->get_next();
 			}
 

+ 14 - 14
editor/editor_paths.cpp

@@ -67,19 +67,19 @@ String EditorPaths::get_self_contained_file() const {
 }
 
 String EditorPaths::get_export_templates_dir() const {
-	return get_data_dir().plus_file(export_templates_folder);
+	return get_data_dir().path_join(export_templates_folder);
 }
 
 String EditorPaths::get_project_settings_dir() const {
-	return get_project_data_dir().plus_file("editor");
+	return get_project_data_dir().path_join("editor");
 }
 
 String EditorPaths::get_text_editor_themes_dir() const {
-	return get_config_dir().plus_file(text_editor_themes_folder);
+	return get_config_dir().path_join(text_editor_themes_folder);
 }
 
 String EditorPaths::get_script_templates_dir() const {
-	return get_config_dir().plus_file(script_templates_folder);
+	return get_config_dir().path_join(script_templates_folder);
 }
 
 String EditorPaths::get_project_script_templates_dir() const {
@@ -87,7 +87,7 @@ String EditorPaths::get_project_script_templates_dir() const {
 }
 
 String EditorPaths::get_feature_profiles_dir() const {
-	return get_config_dir().plus_file(feature_profiles_folder);
+	return get_config_dir().path_join(feature_profiles_folder);
 }
 
 void EditorPaths::create() {
@@ -119,8 +119,8 @@ EditorPaths::EditorPaths() {
 	String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();
 
 	// On macOS, look outside .app bundle, since .app bundle is read-only.
-	if (OS::get_singleton()->has_feature("macos") && exe_path.ends_with("MacOS") && exe_path.plus_file("..").simplify_path().ends_with("Contents")) {
-		exe_path = exe_path.plus_file("../../..").simplify_path();
+	if (OS::get_singleton()->has_feature("macos") && exe_path.ends_with("MacOS") && exe_path.path_join("..").simplify_path().ends_with("Contents")) {
+		exe_path = exe_path.path_join("../../..").simplify_path();
 	}
 	{
 		Ref<DirAccess> d = DirAccess::create_for_path(exe_path);
@@ -141,24 +141,24 @@ EditorPaths::EditorPaths() {
 	if (self_contained) {
 		// editor is self contained, all in same folder
 		data_path = exe_path;
-		data_dir = data_path.plus_file("editor_data");
+		data_dir = data_path.path_join("editor_data");
 		config_path = exe_path;
 		config_dir = data_dir;
 		cache_path = exe_path;
-		cache_dir = data_dir.plus_file("cache");
+		cache_dir = data_dir.path_join("cache");
 	} else {
 		// Typically XDG_DATA_HOME or %APPDATA%.
 		data_path = OS::get_singleton()->get_data_path();
-		data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+		data_dir = data_path.path_join(OS::get_singleton()->get_godot_dir_name());
 		// Can be different from data_path e.g. on Linux or macOS.
 		config_path = OS::get_singleton()->get_config_path();
-		config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+		config_dir = config_path.path_join(OS::get_singleton()->get_godot_dir_name());
 		// Can be different from above paths, otherwise a subfolder of data_dir.
 		cache_path = OS::get_singleton()->get_cache_path();
 		if (cache_path == data_path) {
-			cache_dir = data_dir.plus_file("cache");
+			cache_dir = data_dir.path_join("cache");
 		} else {
-			cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+			cache_dir = cache_path.path_join(OS::get_singleton()->get_godot_dir_name());
 		}
 	}
 
@@ -232,7 +232,7 @@ EditorPaths::EditorPaths() {
 		}
 
 		// Check that the project data directory '.gdignore' file exists
-		String project_data_gdignore_file_path = project_data_dir.plus_file(".gdignore");
+		String project_data_gdignore_file_path = project_data_dir.path_join(".gdignore");
 		if (!FileAccess::exists(project_data_gdignore_file_path)) {
 			// Add an empty .gdignore file to avoid scan.
 			Ref<FileAccess> f = FileAccess::open(project_data_gdignore_file_path, FileAccess::WRITE);

+ 2 - 2
editor/editor_plugin_settings.cpp

@@ -178,8 +178,8 @@ Vector<String> EditorPluginSettings::_get_plugins(const String &p_dir) {
 			continue;
 		}
 
-		const String full_path = p_dir.plus_file(path);
-		const String plugin_config = full_path.plus_file("plugin.cfg");
+		const String full_path = p_dir.path_join(path);
+		const String plugin_config = full_path.path_join("plugin.cfg");
 		if (FileAccess::exists(plugin_config)) {
 			plugins.push_back(plugin_config);
 		} else {

+ 1 - 1
editor/editor_resource_preview.cpp

@@ -244,7 +244,7 @@ void EditorResourcePreview::_iterate() {
 			} else {
 				String temp_path = EditorPaths::get_singleton()->get_cache_dir();
 				String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
-				cache_base = temp_path.plus_file("resthumb-" + cache_base);
+				cache_base = temp_path.path_join("resthumb-" + cache_base);
 
 				//does not have it, try to load a cached thumbnail
 

+ 16 - 16
editor/editor_settings.cpp

@@ -856,7 +856,7 @@ void EditorSettings::create() {
 		// Validate editor config file.
 		Ref<DirAccess> dir = DirAccess::open(EditorPaths::get_singleton()->get_config_dir());
 		String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres";
-		config_file_path = EditorPaths::get_singleton()->get_config_dir().plus_file(config_file_name);
+		config_file_path = EditorPaths::get_singleton()->get_config_dir().path_join(config_file_name);
 		if (!dir->file_exists(config_file_name)) {
 			goto fail;
 		}
@@ -887,7 +887,7 @@ fail:
 	if (extra_config->has_section("init_projects")) {
 		Vector<String> list = extra_config->get_value("init_projects", "list");
 		for (int i = 0; i < list.size(); i++) {
-			list.write[i] = exe_path.plus_file(list[i]);
+			list.write[i] = exe_path.path_join(list[i]);
 		}
 		extra_config->set_value("init_projects", "list", list);
 	}
@@ -1106,7 +1106,7 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) {
 
 void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) {
 	Ref<ConfigFile> cf = memnew(ConfigFile);
-	String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("project_metadata.cfg");
+	String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg");
 	Error err;
 	err = cf->load(path);
 	ERR_FAIL_COND_MSG(err != OK && err != ERR_FILE_NOT_FOUND, "Cannot load editor settings from file '" + path + "'.");
@@ -1117,7 +1117,7 @@ void EditorSettings::set_project_metadata(const String &p_section, const String
 
 Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const {
 	Ref<ConfigFile> cf = memnew(ConfigFile);
-	String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("project_metadata.cfg");
+	String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg");
 	Error err = cf->load(path);
 	if (err != OK) {
 		return p_default;
@@ -1129,9 +1129,9 @@ void EditorSettings::set_favorites(const Vector<String> &p_favorites) {
 	favorites = p_favorites;
 	String favorites_file;
 	if (Engine::get_singleton()->is_project_manager_hint()) {
-		favorites_file = EditorPaths::get_singleton()->get_config_dir().plus_file("favorite_dirs");
+		favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs");
 	} else {
-		favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites");
+		favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites");
 	}
 	Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::WRITE);
 	if (f.is_valid()) {
@@ -1149,9 +1149,9 @@ void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs) {
 	recent_dirs = p_recent_dirs;
 	String recent_dirs_file;
 	if (Engine::get_singleton()->is_project_manager_hint()) {
-		recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().plus_file("recent_dirs");
+		recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs");
 	} else {
-		recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("recent_dirs");
+		recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs");
 	}
 	Ref<FileAccess> f = FileAccess::open(recent_dirs_file, FileAccess::WRITE);
 	if (f.is_valid()) {
@@ -1169,11 +1169,11 @@ void EditorSettings::load_favorites_and_recent_dirs() {
 	String favorites_file;
 	String recent_dirs_file;
 	if (Engine::get_singleton()->is_project_manager_hint()) {
-		favorites_file = EditorPaths::get_singleton()->get_config_dir().plus_file("favorite_dirs");
-		recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().plus_file("recent_dirs");
+		favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs");
+		recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs");
 	} else {
-		favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites");
-		recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("recent_dirs");
+		favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites");
+		recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs");
 	}
 	Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::READ);
 	if (f.is_valid()) {
@@ -1236,7 +1236,7 @@ void EditorSettings::load_text_editor_theme() {
 		return; // sorry for "Settings changed" console spam
 	}
 
-	String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file + ".tet");
+	String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file + ".tet");
 
 	Ref<ConfigFile> cf = memnew(ConfigFile);
 	Error err = cf->load(theme_path);
@@ -1273,7 +1273,7 @@ bool EditorSettings::import_text_editor_theme(String p_file) {
 
 		Ref<DirAccess> d = DirAccess::open(EditorPaths::get_singleton()->get_text_editor_themes_dir());
 		if (d.is_valid()) {
-			d->copy(p_file, EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file.get_file()));
+			d->copy(p_file, EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file.get_file()));
 			return true;
 		}
 	}
@@ -1286,7 +1286,7 @@ bool EditorSettings::save_text_editor_theme() {
 	if (_is_default_text_editor_theme(p_file.get_file().to_lower())) {
 		return false;
 	}
-	String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file + ".tet");
+	String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file + ".tet");
 	return _save_text_editor_theme(theme_path);
 }
 
@@ -1339,7 +1339,7 @@ Vector<String> EditorSettings::get_script_templates(const String &p_extension, c
 }
 
 String EditorSettings::get_editor_layouts_config() const {
-	return EditorPaths::get_singleton()->get_config_dir().plus_file("editor_layouts.cfg");
+	return EditorPaths::get_singleton()->get_config_dir().path_join("editor_layouts.cfg");
 }
 
 float EditorSettings::get_auto_display_scale() const {

+ 2 - 2
editor/editor_vcs_interface.cpp

@@ -168,14 +168,14 @@ void EditorVCSInterface::set_singleton(EditorVCSInterface *p_singleton) {
 
 void EditorVCSInterface::create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir) {
 	if (p_vcs_metadata_type == VCSMetadata::GIT) {
-		Ref<FileAccess> f = FileAccess::open(p_dir.plus_file(".gitignore"), FileAccess::WRITE);
+		Ref<FileAccess> f = FileAccess::open(p_dir.path_join(".gitignore"), FileAccess::WRITE);
 		if (f.is_null()) {
 			ERR_FAIL_MSG(TTR("Couldn't create .gitignore in project path."));
 		} else {
 			f->store_line("# Godot 4+ specific ignores");
 			f->store_line(".godot/");
 		}
-		f = FileAccess::open(p_dir.plus_file(".gitattributes"), FileAccess::WRITE);
+		f = FileAccess::open(p_dir.path_join(".gitattributes"), FileAccess::WRITE);
 		if (f.is_null()) {
 			ERR_FAIL_MSG(TTR("Couldn't create .gitattributes in project path."));
 		} else {

+ 4 - 4
editor/export/editor_export_platform.cpp

@@ -295,7 +295,7 @@ Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const {
 
 String EditorExportPlatform::find_export_template(String template_file_name, String *err) const {
 	String current_version = VERSION_FULL_CONFIG;
-	String template_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(current_version).plus_file(template_file_name);
+	String template_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(current_version).path_join(template_file_name);
 
 	if (FileAccess::exists(template_path)) {
 		return template_path;
@@ -848,7 +848,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
 				}
 			} else {
 				// Use default text server data.
-				String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_icu_data");
+				String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_icu_data");
 				TS->save_support_data(icu_data_file);
 				Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file);
 				err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
@@ -861,7 +861,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
 	}
 
 	String config_file = "project.binary";
-	String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp" + config_file);
+	String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp" + config_file);
 	ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list);
 	Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb);
 	DirAccess::remove_file_or_error(engine_cfb);
@@ -885,7 +885,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
 	Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 	da->make_dir_recursive(EditorPaths::get_singleton()->get_cache_dir());
 
-	String tmppath = EditorPaths::get_singleton()->get_cache_dir().plus_file("packtmp");
+	String tmppath = EditorPaths::get_singleton()->get_cache_dir().path_join("packtmp");
 	Ref<FileAccess> ftmp = FileAccess::open(tmppath, FileAccess::WRITE);
 	if (ftmp.is_null()) {
 		add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), vformat(TTR("Cannot create file \"%s\"."), tmppath));

+ 2 - 2
editor/export/editor_export_platform_pc.cpp

@@ -185,9 +185,9 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset>
 			String src_path = ProjectSettings::get_singleton()->globalize_path(so_files[i].path);
 			String target_path;
 			if (so_files[i].target.is_empty()) {
-				target_path = p_path.get_base_dir().plus_file(src_path.get_file());
+				target_path = p_path.get_base_dir().path_join(src_path.get_file());
 			} else {
-				target_path = p_path.get_base_dir().plus_file(so_files[i].target).plus_file(src_path.get_file());
+				target_path = p_path.get_base_dir().path_join(so_files[i].target).path_join(src_path.get_file());
 			}
 
 			if (da->dir_exists(src_path)) {

+ 1 - 1
editor/export/editor_export_plugin.cpp

@@ -181,7 +181,7 @@ void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, con
 	if (!convert) {
 		return;
 	}
-	String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpfile.res");
+	String tmp_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpfile.res");
 	Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path);
 	if (err != OK) {
 		DirAccess::remove_file_or_error(tmp_path);

+ 16 - 16
editor/export/export_template_manager.cpp

@@ -91,7 +91,7 @@ void ExportTemplateManager::_update_template_status() {
 		install_options_vb->show();
 
 		if (templates.has(current_version)) {
-			current_installed_path->set_text(templates_dir.plus_file(current_version));
+			current_installed_path->set_text(templates_dir.path_join(current_version));
 		}
 	}
 
@@ -146,7 +146,7 @@ void ExportTemplateManager::_download_template(const String &p_url, bool p_skip_
 	download_progress_hb->show();
 	_set_current_progress_status(TTR("Starting the download..."));
 
-	download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz"));
+	download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_templates.tpz"));
 	download_templates->set_use_threads(true);
 
 	const String proxy_host = EDITOR_GET("network/http_proxy/host");
@@ -440,7 +440,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
 	}
 
 	Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
-	String template_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(version);
+	String template_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(version);
 	Error err = d->make_dir_recursive(template_path);
 	if (err != OK) {
 		EditorNode::get_singleton()->show_warning(TTR("Error creating path for extracting templates:") + "\n" + template_path);
@@ -486,12 +486,12 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
 
 		if (base_dir != contents_dir && base_dir.begins_with(contents_dir)) {
 			base_dir = base_dir.substr(contents_dir.length(), file_path.length()).trim_prefix("/");
-			file = base_dir.plus_file(file);
+			file = base_dir.path_join(file);
 
 			Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 			ERR_CONTINUE(da.is_null());
 
-			String output_dir = template_path.plus_file(base_dir);
+			String output_dir = template_path.path_join(base_dir);
 
 			if (!DirAccess::exists(output_dir)) {
 				Error mkdir_err = da->make_dir_recursive(output_dir);
@@ -503,7 +503,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
 			p->step(TTR("Importing:") + " " + file, fc);
 		}
 
-		String to_write = template_path.plus_file(file);
+		String to_write = template_path.path_join(file);
 		Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE);
 
 		if (f.is_null()) {
@@ -544,14 +544,14 @@ void ExportTemplateManager::_uninstall_template_confirmed() {
 	Error err = da->change_dir(templates_dir);
 	ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir + "'.");
 	err = da->change_dir(uninstall_version);
-	ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.plus_file(uninstall_version) + "'.");
+	ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.path_join(uninstall_version) + "'.");
 
 	err = da->erase_contents_recursive();
-	ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.plus_file(uninstall_version) + "'.");
+	ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.path_join(uninstall_version) + "'.");
 
 	da->change_dir("..");
 	err = da->remove(uninstall_version);
-	ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.plus_file(uninstall_version) + "'.");
+	ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.path_join(uninstall_version) + "'.");
 
 	_update_template_status();
 }
@@ -618,7 +618,7 @@ void ExportTemplateManager::_installed_table_button_cbk(Object *p_item, int p_co
 
 void ExportTemplateManager::_open_template_folder(const String &p_version) {
 	const String &templates_dir = EditorPaths::get_singleton()->get_export_templates_dir();
-	OS::get_singleton()->shell_open("file://" + templates_dir.plus_file(p_version));
+	OS::get_singleton()->shell_open("file://" + templates_dir.path_join(p_version));
 }
 
 void ExportTemplateManager::popup_manager() {
@@ -641,13 +641,13 @@ void ExportTemplateManager::_hide_dialog() {
 }
 
 bool ExportTemplateManager::can_install_android_template() {
-	const String templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
-	return FileAccess::exists(templates_dir.plus_file("android_source.zip"));
+	const String templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG);
+	return FileAccess::exists(templates_dir.path_join("android_source.zip"));
 }
 
 Error ExportTemplateManager::install_android_template() {
-	const String &templates_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
-	const String &source_zip = templates_path.plus_file("android_source.zip");
+	const String &templates_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG);
+	const String &source_zip = templates_path.path_join("android_source.zip");
 	ERR_FAIL_COND_V(!FileAccess::exists(source_zip), ERR_CANT_OPEN);
 	return install_android_template_from_file(source_zip);
 }
@@ -723,11 +723,11 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_
 			unzCloseCurrentFile(pkg);
 
 			if (!dirs_tested.has(base_dir)) {
-				da->make_dir_recursive(String("android/build").plus_file(base_dir));
+				da->make_dir_recursive(String("android/build").path_join(base_dir));
 				dirs_tested.insert(base_dir);
 			}
 
-			String to_write = String("res://android/build").plus_file(path);
+			String to_write = String("res://android/build").path_join(path);
 			Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE);
 			if (f.is_valid()) {
 				f->store_buffer(data.ptr(), data.size());

+ 14 - 14
editor/filesystem_dock.cpp

@@ -146,7 +146,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
 			file_item->set_text(0, fi.name);
 			file_item->set_structured_text_bidi_override(0, TextServer::STRUCTURED_TEXT_FILE);
 			file_item->set_icon(0, _get_tree_item_icon(!fi.import_broken, fi.type));
-			String file_metadata = lpath.plus_file(fi.name);
+			String file_metadata = lpath.path_join(fi.name);
 			file_item->set_metadata(0, file_metadata);
 			if (!p_select_in_favorites && path == file_metadata) {
 				file_item->select(0);
@@ -867,7 +867,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
 					String dname = efd->get_subdir(i)->get_name();
 
 					files->add_item(dname, folder_icon, true);
-					files->set_item_metadata(-1, directory.plus_file(dname) + "/");
+					files->set_item_metadata(-1, directory.path_join(dname) + "/");
 					files->set_item_icon_modulate(-1, folder_color);
 
 					if (cselection.has(dname)) {
@@ -880,7 +880,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
 			for (int i = 0; i < efd->get_file_count(); i++) {
 				FileInfo fi;
 				fi.name = efd->get_file(i);
-				fi.path = directory.plus_file(fi.name);
+				fi.path = directory.path_join(fi.name);
 				fi.type = efd->get_file_type(i);
 				fi.import_broken = !efd->get_file_import_is_valid(i);
 				fi.modified_time = efd->get_file_modified_time(i);
@@ -1545,7 +1545,7 @@ void FileSystemDock::_rename_operation_confirm() {
 	}
 
 	String old_path = to_rename.path.ends_with("/") ? to_rename.path.substr(0, to_rename.path.length() - 1) : to_rename.path;
-	String new_path = old_path.get_base_dir().plus_file(new_name);
+	String new_path = old_path.get_base_dir().path_join(new_name);
 	if (old_path == new_path) {
 		return;
 	}
@@ -1605,7 +1605,7 @@ void FileSystemDock::_duplicate_operation_confirm() {
 		base_dir = base_dir.get_base_dir();
 	}
 
-	String new_path = base_dir.plus_file(new_name);
+	String new_path = base_dir.path_join(new_name);
 
 	// Present a more user friendly warning for name conflict
 	Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
@@ -1630,7 +1630,7 @@ Vector<String> FileSystemDock::_check_existing() {
 	String &p_to_path = to_move_path;
 	for (int i = 0; i < to_move.size(); i++) {
 		String ol_pth = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
-		String p_new_path = p_to_path.plus_file(ol_pth.get_file());
+		String p_new_path = p_to_path.path_join(ol_pth.get_file());
 		FileOrFolder p_item = to_move[i];
 
 		String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/");
@@ -1662,7 +1662,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove
 	// Check groups.
 	for (int i = 0; i < to_move.size(); i++) {
 		if (to_move[i].is_file && EditorFileSystem::get_singleton()->is_group_file(to_move[i].path)) {
-			EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.plus_file(to_move[i].path.get_file()));
+			EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.path_join(to_move[i].path.get_file()));
 		}
 	}
 
@@ -1671,7 +1671,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove
 	bool is_moved = false;
 	for (int i = 0; i < to_move.size(); i++) {
 		String old_path = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
-		String new_path = p_to_path.plus_file(old_path.get_file());
+		String new_path = p_to_path.path_join(old_path.get_file());
 		if (old_path != new_path) {
 			_try_move_item(to_move[i], new_path, file_renames, folder_renames);
 			is_moved = true;
@@ -2005,7 +2005,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
 			if (!fpath.ends_with("/")) {
 				fpath = fpath.get_base_dir();
 			}
-			make_script_dialog->config("Node", fpath.plus_file("new_script.gd"), false, false);
+			make_script_dialog->config("Node", fpath.path_join("new_script.gd"), false, false);
 			make_script_dialog->popup_centered();
 		} break;
 
@@ -2047,15 +2047,15 @@ void FileSystemDock::_resource_created() {
 
 	String type_name = new_resource_dialog->get_selected_type();
 	if (type_name == "Shader") {
-		make_shader_dialog->config(fpath.plus_file("new_shader"), false, false, 0);
+		make_shader_dialog->config(fpath.path_join("new_shader"), false, false, 0);
 		make_shader_dialog->popup_centered();
 		return;
 	} else if (type_name == "VisualShader") {
-		make_shader_dialog->config(fpath.plus_file("new_shader"), false, false, 1);
+		make_shader_dialog->config(fpath.path_join("new_shader"), false, false, 1);
 		make_shader_dialog->popup_centered();
 		return;
 	} else if (type_name == "ShaderInclude") {
-		make_shader_dialog->config(fpath.plus_file("new_shader_include"), false, false, 2);
+		make_shader_dialog->config(fpath.path_join("new_shader_include"), false, false, 2);
 		make_shader_dialog->popup_centered();
 		return;
 	}
@@ -2370,11 +2370,11 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
 						String new_path_base;
 
 						if (to_move[i].is_file) {
-							new_path = to_dir.plus_file(to_move[i].path.get_file());
+							new_path = to_dir.path_join(to_move[i].path.get_file());
 							new_path_base = new_path.get_basename() + " (%d)." + new_path.get_extension();
 						} else {
 							PackedStringArray path_split = to_move[i].path.split("/");
-							new_path = to_dir.plus_file(path_split[path_split.size() - 2]);
+							new_path = to_dir.path_join(path_split[path_split.size() - 2]);
 							new_path_base = new_path + " (%d)";
 						}
 

+ 2 - 2
editor/find_in_files.cpp

@@ -168,7 +168,7 @@ void FindInFiles::_iterate() {
 			String folder_name = folders_to_scan[folders_to_scan.size() - 1];
 			pop_back(folders_to_scan);
 
-			_current_dir = _current_dir.plus_file(folder_name);
+			_current_dir = _current_dir.path_join(folder_name);
 
 			PackedStringArray sub_dirs;
 			_scan_dir("res://" + _current_dir, sub_dirs);
@@ -246,7 +246,7 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) {
 		} else {
 			String file_ext = file.get_extension();
 			if (_extension_filter.has(file_ext)) {
-				_files_to_scan.push_back(path.plus_file(file));
+				_files_to_scan.push_back(path.path_join(file));
 			}
 		}
 	}

+ 2 - 2
editor/import/collada.cpp

@@ -289,7 +289,7 @@ void Collada::_parse_image(XMLParser &parser) {
 		String path = parser.get_attribute_value("source").strip_edges();
 		if (!path.contains("://") && path.is_relative_path()) {
 			// path is relative to file being loaded, so convert to a resource path
-			image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path.uri_decode()));
+			image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path.uri_decode()));
 		}
 	} else {
 		while (parser.read() == OK) {
@@ -302,7 +302,7 @@ void Collada::_parse_image(XMLParser &parser) {
 
 					if (!path.contains("://") && path.is_relative_path()) {
 						// path is relative to file being loaded, so convert to a resource path
-						path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path));
+						path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path));
 
 					} else if (path.find("file:///") == 0) {
 						path = path.replace_first("file:///", "");

+ 5 - 5
editor/import/resource_importer_obj.cpp

@@ -129,7 +129,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
 			if (p.is_absolute_path()) {
 				path = p;
 			} else {
-				path = base_path.plus_file(p);
+				path = base_path.path_join(p);
 			}
 
 			Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -149,7 +149,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
 			if (p.is_absolute_path()) {
 				path = p;
 			} else {
-				path = base_path.plus_file(p);
+				path = base_path.path_join(p);
 			}
 
 			Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -169,7 +169,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
 			if (p.is_absolute_path()) {
 				path = p;
 			} else {
-				path = base_path.plus_file(p);
+				path = base_path.path_join(p);
 			}
 
 			Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -184,7 +184,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
 			ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT);
 
 			String p = l.replace("map_bump", "").replace("\\", "/").strip_edges();
-			String path = base_path.plus_file(p);
+			String path = base_path.path_join(p);
 
 			Ref<Texture2D> texture = ResourceLoader::load(path);
 
@@ -405,7 +405,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
 				HashMap<String, Ref<StandardMaterial3D>> lib;
 				String lib_path = current_material_library;
 				if (lib_path.is_relative_path()) {
-					lib_path = p_path.get_base_dir().plus_file(current_material_library);
+					lib_path = p_path.get_base_dir().path_join(current_material_library);
 				}
 				Error err = _parse_material_library(lib_path, lib, r_missing_deps);
 				if (err == OK) {

+ 1 - 1
editor/import/resource_importer_shader_file.cpp

@@ -79,7 +79,7 @@ static String _include_function(const String &p_path, void *userpointer) {
 
 	String include = p_path;
 	if (include.is_relative_path()) {
-		include = base_path->plus_file(include);
+		include = base_path->path_join(include);
 	}
 
 	Ref<FileAccess> file_inc = FileAccess::open(include, FileAccess::READ, &err);

+ 3 - 3
editor/import/scene_import_settings.cpp

@@ -1029,7 +1029,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
 						item->set_metadata(0, E.key);
 						item->set_editable(0, true);
 						item->set_checked(0, true);
-						String path = p_path.plus_file(name);
+						String path = p_path.path_join(name);
 						if (external_extension_type->get_selected() == 0) {
 							path += ".tres";
 						} else {
@@ -1082,7 +1082,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
 						item->set_metadata(0, E.key);
 						item->set_editable(0, true);
 						item->set_checked(0, true);
-						String path = p_path.plus_file(name);
+						String path = p_path.path_join(name);
 						if (external_extension_type->get_selected() == 0) {
 							path += ".tres";
 						} else {
@@ -1134,7 +1134,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
 					item->set_metadata(0, E.key);
 					item->set_editable(0, true);
 					item->set_checked(0, true);
-					String path = p_path.plus_file(name);
+					String path = p_path.path_join(name);
 					if (external_extension_type->get_selected() == 0) {
 						path += ".tres";
 					} else {

+ 2 - 2
editor/plugin_config_dialog.cpp

@@ -62,7 +62,7 @@ void PluginConfigDialog::_on_confirmed() {
 	if (script_name.get_extension().is_empty()) {
 		script_name += "." + ext;
 	}
-	String script_path = path.plus_file(script_name);
+	String script_path = path.path_join(script_name);
 
 	Ref<ConfigFile> cf = memnew(ConfigFile);
 	cf->set_value("plugin", "name", name_edit->get_text());
@@ -71,7 +71,7 @@ void PluginConfigDialog::_on_confirmed() {
 	cf->set_value("plugin", "version", version_edit->get_text());
 	cf->set_value("plugin", "script", script_name);
 
-	cf->save(path.plus_file("plugin.cfg"));
+	cf->save(path.path_join("plugin.cfg"));
 
 	if (!_edit_mode) {
 		String class_name = script_name.get_basename();

+ 4 - 4
editor/plugins/asset_library_editor_plugin.cpp

@@ -487,7 +487,7 @@ void EditorAssetLibraryItemDownload::_make_request() {
 	retry_button->hide();
 
 	download->cancel_request();
-	download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip");
+	download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_asset_" + itos(asset_id)) + ".zip");
 
 	Error err = download->request(host);
 	if (err != OK) {
@@ -730,7 +730,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
 		PackedByteArray image_data = p_data;
 
 		if (use_cache) {
-			String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
+			String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
 
 			Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ);
 			if (file.is_valid()) {
@@ -804,7 +804,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
 		if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) {
 			for (int i = 0; i < headers.size(); i++) {
 				if (headers[i].findn("ETag:") == 0) { // Save etag
-					String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
+					String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
 					String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges();
 					Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".etag", FileAccess::WRITE);
 					if (file.is_valid()) {
@@ -846,7 +846,7 @@ void EditorAssetLibrary::_update_image_queue() {
 	List<int> to_delete;
 	for (KeyValue<int, ImageQueue> &E : image_queue) {
 		if (!E.value.active && current_images < max_images) {
-			String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + E.value.image_url.md5_text());
+			String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + E.value.image_url.md5_text());
 			Vector<String> headers;
 
 			if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) {

+ 1 - 1
editor/plugins/editor_preview_plugins.cpp

@@ -255,7 +255,7 @@ Ref<Texture2D> EditorPackedScenePreviewPlugin::generate(const Ref<Resource> &p_f
 Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const {
 	String temp_path = EditorPaths::get_singleton()->get_cache_dir();
 	String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text();
-	cache_base = temp_path.plus_file("resthumb-" + cache_base);
+	cache_base = temp_path.path_join("resthumb-" + cache_base);
 
 	//does not have it, try to load a cached thumbnail
 

+ 5 - 5
editor/plugins/script_editor_plugin.cpp

@@ -1540,7 +1540,7 @@ void ScriptEditor::_show_save_theme_as_dialog() {
 	file_dialog_option = THEME_SAVE_AS;
 	file_dialog->clear_filters();
 	file_dialog->add_filter("*.tet");
-	file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(EditorSettings::get_singleton()->get("text_editor/theme/color_theme")));
+	file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(EditorSettings::get_singleton()->get("text_editor/theme/color_theme")));
 	file_dialog->popup_file_dialog();
 	file_dialog->set_title(TTR("Save Theme As..."));
 }
@@ -2038,7 +2038,7 @@ void ScriptEditor::_update_script_names() {
 				} break;
 				case DISPLAY_DIR_AND_NAME: {
 					if (!path.get_base_dir().get_file().is_empty()) {
-						sd.name = path.get_base_dir().get_file().plus_file(name);
+						sd.name = path.get_base_dir().get_file().path_join(name);
 					} else {
 						sd.name = name;
 					}
@@ -2064,7 +2064,7 @@ void ScriptEditor::_update_script_names() {
 					name = name.get_file();
 				} break;
 				case DISPLAY_DIR_AND_NAME: {
-					name = name.get_base_dir().get_file().plus_file(name.get_file());
+					name = name.get_base_dir().get_file().path_join(name.get_file());
 				} break;
 				default:
 					break;
@@ -3267,7 +3267,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
 	p_layout->set_value("ScriptEditor", "list_split_offset", list_split->get_split_offset());
 
 	// Save the cache.
-	script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg"));
+	script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg"));
 }
 
 void ScriptEditor::_help_class_open(const String &p_class) {
@@ -3648,7 +3648,7 @@ ScriptEditor::ScriptEditor() {
 	current_theme = "";
 
 	script_editor_cache.instantiate();
-	script_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg"));
+	script_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg"));
 
 	completion_cache = memnew(EditorScriptCodeCompletionCache);
 	restoring_layout = false;

+ 1 - 1
editor/plugins/script_text_editor.cpp

@@ -942,7 +942,7 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) {
 
 String ScriptTextEditor::_get_absolute_path(const String &rel_path) {
 	String base_path = script->get_path().get_base_dir();
-	String path = base_path.plus_file(rel_path);
+	String path = base_path.path_join(rel_path);
 	return path.replace("///", "//").simplify_path();
 }
 

+ 2 - 2
editor/plugins/shader_editor_plugin.cpp

@@ -1398,12 +1398,12 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) {
 	switch (p_index) {
 		case FILE_NEW: {
 			String base_path = FileSystemDock::get_singleton()->get_current_path().get_base_dir();
-			shader_create_dialog->config(base_path.plus_file("new_shader"), false, false, 0);
+			shader_create_dialog->config(base_path.path_join("new_shader"), false, false, 0);
 			shader_create_dialog->popup_centered();
 		} break;
 		case FILE_NEW_INCLUDE: {
 			String base_path = FileSystemDock::get_singleton()->get_current_path().get_base_dir();
-			shader_create_dialog->config(base_path.plus_file("new_shader"), false, false, 2);
+			shader_create_dialog->config(base_path.path_join("new_shader"), false, false, 2);
 			shader_create_dialog->popup_centered();
 		} break;
 		case FILE_OPEN: {

+ 2 - 2
editor/project_converter_3_to_4.cpp

@@ -1972,14 +1972,14 @@ Vector<String> ProjectConverter3To4::check_for_files() {
 					continue;
 				}
 				if (dir.current_is_dir()) {
-					directories_to_check.append(current_dir.plus_file(file_name) + "/");
+					directories_to_check.append(current_dir.path_join(file_name) + "/");
 				} else {
 					bool proper_extension = false;
 					if (file_name.ends_with(".gd") || file_name.ends_with(".shader") || file_name.ends_with(".tscn") || file_name.ends_with(".tres") || file_name.ends_with(".godot") || file_name.ends_with(".cs") || file_name.ends_with(".csproj"))
 						proper_extension = true;
 
 					if (proper_extension) {
-						collected_files.append(current_dir.plus_file(file_name));
+						collected_files.append(current_dir.path_join(file_name));
 					}
 				}
 				file_name = dir.get_next();

+ 13 - 13
editor/project_manager.cpp

@@ -438,7 +438,7 @@ private:
 				ProjectSettings::CustomMap edited_settings;
 				edited_settings["application/config/name"] = project_name->get_text().strip_edges();
 
-				if (current->save_custom(dir2.plus_file("project.godot"), edited_settings, Vector<String>(), true) != OK) {
+				if (current->save_custom(dir2.path_join("project.godot"), edited_settings, Vector<String>(), true) != OK) {
 					set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR);
 				}
 			}
@@ -486,12 +486,12 @@ private:
 					initial_settings["application/config/name"] = project_name->get_text().strip_edges();
 					initial_settings["application/config/icon"] = "res://icon.svg";
 
-					if (ProjectSettings::get_singleton()->save_custom(dir.plus_file("project.godot"), initial_settings, Vector<String>(), false) != OK) {
+					if (ProjectSettings::get_singleton()->save_custom(dir.path_join("project.godot"), initial_settings, Vector<String>(), false) != OK) {
 						set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
 					} else {
 						// Store default project icon in SVG format.
 						Error err;
-						Ref<FileAccess> fa_icon = FileAccess::open(dir.plus_file("icon.svg"), FileAccess::WRITE, &err);
+						Ref<FileAccess> fa_icon = FileAccess::open(dir.path_join("icon.svg"), FileAccess::WRITE, &err);
 						fa_icon->store_string(get_default_project_icon());
 
 						if (err != OK) {
@@ -556,7 +556,7 @@ private:
 							String rel_path = path.substr(zip_root.length());
 
 							Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
-							da->make_dir(dir.plus_file(rel_path));
+							da->make_dir(dir.path_join(rel_path));
 						} else {
 							Vector<uint8_t> data;
 							data.resize(info.uncompressed_size);
@@ -568,7 +568,7 @@ private:
 							ERR_BREAK_MSG(ret < 0, vformat("An error occurred while attempting to read from file: %s. This file will not be used.", rel_path));
 							unzCloseCurrentFile(pkg);
 
-							Ref<FileAccess> f = FileAccess::open(dir.plus_file(rel_path), FileAccess::WRITE);
+							Ref<FileAccess> f = FileAccess::open(dir.path_join(rel_path), FileAccess::WRITE);
 							if (f.is_valid()) {
 								f->store_buffer(data.ptr(), data.size());
 							} else {
@@ -1126,7 +1126,7 @@ ProjectList::ProjectList() {
 
 	_icon_load_index = 0;
 	project_opening_initiated = false;
-	_config_path = EditorPaths::get_singleton()->get_data_dir().plus_file("projects.cfg");
+	_config_path = EditorPaths::get_singleton()->get_data_dir().path_join("projects.cfg");
 }
 
 ProjectList::~ProjectList() {
@@ -1185,7 +1185,7 @@ void ProjectList::load_project_icon(int p_index) {
 
 // Load project data from p_property_key and return it in a ProjectList::Item. p_favorite is passed directly into the Item.
 ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_favorite) {
-	String conf = p_path.plus_file("project.godot");
+	String conf = p_path.path_join("project.godot");
 	bool grayed = false;
 	bool missing = false;
 
@@ -1221,7 +1221,7 @@ ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_fa
 		// when editing a project (but not when running it).
 		last_edited = FileAccess::get_modified_time(conf);
 
-		String fscache = p_path.plus_file(".fscache");
+		String fscache = p_path.path_join(".fscache");
 		if (FileAccess::exists(fscache)) {
 			uint64_t cache_modified = FileAccess::get_modified_time(fscache);
 			if (cache_modified > last_edited) {
@@ -1341,7 +1341,7 @@ void ProjectList::_global_menu_open_project(const Variant &p_tag) {
 	int idx = (int)p_tag;
 
 	if (idx >= 0 && idx < _projects.size()) {
-		String conf = _projects[idx].path.plus_file("project.godot");
+		String conf = _projects[idx].path.path_join("project.godot");
 		List<String> args;
 		args.push_back(conf);
 		OS::get_singleton()->create_instance(args);
@@ -2112,7 +2112,7 @@ void ProjectManager::_open_selected_projects() {
 	const HashSet<String> &selected_list = _project_list->get_selected_project_keys();
 
 	for (const String &path : selected_list) {
-		String conf = path.plus_file("project.godot");
+		String conf = path.path_join("project.godot");
 
 		if (!FileAccess::exists(conf)) {
 			dialog_error->set_text(vformat(TTR("Can't open project at '%s'."), path));
@@ -2162,7 +2162,7 @@ void ProjectManager::_open_selected_projects_ask() {
 	}
 
 	// Update the project settings or don't open
-	const String conf = project.path.plus_file("project.godot");
+	const String conf = project.path.path_join("project.godot");
 	const int config_version = project.version;
 	PackedStringArray unsupported_features = project.unsupported_features;
 
@@ -2235,7 +2235,7 @@ void ProjectManager::_run_project_confirm() {
 		const String &path = selected_list[i].path;
 
 		// `.substr(6)` on `ProjectSettings::get_singleton()->get_imported_files_path()` strips away the leading "res://".
-		if (!DirAccess::exists(path.plus_file(ProjectSettings::get_singleton()->get_imported_files_path().substr(6)))) {
+		if (!DirAccess::exists(path.path_join(ProjectSettings::get_singleton()->get_imported_files_path().substr(6)))) {
 			run_error_diag->set_text(TTR("Can't run project: Assets need to be imported.\nPlease edit the project to trigger the initial import."));
 			run_error_diag->popup_centered();
 			continue;
@@ -2280,7 +2280,7 @@ void ProjectManager::_scan_dir(const String &path) {
 	String n = da->get_next();
 	while (!n.is_empty()) {
 		if (da->current_is_dir() && !n.begins_with(".")) {
-			_scan_dir(da->get_current_dir().plus_file(n));
+			_scan_dir(da->get_current_dir().path_join(n));
 		} else if (n == "project.godot") {
 			_project_list->add_project(da->get_current_dir(), false);
 		}

+ 1 - 1
editor/scene_create_dialog.cpp

@@ -111,7 +111,7 @@ void SceneCreateDialog::update_dialog() {
 	}
 
 	if (is_valid) {
-		scene_name = directory.plus_file(scene_name);
+		scene_name = directory.path_join(scene_name);
 		Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
 		if (da->file_exists(scene_name)) {
 			update_error(file_error_label, MSG_ERROR, TTR("File already exists."));

+ 10 - 10
editor/scene_tree_dock.cpp

@@ -240,7 +240,7 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N
 		String new_name = parent->validate_child_name(instantiated_scene);
 		EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
 		editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name);
-		editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name)));
+		editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(new_name)));
 	}
 
 	editor_data->get_undo_redo()->commit_action();
@@ -691,7 +691,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 				EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
 
 				editor_data->get_undo_redo()->add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name());
-				editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(dup->get_name())));
+				editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(dup->get_name())));
 
 				add_below_node = dup;
 			}
@@ -1469,7 +1469,7 @@ bool SceneTreeDock::_update_node_path(Node *p_root_node, NodePath &r_node_path,
 	if (found_root_path) {
 		NodePath root_path_new = found_root_path->value;
 		if (!root_path_new.is_empty()) {
-			NodePath old_abs_path = NodePath(String(p_root_node->get_path()).plus_file(r_node_path));
+			NodePath old_abs_path = NodePath(String(p_root_node->get_path()).path_join(r_node_path));
 			old_abs_path.simplify();
 			r_node_path = root_path_new.rel_path_to(old_abs_path);
 		}
@@ -1839,7 +1839,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
 		}
 
 		editor_data->get_undo_redo()->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc);
-		editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).plus_file(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index());
+		editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).path_join(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index());
 
 		if (p_keep_global_xform) {
 			if (Object::cast_to<Node2D>(node)) {
@@ -2202,7 +2202,7 @@ void SceneTreeDock::_do_create(Node *p_parent) {
 		String new_name = p_parent->validate_child_name(child);
 		EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
 		editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name);
-		editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).plus_file(new_name)));
+		editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
 
 	} else {
 		editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
@@ -2938,9 +2938,9 @@ void SceneTreeDock::attach_script_to_selected(bool p_extend) {
 	if (path.is_empty()) {
 		String root_path = editor_data->get_edited_scene_root()->get_scene_file_path();
 		if (root_path.is_empty()) {
-			path = String("res://").plus_file(selected->get_name());
+			path = String("res://").path_join(selected->get_name());
 		} else {
-			path = root_path.get_base_dir().plus_file(selected->get_name());
+			path = root_path.get_base_dir().path_join(selected->get_name());
 		}
 	}
 
@@ -2997,9 +2997,9 @@ void SceneTreeDock::attach_shader_to_selected(int p_preferred_mode) {
 			shader_name = selected_shader_material->get_name();
 		}
 		if (root_path.is_empty()) {
-			path = String("res://").plus_file(shader_name);
+			path = String("res://").path_join(shader_name);
 		} else {
-			path = root_path.get_base_dir().plus_file(shader_name);
+			path = root_path.get_base_dir().path_join(shader_name);
 		}
 	}
 
@@ -3199,7 +3199,7 @@ void SceneTreeDock::_update_create_root_dialog() {
 			favorite_nodes->get_child(i)->queue_delete();
 		}
 
-		Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites.Node"), FileAccess::READ);
+		Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites.Node"), FileAccess::READ);
 		if (f.is_valid()) {
 			while (!f->eof_reached()) {
 				String l = f->get_line().strip_edges();

+ 2 - 2
editor/script_create_dialog.cpp

@@ -824,7 +824,7 @@ Vector<ScriptLanguage::ScriptTemplate> ScriptCreateDialog::_get_user_templates(c
 	Vector<ScriptLanguage::ScriptTemplate> user_templates;
 	String extension = language->get_extension();
 
-	String dir_path = p_dir.plus_file(p_object);
+	String dir_path = p_dir.path_join(p_object);
 
 	Ref<DirAccess> d = DirAccess::open(dir_path);
 	if (d.is_valid()) {
@@ -860,7 +860,7 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL
 
 	// Parse file for meta-information and script content
 	Error err;
-	Ref<FileAccess> file = FileAccess::open(p_path.plus_file(p_filename), FileAccess::READ, &err);
+	Ref<FileAccess> file = FileAccess::open(p_path.path_join(p_filename), FileAccess::READ, &err);
 	if (!err) {
 		while (!file->eof_reached()) {
 			String line = file->get_line();

+ 4 - 4
main/main.cpp

@@ -2342,7 +2342,7 @@ bool Main::start() {
 			// 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.plus_file(path);
+				path = doc_tool_path.path_join(path);
 			}
 			String name = _doc_data_class_paths[i].name;
 			doc_data_classes[name] = path;
@@ -2360,7 +2360,7 @@ bool Main::start() {
 			}
 		}
 
-		String index_path = doc_tool_path.plus_file("doc/classes");
+		String index_path = 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);
@@ -2730,11 +2730,11 @@ bool Main::start() {
 
 						if (sep == -1) {
 							Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
-							local_game_path = da->get_current_dir().plus_file(local_game_path);
+							local_game_path = da->get_current_dir().path_join(local_game_path);
 						} else {
 							Ref<DirAccess> da = DirAccess::open(local_game_path.substr(0, sep));
 							if (da.is_valid()) {
-								local_game_path = da->get_current_dir().plus_file(
+								local_game_path = da->get_current_dir().path_join(
 										local_game_path.substr(sep + 1, local_game_path.length()));
 							}
 						}

+ 3 - 3
modules/gdscript/gdscript.cpp

@@ -683,7 +683,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
 						if (base.is_empty() || base.is_relative_path()) {
 							ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());
 						} else {
-							path = base.get_base_dir().plus_file(path);
+							path = base.get_base_dir().path_join(path);
 						}
 					}
 				} else if (c->extends.size() != 0) {
@@ -2204,7 +2204,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
 			if (c->icon_path.is_empty() || c->icon_path.is_absolute_path()) {
 				*r_icon_path = c->icon_path;
 			} else if (c->icon_path.is_relative_path()) {
-				*r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path();
+				*r_icon_path = p_path.get_base_dir().path_join(c->icon_path).simplify_path();
 			}
 		}
 		if (r_base_type) {
@@ -2232,7 +2232,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
 							}
 							String subpath = subclass->extends_path;
 							if (subpath.is_relative_path()) {
-								subpath = path.get_base_dir().plus_file(subpath).simplify_path();
+								subpath = path.get_base_dir().path_join(subpath).simplify_path();
 							}
 
 							if (OK != subparser.parse(subsource, subpath, false)) {

+ 2 - 2
modules/gdscript/gdscript_analyzer.cpp

@@ -260,7 +260,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
 
 		if (!p_class->extends_path.is_empty()) {
 			if (p_class->extends_path.is_relative_path()) {
-				p_class->extends_path = class_type.script_path.get_base_dir().plus_file(p_class->extends_path).simplify_path();
+				p_class->extends_path = class_type.script_path.get_base_dir().path_join(p_class->extends_path).simplify_path();
 			}
 			Ref<GDScriptParserRef> parser = get_parser_for(p_class->extends_path);
 			if (parser.is_null()) {
@@ -3185,7 +3185,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
 		p_preload->resolved_path = p_preload->path->reduced_value;
 		// TODO: Save this as script dependency.
 		if (p_preload->resolved_path.is_relative_path()) {
-			p_preload->resolved_path = parser->script_path.get_base_dir().plus_file(p_preload->resolved_path);
+			p_preload->resolved_path = parser->script_path.get_base_dir().path_join(p_preload->resolved_path);
 		}
 		p_preload->resolved_path = p_preload->resolved_path.simplify_path();
 		if (!FileAccess::exists(p_preload->resolved_path)) {

+ 2 - 2
modules/gdscript/language_server/gdscript_workspace.cpp

@@ -228,9 +228,9 @@ void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String>
 		String file_name = dir->get_next();
 		while (file_name.length()) {
 			if (dir->current_is_dir() && file_name != "." && file_name != ".." && file_name != "./") {
-				list_script_files(p_root_dir.plus_file(file_name), r_files);
+				list_script_files(p_root_dir.path_join(file_name), r_files);
 			} else if (file_name.ends_with(".gd")) {
-				String script_file = p_root_dir.plus_file(file_name);
+				String script_file = p_root_dir.path_join(file_name);
 				r_files.push_back(script_file);
 			}
 			file_name = dir->get_next();

+ 3 - 3
modules/gdscript/tests/gdscript_test_runner.cpp

@@ -247,7 +247,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
 				next = dir->get_next();
 				continue;
 			}
-			if (!make_tests_for_dir(current_dir.plus_file(next))) {
+			if (!make_tests_for_dir(current_dir.path_join(next))) {
 				return false;
 			}
 		} else {
@@ -255,7 +255,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
 #ifndef DEBUG_ENABLED
 				// On release builds, skip tests marked as debug only.
 				Error open_err = OK;
-				Ref<FileAccess> script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err));
+				Ref<FileAccess> script_file(FileAccess::open(current_dir.path_join(next), FileAccess::READ, &open_err));
 				if (open_err != OK) {
 					ERR_PRINT(vformat(R"(Couldn't open test file "%s".)", next));
 					next = dir->get_next();
@@ -272,7 +272,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
 				if (!is_generating && !dir->file_exists(out_file)) {
 					ERR_FAIL_V_MSG(false, "Could not find output file for " + next);
 				}
-				GDScriptTest test(current_dir.plus_file(next), current_dir.plus_file(out_file), source_dir);
+				GDScriptTest test(current_dir.path_join(next), current_dir.path_join(out_file), source_dir);
 				tests.push_back(test);
 			}
 		}

+ 7 - 7
modules/gltf/editor/editor_scene_importer_blend.cpp

@@ -64,7 +64,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
 
 	// Escape paths to be valid Python strings to embed in the script.
 	const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape();
-	const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file(
+	const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
 			vformat("%s-%s.gltf", p_path.get_file().get_basename(), p_path.md5_text()));
 	const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape();
 
@@ -193,9 +193,9 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
 	String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path");
 
 #ifdef WINDOWS_ENABLED
-	blender_path = blender_path.plus_file("blender.exe");
+	blender_path = blender_path.path_join("blender.exe");
 #else
-	blender_path = blender_path.plus_file("blender");
+	blender_path = blender_path.path_join("blender");
 #endif
 
 	List<String> args;
@@ -287,14 +287,14 @@ void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, Li
 static bool _test_blender_path(const String &p_path, String *r_err = nullptr) {
 	String path = p_path;
 #ifdef WINDOWS_ENABLED
-	path = path.plus_file("blender.exe");
+	path = path.path_join("blender.exe");
 #else
-	path = path.plus_file("blender");
+	path = path.path_join("blender");
 #endif
 
 #if defined(MACOS_ENABLED)
 	if (!FileAccess::exists(path)) {
-		path = path.plus_file("Blender");
+		path = path.path_join("Blender");
 	}
 #endif
 
@@ -485,7 +485,7 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() {
 
 			bool found = false;
 			for (const String &path : mdfind_paths) {
-				found = _autodetect_path(path.plus_file("Contents/MacOS"));
+				found = _autodetect_path(path.path_join("Contents/MacOS"));
 				if (found) {
 					break;
 				}

+ 1 - 1
modules/gltf/editor/editor_scene_importer_fbx.cpp

@@ -57,7 +57,7 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t
 	// enclosed in double quotes by OS::execute(), so we only need to escape those.
 	// `c_escape_multiline()` seems to do this (escapes `\` and `"` only).
 	const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape_multiline();
-	const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file(
+	const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
 			vformat("%s-%s.glb", p_path.get_file().get_basename(), p_path.md5_text()));
 	const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape_multiline();
 

+ 4 - 4
modules/gltf/gltf_document.cpp

@@ -786,7 +786,7 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_pa
 				} else { // Relative path to an external image file.
 					ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER);
 					uri = uri.uri_decode();
-					uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows.
+					uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows.
 					buffer_data = FileAccess::get_file_as_array(uri);
 					ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri);
 				}
@@ -3039,8 +3039,8 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
 			if (!da->dir_exists(new_texture_dir)) {
 				da->make_dir(new_texture_dir);
 			}
-			image->save_png(new_texture_dir.plus_file(name));
-			d["uri"] = texture_dir.plus_file(name).uri_encode();
+			image->save_png(new_texture_dir.path_join(name));
+			d["uri"] = texture_dir.path_join(name).uri_encode();
 		}
 		images.push_back(d);
 	}
@@ -3118,7 +3118,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat
 			} else { // Relative path to an external image file.
 				ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER);
 				uri = uri.uri_decode();
-				uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows.
+				uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows.
 				// ResourceLoader will rely on the file extension to use the relevant loader.
 				// The spec says that if mimeType is defined, it should take precedence (e.g.
 				// there could be a `.png` image which is actually JPEG), but there's no easy

+ 2 - 2
modules/mono/csharp_script.cpp

@@ -694,7 +694,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
 		}
 
 		assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir()
-								.plus_file(assembly_name + ".dll");
+								.path_join(assembly_name + ".dll");
 		assembly_path = ProjectSettings::get_singleton()->globalize_path(assembly_path);
 
 		if (!FileAccess::exists(assembly_path)) {
@@ -1085,7 +1085,7 @@ void CSharpLanguage::_editor_init_callback() {
 	const void **interop_funcs = godotsharp::get_editor_interop_funcs(interop_funcs_size);
 
 	Object *editor_plugin_obj = GDMono::get_singleton()->get_plugin_callbacks().LoadToolsAssemblyCallback(
-			GodotSharpDirs::get_data_editor_tools_dir().plus_file("GodotTools.dll").utf16(),
+			GodotSharpDirs::get_data_editor_tools_dir().path_join("GodotTools.dll").utf16(),
 			interop_funcs, interop_funcs_size);
 	CRASH_COND(editor_plugin_obj == nullptr);
 

+ 3 - 3
modules/mono/editor/bindings_generator.cpp

@@ -1315,7 +1315,7 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
 
 	// Generate GodotSharp source files
 
-	String core_proj_dir = output_dir.plus_file(CORE_API_ASSEMBLY_NAME);
+	String core_proj_dir = output_dir.path_join(CORE_API_ASSEMBLY_NAME);
 
 	proj_err = generate_cs_core_project(core_proj_dir);
 	if (proj_err != OK) {
@@ -1325,7 +1325,7 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
 
 	// Generate GodotSharpEditor source files
 
-	String editor_proj_dir = output_dir.plus_file(EDITOR_API_ASSEMBLY_NAME);
+	String editor_proj_dir = output_dir.path_join(EDITOR_API_ASSEMBLY_NAME);
 
 	proj_err = generate_cs_editor_project(editor_proj_dir);
 	if (proj_err != OK) {
@@ -3880,7 +3880,7 @@ static void handle_cmdline_options(String glue_dir_path) {
 
 	CRASH_COND(glue_dir_path.is_empty());
 
-	if (bindings_generator.generate_cs_api(glue_dir_path.plus_file(API_SOLUTION_NAME)) != OK) {
+	if (bindings_generator.generate_cs_api(glue_dir_path.path_join(API_SOLUTION_NAME)) != OK) {
 		ERR_PRINT(generate_all_glue_option + ": Failed to generate the C# API.");
 	}
 }

+ 2 - 2
modules/mono/editor/code_completion.cpp

@@ -163,9 +163,9 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
 					}
 
 					if (dir_access->dir_exists(filename)) {
-						directories.push_back(dir_access->get_current_dir().plus_file(filename));
+						directories.push_back(dir_access->get_current_dir().path_join(filename));
 					} else if (filename.ends_with(".tscn") || filename.ends_with(".scn")) {
-						suggestions.push_back(quoted(dir_access->get_current_dir().plus_file(filename)));
+						suggestions.push_back(quoted(dir_access->get_current_dir().path_join(filename)));
 					}
 
 					filename = dir_access->get_next();

+ 1 - 1
modules/mono/editor/editor_internal_calls.cpp

@@ -98,7 +98,7 @@ bool godot_icall_EditorProgress_Step(const godot_string *p_task, const godot_str
 }
 
 void godot_icall_Internal_FullExportTemplatesDir(godot_string *r_dest) {
-	String full_templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
+	String full_templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG);
 	memnew_placement(r_dest, String(full_templates_dir));
 }
 

+ 39 - 39
modules/mono/godotsharp_dirs.cpp

@@ -64,7 +64,7 @@ String _get_expected_build_config() {
 String _get_mono_user_dir() {
 #ifdef TOOLS_ENABLED
 	if (EditorPaths::get_singleton()) {
-		return EditorPaths::get_singleton()->get_data_dir().plus_file("mono");
+		return EditorPaths::get_singleton()->get_data_dir().path_join("mono");
 	} else {
 		String settings_path;
 
@@ -72,23 +72,23 @@ String _get_mono_user_dir() {
 		String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir();
 
 		// On macOS, look outside .app bundle, since .app bundle is read-only.
-		if (OS::get_singleton()->has_feature("macos") && exe_dir.ends_with("MacOS") && exe_dir.plus_file("..").simplify_path().ends_with("Contents")) {
-			exe_dir = exe_dir.plus_file("../../..").simplify_path();
+		if (OS::get_singleton()->has_feature("macos") && exe_dir.ends_with("MacOS") && exe_dir.path_join("..").simplify_path().ends_with("Contents")) {
+			exe_dir = exe_dir.path_join("../../..").simplify_path();
 		}
 
 		Ref<DirAccess> d = DirAccess::create_for_path(exe_dir);
 
 		if (d->file_exists("._sc_") || d->file_exists("_sc_")) {
 			// contain yourself
-			settings_path = exe_dir.plus_file("editor_data");
+			settings_path = exe_dir.path_join("editor_data");
 		} else {
-			settings_path = OS::get_singleton()->get_data_path().plus_file(OS::get_singleton()->get_godot_dir_name());
+			settings_path = OS::get_singleton()->get_data_path().path_join(OS::get_singleton()->get_godot_dir_name());
 		}
 
-		return settings_path.plus_file("mono");
+		return settings_path.path_join("mono");
 	}
 #else
-	return OS::get_singleton()->get_user_data_dir().plus_file("mono");
+	return OS::get_singleton()->get_user_data_dir().path_join("mono");
 #endif
 }
 
@@ -126,27 +126,27 @@ public:
 
 private:
 	_GodotSharpDirs() {
-		res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().plus_file("mono");
-		res_metadata_dir = res_data_dir.plus_file("metadata");
-		res_config_dir = res_data_dir.plus_file("etc").plus_file("mono");
+		res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().path_join("mono");
+		res_metadata_dir = res_data_dir.path_join("metadata");
+		res_config_dir = res_data_dir.path_join("etc").path_join("mono");
 
 		// TODO use paths from csproj
-		res_temp_dir = res_data_dir.plus_file("temp");
-		res_temp_assemblies_base_dir = res_temp_dir.plus_file("bin");
-		res_temp_assemblies_dir = res_temp_assemblies_base_dir.plus_file(_get_expected_build_config());
+		res_temp_dir = res_data_dir.path_join("temp");
+		res_temp_assemblies_base_dir = res_temp_dir.path_join("bin");
+		res_temp_assemblies_dir = res_temp_assemblies_base_dir.path_join(_get_expected_build_config());
 
-		api_assemblies_base_dir = res_data_dir.plus_file("assemblies");
+		api_assemblies_base_dir = res_data_dir.path_join("assemblies");
 
 #ifdef WEB_ENABLED
 		mono_user_dir = "user://";
 #else
 		mono_user_dir = _get_mono_user_dir();
 #endif
-		mono_logs_dir = mono_user_dir.plus_file("mono_logs");
+		mono_logs_dir = mono_user_dir.path_join("mono_logs");
 
 #ifdef TOOLS_ENABLED
-		mono_solutions_dir = mono_user_dir.plus_file("solutions");
-		build_logs_dir = mono_user_dir.plus_file("build_logs");
+		mono_solutions_dir = mono_user_dir.path_join("solutions");
+		build_logs_dir = mono_user_dir.path_join("build_logs");
 
 		String base_path = ProjectSettings::get_singleton()->globalize_path("res://");
 #endif
@@ -155,35 +155,35 @@ private:
 
 #ifdef TOOLS_ENABLED
 
-		String data_dir_root = exe_dir.plus_file("GodotSharp");
-		data_editor_tools_dir = data_dir_root.plus_file("Tools");
-		api_assemblies_base_dir = data_dir_root.plus_file("Api");
+		String data_dir_root = exe_dir.path_join("GodotSharp");
+		data_editor_tools_dir = data_dir_root.path_join("Tools");
+		api_assemblies_base_dir = data_dir_root.path_join("Api");
 
-		String data_mono_root_dir = data_dir_root.plus_file("Mono");
-		data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
+		String data_mono_root_dir = data_dir_root.path_join("Mono");
+		data_mono_etc_dir = data_mono_root_dir.path_join("etc");
 
 #ifdef ANDROID_ENABLED
 		data_mono_lib_dir = gdmono::android::support::get_app_native_lib_dir();
 #else
-		data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
+		data_mono_lib_dir = data_mono_root_dir.path_join("lib");
 #endif
 
 #ifdef WINDOWS_ENABLED
-		data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
+		data_mono_bin_dir = data_mono_root_dir.path_join("bin");
 #endif
 
 #ifdef MACOS_ENABLED
 		if (!DirAccess::exists(data_editor_tools_dir)) {
-			data_editor_tools_dir = exe_dir.plus_file("../Resources/GodotSharp/Tools");
+			data_editor_tools_dir = exe_dir.path_join("../Resources/GodotSharp/Tools");
 		}
 
 		if (!DirAccess::exists(api_assemblies_base_dir)) {
-			api_assemblies_base_dir = exe_dir.plus_file("../Resources/GodotSharp/Api");
+			api_assemblies_base_dir = exe_dir.path_join("../Resources/GodotSharp/Api");
 		}
 
 		if (!DirAccess::exists(data_mono_root_dir)) {
-			data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc");
-			data_mono_lib_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/lib");
+			data_mono_etc_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/etc");
+			data_mono_lib_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/lib");
 		}
 #endif
 
@@ -191,40 +191,40 @@ private:
 
 		String appname = ProjectSettings::get_singleton()->get("application/config/name");
 		String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
-		String data_dir_root = exe_dir.plus_file("data_" + appname_safe);
+		String data_dir_root = exe_dir.path_join("data_" + appname_safe);
 		if (!DirAccess::exists(data_dir_root)) {
-			data_dir_root = exe_dir.plus_file("data_Godot");
+			data_dir_root = exe_dir.path_join("data_Godot");
 		}
 
-		String data_mono_root_dir = data_dir_root.plus_file("Mono");
-		data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
+		String data_mono_root_dir = data_dir_root.path_join("Mono");
+		data_mono_etc_dir = data_mono_root_dir.path_join("etc");
 
 #ifdef ANDROID_ENABLED
 		data_mono_lib_dir = gdmono::android::support::get_app_native_lib_dir();
 #else
-		data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
-		data_game_assemblies_dir = data_dir_root.plus_file("Assemblies");
+		data_mono_lib_dir = data_mono_root_dir.path_join("lib");
+		data_game_assemblies_dir = data_dir_root.path_join("Assemblies");
 #endif
 
 #ifdef WINDOWS_ENABLED
-		data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
+		data_mono_bin_dir = data_mono_root_dir.path_join("bin");
 #endif
 
 #ifdef MACOS_ENABLED
 		if (!DirAccess::exists(data_mono_root_dir)) {
-			data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc");
-			data_mono_lib_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/lib");
+			data_mono_etc_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/etc");
+			data_mono_lib_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/lib");
 		}
 
 		if (!DirAccess::exists(data_game_assemblies_dir)) {
-			data_game_assemblies_dir = exe_dir.plus_file("../Resources/GodotSharp/Assemblies");
+			data_game_assemblies_dir = exe_dir.path_join("../Resources/GodotSharp/Assemblies");
 		}
 #endif
 
 #endif
 
 #ifdef TOOLS_ENABLED
-		api_assemblies_dir = api_assemblies_base_dir.plus_file(GDMono::get_expected_api_build_config());
+		api_assemblies_dir = api_assemblies_base_dir.path_join(GDMono::get_expected_api_build_config());
 #else
 		api_assemblies_dir = data_dir_root;
 #endif

+ 10 - 10
modules/mono/mono_gd/gd_mono.cpp

@@ -173,13 +173,13 @@ String find_hostfxr() {
 
 #if defined(WINDOWS_ENABLED)
 	String probe_path = GodotSharpDirs::get_api_assemblies_dir()
-								.plus_file("hostfxr.dll");
+								.path_join("hostfxr.dll");
 #elif defined(MACOS_ENABLED)
 	String probe_path = GodotSharpDirs::get_api_assemblies_dir()
-								.plus_file("libhostfxr.dylib");
+								.path_join("libhostfxr.dylib");
 #elif defined(UNIX_ENABLED)
 	String probe_path = GodotSharpDirs::get_api_assemblies_dir()
-								.plus_file("libhostfxr.so");
+								.path_join("libhostfxr.so");
 #else
 #error "Platform not supported (yet?)"
 #endif
@@ -305,10 +305,10 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
 	godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
 
 	HostFxrCharString godot_plugins_path = str_to_hostfxr(
-			GodotSharpDirs::get_api_assemblies_dir().plus_file("GodotPlugins.dll"));
+			GodotSharpDirs::get_api_assemblies_dir().path_join("GodotPlugins.dll"));
 
 	HostFxrCharString config_path = str_to_hostfxr(
-			GodotSharpDirs::get_api_assemblies_dir().plus_file("GodotPlugins.runtimeconfig.json"));
+			GodotSharpDirs::get_api_assemblies_dir().path_join("GodotPlugins.runtimeconfig.json"));
 
 	load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer =
 			initialize_hostfxr_for_config(get_data(config_path));
@@ -345,7 +345,7 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime
 	String assembly_name = get_assembly_name();
 
 	HostFxrCharString assembly_path = str_to_hostfxr(GodotSharpDirs::get_api_assemblies_dir()
-															 .plus_file(assembly_name + ".dll"));
+															 .path_join(assembly_name + ".dll"));
 
 	load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer =
 			initialize_hostfxr_self_contained(get_data(assembly_path));
@@ -370,11 +370,11 @@ godot_plugins_initialize_fn try_load_native_aot_library(void *&r_aot_dll_handle)
 	String assembly_name = get_assembly_name();
 
 #if defined(WINDOWS_ENABLED)
-	String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().plus_file(assembly_name + ".dll");
+	String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dll");
 #elif defined(MACOS_ENABLED)
-	String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().plus_file(assembly_name + ".dylib");
+	String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dylib");
 #elif defined(UNIX_ENABLED)
-	String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().plus_file(assembly_name + ".so");
+	String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".so");
 #else
 #error "Platform not supported (yet?)"
 #endif
@@ -514,7 +514,7 @@ bool GDMono::_load_project_assembly() {
 	}
 
 	String assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir()
-								   .plus_file(assembly_name + ".dll");
+								   .path_join(assembly_name + ".dll");
 	assembly_path = ProjectSettings::get_singleton()->globalize_path(assembly_path);
 
 	if (!FileAccess::exists(assembly_path)) {

+ 1 - 1
modules/mono/utils/path_utils.cpp

@@ -205,7 +205,7 @@ String relative_to_impl(const String &p_path, const String &p_relative_to) {
 			return p_path;
 		}
 
-		return String("..").plus_file(relative_to_impl(p_path, base_dir));
+		return String("..").path_join(relative_to_impl(p_path, base_dir));
 	}
 }
 

+ 1 - 1
platform/android/dir_access_jandroid.cpp

@@ -169,7 +169,7 @@ String DirAccessJAndroid::get_absolute_path(String p_path) {
 	}
 
 	if (p_path.is_relative_path()) {
-		p_path = get_current_dir().plus_file(p_path);
+		p_path = get_current_dir().path_join(p_path);
 	}
 
 	p_path = fix_path(p_path);

+ 17 - 17
platform/android/export/export_plugin.cpp

@@ -624,7 +624,7 @@ Vector<String> EditorExportPlatformAndroid::list_gdap_files(const String &p_path
 Vector<PluginConfigAndroid> EditorExportPlatformAndroid::get_plugins() {
 	Vector<PluginConfigAndroid> loaded_plugins;
 
-	String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins");
+	String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().path_join("android/plugins");
 
 	// Add the prebuilt plugins
 	loaded_plugins.append_array(PluginConfigAndroid::get_prebuilt_plugins(plugins_dir));
@@ -635,7 +635,7 @@ Vector<PluginConfigAndroid> EditorExportPlatformAndroid::get_plugins() {
 		if (!plugins_filenames.is_empty()) {
 			Ref<ConfigFile> config_file = memnew(ConfigFile);
 			for (int i = 0; i < plugins_filenames.size(); i++) {
-				PluginConfigAndroid config = PluginConfigAndroid::load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i]));
+				PluginConfigAndroid config = PluginConfigAndroid::load_plugin_config(config_file, plugins_dir.path_join(plugins_filenames[i]));
 				if (config.valid_config) {
 					loaded_plugins.push_back(config);
 				} else {
@@ -696,7 +696,7 @@ Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObj
 		if (abi_index != -1) {
 			exported = true;
 			String abi = abis[abi_index];
-			String dst_path = String("lib").plus_file(abi).plus_file(p_so.path.get_file());
+			String dst_path = String("lib").path_join(abi).path_join(p_so.path.get_file());
 			Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path);
 			Error store_err = store_in_apk(ed, dst_path, array);
 			ERR_FAIL_COND_V_MSG(store_err, store_err, "Cannot store in apk file '" + dst_path + "'.");
@@ -737,7 +737,7 @@ Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const Shared
 			String type = export_data->debug ? "debug" : "release";
 			String abi = abis[abi_index];
 			String filename = p_so.path.get_file();
-			String dst_path = base.plus_file(type).plus_file(abi).plus_file(filename);
+			String dst_path = base.path_join(type).path_join(abi).path_join(filename);
 			Vector<uint8_t> data = FileAccess::get_file_as_array(p_so.path);
 			print_verbose("Copying .so file from " + p_so.path + " to " + dst_path);
 			Error err = store_file_at_path(dst_path, data);
@@ -1851,7 +1851,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
 		p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST;
 	}
 
-	String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
+	String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
 
 #define CLEANUP_AND_RETURN(m_err)                         \
 	{                                                     \
@@ -2004,7 +2004,7 @@ String EditorExportPlatformAndroid::get_adb_path() {
 		exe_ext = ".exe";
 	}
 	String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
-	return sdk_path.plus_file("platform-tools/adb" + exe_ext);
+	return sdk_path.path_join("platform-tools/adb" + exe_ext);
 }
 
 String EditorExportPlatformAndroid::get_apksigner_path() {
@@ -2017,7 +2017,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
 	String apksigner_path = "";
 
 	Error errn;
-	String build_tools_dir = sdk_path.plus_file("build-tools");
+	String build_tools_dir = sdk_path.path_join("build-tools");
 	Ref<DirAccess> da = DirAccess::open(build_tools_dir, &errn);
 	if (errn != OK) {
 		print_error("Unable to open Android 'build-tools' directory.");
@@ -2030,7 +2030,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
 	while (!sub_dir.is_empty()) {
 		if (!sub_dir.begins_with(".") && da->current_is_dir()) {
 			// Check if the tool is here.
-			String tool_path = build_tools_dir.plus_file(sub_dir).plus_file(apksigner_command_name);
+			String tool_path = build_tools_dir.path_join(sub_dir).path_join(apksigner_command_name);
 			if (FileAccess::exists(tool_path)) {
 				apksigner_path = tool_path;
 				break;
@@ -2135,7 +2135,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
 	} else {
 		Error errn;
 		// Check for the platform-tools directory.
-		Ref<DirAccess> da = DirAccess::open(sdk_path.plus_file("platform-tools"), &errn);
+		Ref<DirAccess> da = DirAccess::open(sdk_path.path_join("platform-tools"), &errn);
 		if (errn != OK) {
 			err += TTR("Invalid Android SDK path in Editor Settings.");
 			err += TTR("Missing 'platform-tools' directory!");
@@ -2153,7 +2153,7 @@ bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<Edito
 		}
 
 		// Check for the build-tools directory.
-		Ref<DirAccess> build_tools_da = DirAccess::open(sdk_path.plus_file("build-tools"), &errn);
+		Ref<DirAccess> build_tools_da = DirAccess::open(sdk_path.path_join("build-tools"), &errn);
 		if (errn != OK) {
 			err += TTR("Invalid Android SDK path in Editor Settings.");
 			err += TTR("Missing 'build-tools' directory!");
@@ -2310,7 +2310,7 @@ String EditorExportPlatformAndroid::get_apk_expansion_fullpath(const Ref<EditorE
 	int version_code = p_preset->get("version/code");
 	String package_name = p_preset->get("package/unique_name");
 	String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb";
-	String fullpath = p_path.get_base_dir().plus_file(apk_file_name);
+	String fullpath = p_path.get_base_dir().path_join(apk_file_name);
 	return fullpath;
 }
 
@@ -2671,8 +2671,8 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
 		build_command = "gradlew";
 #endif
 
-		String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build");
-		build_command = build_path.plus_file(build_command);
+		String build_path = ProjectSettings::get_singleton()->get_resource_path().path_join("android/build");
+		build_command = build_path.path_join(build_command);
 
 		String package_name = get_package_name(p_preset->get("package/unique_name"));
 		String version_code = itos(p_preset->get("version/code"));
@@ -2742,7 +2742,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
 					debug_user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user");
 				}
 				if (debug_keystore.is_relative_path()) {
-					debug_keystore = OS::get_singleton()->get_resource_dir().plus_file(debug_keystore).simplify_path();
+					debug_keystore = OS::get_singleton()->get_resource_dir().path_join(debug_keystore).simplify_path();
 				}
 				if (!FileAccess::exists(debug_keystore)) {
 					add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not find keystore, unable to export."));
@@ -2758,7 +2758,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
 				String release_username = p_preset->get("keystore/release_user");
 				String release_password = p_preset->get("keystore/release_password");
 				if (release_keystore.is_relative_path()) {
-					release_keystore = OS::get_singleton()->get_resource_dir().plus_file(release_keystore).simplify_path();
+					release_keystore = OS::get_singleton()->get_resource_dir().path_join(release_keystore).simplify_path();
 				}
 				if (!FileAccess::exists(release_keystore)) {
 					add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not find keystore, unable to export."));
@@ -2793,7 +2793,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
 		String export_filename = p_path.get_file();
 		String export_path = p_path.get_base_dir();
 		if (export_path.is_relative_path()) {
-			export_path = OS::get_singleton()->get_resource_dir().plus_file(export_path);
+			export_path = OS::get_singleton()->get_resource_dir().path_join(export_path);
 		}
 		export_path = ProjectSettings::get_singleton()->globalize_path(export_path).simplify_path();
 
@@ -2852,7 +2852,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
 	Ref<FileAccess> io2_fa;
 	zlib_filefunc_def io2 = zipio_create_io(&io2_fa);
 
-	String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
+	String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
 
 #define CLEANUP_AND_RETURN(m_err)                            \
 	{                                                        \

+ 1 - 1
platform/android/export/godot_plugin_config.cpp

@@ -50,7 +50,7 @@ String PluginConfigAndroid::resolve_local_dependency_path(String plugin_config_d
 		if (dependency_path.is_absolute_path()) {
 			absolute_path = ProjectSettings::get_singleton()->globalize_path(dependency_path);
 		} else {
-			absolute_path = plugin_config_dir.plus_file(dependency_path);
+			absolute_path = plugin_config_dir.path_join(dependency_path);
 		}
 	}
 

+ 1 - 1
platform/android/os_android.cpp

@@ -362,7 +362,7 @@ void OS_Android::vibrate_handheld(int p_duration_ms) {
 }
 
 String OS_Android::get_config_path() const {
-	return get_user_data_dir().plus_file("config");
+	return get_user_data_dir().path_join("config");
 }
 
 bool OS_Android::_check_internal_feature_support(const String &p_feature) {

+ 18 - 18
platform/ios/export/export_plugin.cpp

@@ -649,7 +649,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
 
 	if (custom_launch_image_2x.length() > 0 && custom_launch_image_3x.length() > 0) {
 		Ref<Image> image;
-		String image_path = p_dest_dir.plus_file("[email protected]");
+		String image_path = p_dest_dir.path_join("[email protected]");
 		image.instantiate();
 		Error err = image->load(custom_launch_image_2x);
 
@@ -663,7 +663,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
 		}
 
 		image.unref();
-		image_path = p_dest_dir.plus_file("[email protected]");
+		image_path = p_dest_dir.path_join("[email protected]");
 		image.instantiate();
 		err = image->load(custom_launch_image_3x);
 
@@ -696,8 +696,8 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
 		// because Godot's own boot logo uses single image for all resolutions.
 		// Also not using @1x image, because devices using this image variant
 		// are not supported by iOS 9, which is minimal target.
-		const String splash_png_path_2x = p_dest_dir.plus_file("[email protected]");
-		const String splash_png_path_3x = p_dest_dir.plus_file("[email protected]");
+		const String splash_png_path_2x = p_dest_dir.path_join("[email protected]");
+		const String splash_png_path_3x = p_dest_dir.path_join("[email protected]");
 
 		if (splash->save_png(splash_png_path_2x) != OK) {
 			return ERR_FILE_CANT_WRITE;
@@ -812,7 +812,7 @@ Error EditorExportPlatformIOS::_walk_dir_recursive(Ref<DirAccess> &p_da, FileHan
 				dirs.push_back(path);
 			}
 		} else {
-			Error err = p_handler(current_dir.plus_file(path), p_userdata);
+			Error err = p_handler(current_dir.path_join(path), p_userdata);
 			if (err) {
 				p_da->list_dir_end();
 				return err;
@@ -1028,7 +1028,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
 	if (p_is_framework && p_asset.ends_with(".dylib")) {
 		// For iOS we need to turn .dylib into .framework
 		// to be able to send application to AppStore
-		asset_path = String("dylibs").plus_file(base_dir);
+		asset_path = String("dylibs").path_join(base_dir);
 
 		String file_name;
 
@@ -1040,12 +1040,12 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
 
 		String framework_name = file_name + ".framework";
 
-		asset_path = asset_path.plus_file(framework_name);
-		destination_dir = p_out_dir.plus_file(asset_path);
-		destination = destination_dir.plus_file(file_name);
+		asset_path = asset_path.path_join(framework_name);
+		destination_dir = p_out_dir.path_join(asset_path);
+		destination = destination_dir.path_join(file_name);
 		create_framework = true;
 	} else if (p_is_framework && (p_asset.ends_with(".framework") || p_asset.ends_with(".xcframework"))) {
-		asset_path = String("dylibs").plus_file(base_dir);
+		asset_path = String("dylibs").path_join(base_dir);
 
 		String file_name;
 
@@ -1055,8 +1055,8 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
 			file_name = *p_custom_file_name;
 		}
 
-		asset_path = asset_path.plus_file(file_name);
-		destination_dir = p_out_dir.plus_file(asset_path);
+		asset_path = asset_path.path_join(file_name);
+		destination_dir = p_out_dir.path_join(asset_path);
 		destination = destination_dir;
 	} else {
 		asset_path = base_dir;
@@ -1069,9 +1069,9 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
 			file_name = *p_custom_file_name;
 		}
 
-		destination_dir = p_out_dir.plus_file(asset_path);
-		asset_path = asset_path.plus_file(file_name);
-		destination = p_out_dir.plus_file(asset_path);
+		destination_dir = p_out_dir.path_join(asset_path);
+		asset_path = asset_path.path_join(file_name);
+		destination = p_out_dir.path_join(asset_path);
 	}
 
 	Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
@@ -1088,7 +1088,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
 	if (err) {
 		return err;
 	}
-	IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework, p_should_embed };
+	IOSExportAsset exported_asset = { binary_name.path_join(asset_path), p_is_framework, p_should_embed };
 	r_exported_assets.push_back(exported_asset);
 
 	if (create_framework) {
@@ -1106,7 +1106,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
 		{
 			List<String> install_name_args;
 			install_name_args.push_back("-id");
-			install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name));
+			install_name_args.push_back(String("@rpath").path_join(framework_name).path_join(file_name));
 			install_name_args.push_back(destination);
 
 			OS::get_singleton()->execute("install_name_tool", install_name_args);
@@ -1141,7 +1141,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
 
 			String info_plist = info_plist_format.replace("$name", file_name);
 
-			Ref<FileAccess> f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE);
+			Ref<FileAccess> f = FileAccess::open(destination_dir.path_join("Info.plist"), FileAccess::WRITE);
 			if (f.is_valid()) {
 				f->store_string(info_plist);
 			}

+ 4 - 4
platform/ios/export/export_plugin.h

@@ -238,9 +238,9 @@ public:
 
 				if (da->current_is_dir()) {
 					if (p_check_directories) {
-						Vector<String> directory_files = list_plugin_config_files(p_path.plus_file(file), false);
+						Vector<String> directory_files = list_plugin_config_files(p_path.path_join(file), false);
 						for (int i = 0; i < directory_files.size(); ++i) {
-							dir_files.push_back(file.plus_file(directory_files[i]));
+							dir_files.push_back(file.path_join(directory_files[i]));
 						}
 					}
 
@@ -260,7 +260,7 @@ public:
 	static Vector<PluginConfigIOS> get_plugins() {
 		Vector<PluginConfigIOS> loaded_plugins;
 
-		String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("ios/plugins");
+		String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().path_join("ios/plugins");
 
 		if (DirAccess::exists(plugins_dir)) {
 			Vector<String> plugins_filenames = list_plugin_config_files(plugins_dir, true);
@@ -268,7 +268,7 @@ public:
 			if (!plugins_filenames.is_empty()) {
 				Ref<ConfigFile> config_file = memnew(ConfigFile);
 				for (int i = 0; i < plugins_filenames.size(); i++) {
-					PluginConfigIOS config = PluginConfigIOS::load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i]));
+					PluginConfigIOS config = PluginConfigIOS::load_plugin_config(config_file, plugins_dir.path_join(plugins_filenames[i]));
 					if (config.valid_config) {
 						loaded_plugins.push_back(config);
 					} else {

+ 7 - 7
platform/ios/export/godot_plugin_config.cpp

@@ -46,7 +46,7 @@ String PluginConfigIOS::resolve_local_dependency_path(String plugin_config_dir,
 	}
 
 	String res_path = ProjectSettings::get_singleton()->globalize_path("res://");
-	absolute_path = plugin_config_dir.plus_file(dependency_path);
+	absolute_path = plugin_config_dir.path_join(dependency_path);
 
 	return absolute_path.replace(res_path, "res://");
 }
@@ -64,7 +64,7 @@ String PluginConfigIOS::resolve_system_dependency_path(String dependency_path) {
 
 	String system_path = "/System/Library/Frameworks";
 
-	return system_path.plus_file(dependency_path);
+	return system_path.path_join(dependency_path);
 }
 
 Vector<String> PluginConfigIOS::resolve_local_dependencies(String plugin_config_dir, Vector<String> p_paths) {
@@ -121,8 +121,8 @@ bool PluginConfigIOS::validate_plugin(PluginConfigIOS &plugin_config) {
 		String file_path = plugin_config.binary.get_base_dir();
 		String file_name = plugin_config.binary.get_basename().get_file();
 		String file_extension = plugin_config.binary.get_extension();
-		String release_file_name = file_path.plus_file(file_name + ".release." + file_extension);
-		String debug_file_name = file_path.plus_file(file_name + ".debug." + file_extension);
+		String release_file_name = file_path.path_join(file_name + ".release." + file_extension);
+		String debug_file_name = file_path.path_join(file_name + ".debug." + file_extension);
 
 		if ((plugin_extension == "a" && FileAccess::exists(release_file_name) && FileAccess::exists(debug_file_name)) ||
 				(plugin_extension == "xcframework" && DirAccess::exists(release_file_name) && DirAccess::exists(debug_file_name))) {
@@ -144,7 +144,7 @@ String PluginConfigIOS::get_plugin_main_binary(PluginConfigIOS &plugin_config, b
 	String plugin_extension = plugin_config.binary.get_extension();
 	String plugin_file = plugin_name_prefix + "." + (p_debug ? "debug" : "release") + "." + plugin_extension;
 
-	return plugin_binary_dir.plus_file(plugin_file);
+	return plugin_binary_dir.path_join(plugin_file);
 }
 
 uint64_t PluginConfigIOS::get_plugin_modification_time(const PluginConfigIOS &plugin_config, const String &config_path) {
@@ -156,8 +156,8 @@ uint64_t PluginConfigIOS::get_plugin_modification_time(const PluginConfigIOS &pl
 		String file_path = plugin_config.binary.get_base_dir();
 		String file_name = plugin_config.binary.get_basename().get_file();
 		String plugin_extension = plugin_config.binary.get_extension();
-		String release_file_name = file_path.plus_file(file_name + ".release." + plugin_extension);
-		String debug_file_name = file_path.plus_file(file_name + ".debug." + plugin_extension);
+		String release_file_name = file_path.path_join(file_name + ".release." + plugin_extension);
+		String debug_file_name = file_path.path_join(file_name + ".debug." + plugin_extension);
 
 		last_updated = MAX(last_updated, FileAccess::get_modified_time(release_file_name));
 		last_updated = MAX(last_updated, FileAccess::get_modified_time(debug_file_name));

+ 7 - 7
platform/linuxbsd/os_linuxbsd.cpp

@@ -65,7 +65,7 @@ void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) {
 
 	for (int i = 0; i < path_elems.size(); i++) {
 		for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) {
-			String tested_path = path_elems[i].plus_file(message_programs[k]);
+			String tested_path = path_elems[i].path_join(message_programs[k]);
 
 			if (FileAccess::exists(tested_path)) {
 				program = tested_path;
@@ -432,10 +432,10 @@ String OS_LinuxBSD::get_config_path() const {
 			return get_environment("XDG_CONFIG_HOME");
 		} else {
 			WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.config` or `.` per the XDG Base Directory specification.");
-			return has_environment("HOME") ? get_environment("HOME").plus_file(".config") : ".";
+			return has_environment("HOME") ? get_environment("HOME").path_join(".config") : ".";
 		}
 	} else if (has_environment("HOME")) {
-		return get_environment("HOME").plus_file(".config");
+		return get_environment("HOME").path_join(".config");
 	} else {
 		return ".";
 	}
@@ -447,10 +447,10 @@ String OS_LinuxBSD::get_data_path() const {
 			return get_environment("XDG_DATA_HOME");
 		} else {
 			WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.local/share` or `get_config_path()` per the XDG Base Directory specification.");
-			return has_environment("HOME") ? get_environment("HOME").plus_file(".local/share") : get_config_path();
+			return has_environment("HOME") ? get_environment("HOME").path_join(".local/share") : get_config_path();
 		}
 	} else if (has_environment("HOME")) {
-		return get_environment("HOME").plus_file(".local/share");
+		return get_environment("HOME").path_join(".local/share");
 	} else {
 		return get_config_path();
 	}
@@ -462,10 +462,10 @@ String OS_LinuxBSD::get_cache_path() const {
 			return get_environment("XDG_CACHE_HOME");
 		} else {
 			WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.cache` or `get_config_path()` per the XDG Base Directory specification.");
-			return has_environment("HOME") ? get_environment("HOME").plus_file(".cache") : get_config_path();
+			return has_environment("HOME") ? get_environment("HOME").path_join(".cache") : get_config_path();
 		}
 	} else if (has_environment("HOME")) {
-		return get_environment("HOME").plus_file(".cache");
+		return get_environment("HOME").path_join(".cache");
 	} else {
 		return get_config_path();
 	}

+ 1 - 1
platform/macos/dir_access_macos.mm

@@ -69,7 +69,7 @@ String DirAccessMacOS::get_drive(int p_drive) {
 }
 
 bool DirAccessMacOS::is_hidden(const String &p_name) {
-	String f = get_current_dir().plus_file(p_name);
+	String f = get_current_dir().path_join(p_name);
 	NSURL *url = [NSURL fileURLWithPath:@(f.utf8().get_data())];
 	NSNumber *hidden = nil;
 	if (![url getResourceValue:&hidden forKey:NSURLIsHiddenKey error:nil]) {

+ 41 - 41
platform/macos/export/codesign.cpp

@@ -172,7 +172,7 @@ bool CodeSignCodeResources::add_file1(const String &p_root, const String &p_path
 	f.name = p_path;
 	f.optional = (found == CRMatch::CR_MATCH_OPTIONAL);
 	f.nested = false;
-	f.hash = hash_sha1_base64(p_root.plus_file(p_path));
+	f.hash = hash_sha1_base64(p_root.path_join(p_path));
 	print_verbose(vformat("CodeSign/CodeResources: File(V1) %s hash1:%s", f.name, f.hash));
 
 	files1.push_back(f);
@@ -182,7 +182,7 @@ bool CodeSignCodeResources::add_file1(const String &p_root, const String &p_path
 bool CodeSignCodeResources::add_file2(const String &p_root, const String &p_path) {
 	CRMatch found = match_rules2(p_path);
 	if (found == CRMatch::CR_MATCH_NESTED) {
-		return add_nested_file(p_root, p_path, p_root.plus_file(p_path));
+		return add_nested_file(p_root, p_path, p_root.path_join(p_path));
 	}
 	if (found != CRMatch::CR_MATCH_YES && found != CRMatch::CR_MATCH_OPTIONAL) {
 		return true; // No match.
@@ -192,8 +192,8 @@ bool CodeSignCodeResources::add_file2(const String &p_root, const String &p_path
 	f.name = p_path;
 	f.optional = (found == CRMatch::CR_MATCH_OPTIONAL);
 	f.nested = false;
-	f.hash = hash_sha1_base64(p_root.plus_file(p_path));
-	f.hash2 = hash_sha256_base64(p_root.plus_file(p_path));
+	f.hash = hash_sha1_base64(p_root.path_join(p_path));
+	f.hash2 = hash_sha256_base64(p_root.path_join(p_path));
 
 	print_verbose(vformat("CodeSign/CodeResources: File(V2) %s hash1:%s hash2:%s", f.name, f.hash, f.hash2));
 
@@ -214,17 +214,17 @@ bool CodeSignCodeResources::add_nested_file(const String &p_root, const String &
 
 	Vector<String> files_to_add;
 	if (LipO::is_lipo(p_exepath)) {
-		String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file("_lipo");
+		String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().path_join("_lipo");
 		Error err = da->make_dir_recursive(tmp_path_name);
 		ERR_FAIL_COND_V_MSG(err != OK, false, vformat("CodeSign/CodeResources: Failed to create \"%s\" subfolder.", tmp_path_name));
 		LipO lip;
 		if (lip.open_file(p_exepath)) {
 			for (int i = 0; i < lip.get_arch_count(); i++) {
-				if (!lip.extract_arch(i, tmp_path_name.plus_file("_rqexe_" + itos(i)))) {
+				if (!lip.extract_arch(i, tmp_path_name.path_join("_rqexe_" + itos(i)))) {
 					CLEANUP();
 					ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Failed to extract thin binary.");
 				}
-				files_to_add.push_back(tmp_path_name.plus_file("_rqexe_" + itos(i)));
+				files_to_add.push_back(tmp_path_name.path_join("_rqexe_" + itos(i)));
 			}
 		}
 	} else if (MachO::is_macho(p_exepath)) {
@@ -285,7 +285,7 @@ bool CodeSignCodeResources::add_nested_file(const String &p_root, const String &
 bool CodeSignCodeResources::add_folder_recursive(const String &p_root, const String &p_path, const String &p_main_exe_path) {
 	Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 	ERR_FAIL_COND_V(da.is_null(), false);
-	Error err = da->change_dir(p_root.plus_file(p_path));
+	Error err = da->change_dir(p_root.path_join(p_path));
 	ERR_FAIL_COND_V(err != OK, false);
 
 	bool ret = true;
@@ -293,27 +293,27 @@ bool CodeSignCodeResources::add_folder_recursive(const String &p_root, const Str
 	String n = da->get_next();
 	while (n != String()) {
 		if (n != "." && n != "..") {
-			String path = p_root.plus_file(p_path).plus_file(n);
+			String path = p_root.path_join(p_path).path_join(n);
 			if (path == p_main_exe_path) {
 				n = da->get_next();
 				continue; // Skip main executable.
 			}
 			if (da->current_is_dir()) {
-				CRMatch found = match_rules2(p_path.plus_file(n));
+				CRMatch found = match_rules2(p_path.path_join(n));
 				String fmw_ver = "Current"; // Framework version (default).
 				String info_path;
 				String main_exe;
 				bool bundle = false;
-				if (da->file_exists(path.plus_file("Contents/Info.plist"))) {
-					info_path = path.plus_file("Contents/Info.plist");
-					main_exe = path.plus_file("Contents/MacOS");
+				if (da->file_exists(path.path_join("Contents/Info.plist"))) {
+					info_path = path.path_join("Contents/Info.plist");
+					main_exe = path.path_join("Contents/MacOS");
 					bundle = true;
-				} else if (da->file_exists(path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) {
-					info_path = path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver));
-					main_exe = path.plus_file(vformat("Versions/%s", fmw_ver));
+				} else if (da->file_exists(path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) {
+					info_path = path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver));
+					main_exe = path.path_join(vformat("Versions/%s", fmw_ver));
 					bundle = true;
-				} else if (da->file_exists(path.plus_file("Info.plist"))) {
-					info_path = path.plus_file("Info.plist");
+				} else if (da->file_exists(path.path_join("Info.plist"))) {
+					info_path = path.path_join("Info.plist");
 					main_exe = path;
 					bundle = true;
 				}
@@ -322,20 +322,20 @@ bool CodeSignCodeResources::add_folder_recursive(const String &p_root, const Str
 					PList info_plist;
 					if (info_plist.load_file(info_path)) {
 						if (info_plist.get_root()->data_type == PList::PLNodeType::PL_NODE_TYPE_DICT && info_plist.get_root()->data_dict.has("CFBundleExecutable")) {
-							main_exe = main_exe.plus_file(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data()));
+							main_exe = main_exe.path_join(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data()));
 						} else {
 							ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Invalid Info.plist, no exe name.");
 						}
 					} else {
 						ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Invalid Info.plist, can't load.");
 					}
-					ret = ret && add_nested_file(p_root, p_path.plus_file(n), main_exe);
+					ret = ret && add_nested_file(p_root, p_path.path_join(n), main_exe);
 				} else {
-					ret = ret && add_folder_recursive(p_root, p_path.plus_file(n), p_main_exe_path);
+					ret = ret && add_folder_recursive(p_root, p_path.path_join(n), p_main_exe_path);
 				}
 			} else {
-				ret = ret && add_file1(p_root, p_path.plus_file(n));
-				ret = ret && add_file2(p_root, p_path.plus_file(n));
+				ret = ret && add_file1(p_root, p_path.path_join(n));
+				ret = ret && add_file2(p_root, p_path.path_join(n));
 			}
 		}
 
@@ -1222,7 +1222,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
 			}
 
 			if (info_plist.get_root()->data_type == PList::PLNodeType::PL_NODE_TYPE_DICT && info_plist.get_root()->data_dict.has("CFBundleExecutable")) {
-				main_exe = p_exe_path.plus_file(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data()));
+				main_exe = p_exe_path.path_join(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data()));
 			} else {
 				r_error_msg = TTR("Invalid Info.plist, no exe name.");
 				ERR_FAIL_V_MSG(FAILED, "CodeSign: Invalid Info.plist, no exe name.");
@@ -1244,7 +1244,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
 	Vector<String> files_to_sign;
 	if (LipO::is_lipo(main_exe)) {
 		print_verbose(vformat("CodeSign: Executable is fat, extracting..."));
-		String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file("_lipo");
+		String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().path_join("_lipo");
 		Error err = da->make_dir_recursive(tmp_path_name);
 		if (err != OK) {
 			r_error_msg = vformat(TTR("Failed to create \"%s\" subfolder."), tmp_path_name);
@@ -1253,12 +1253,12 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
 		LipO lip;
 		if (lip.open_file(main_exe)) {
 			for (int i = 0; i < lip.get_arch_count(); i++) {
-				if (!lip.extract_arch(i, tmp_path_name.plus_file("_exe_" + itos(i)))) {
+				if (!lip.extract_arch(i, tmp_path_name.path_join("_exe_" + itos(i)))) {
 					CLEANUP();
 					r_error_msg = TTR("Failed to extract thin binary.");
 					ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to extract thin binary.");
 				}
-				files_to_sign.push_back(tmp_path_name.plus_file("_exe_" + itos(i)));
+				files_to_sign.push_back(tmp_path_name.path_join("_exe_" + itos(i)));
 			}
 		}
 	} else if (MachO::is_macho(main_exe)) {
@@ -1338,15 +1338,15 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
 			r_error_msg = TTR("Failed to process nested resources.");
 			ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to process nested resources.");
 		}
-		Error err = da->make_dir_recursive(p_bundle_path.plus_file("_CodeSignature"));
+		Error err = da->make_dir_recursive(p_bundle_path.path_join("_CodeSignature"));
 		if (err != OK) {
 			CLEANUP();
 			r_error_msg = TTR("Failed to create _CodeSignature subfolder.");
 			ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to create _CodeSignature subfolder.");
 		}
-		cr.save_to_file(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources"));
-		res_hash1 = file_hash_sha1(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources"));
-		res_hash2 = file_hash_sha256(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources"));
+		cr.save_to_file(p_bundle_path.path_join("_CodeSignature").path_join("CodeResources"));
+		res_hash1 = file_hash_sha1(p_bundle_path.path_join("_CodeSignature").path_join("CodeResources"));
+		res_hash2 = file_hash_sha256(p_bundle_path.path_join("_CodeSignature").path_join("CodeResources"));
 		if (res_hash1.is_empty() || res_hash2.is_empty()) {
 			CLEANUP();
 			r_error_msg = TTR("Failed to get CodeResources hash.");
@@ -1530,18 +1530,18 @@ Error CodeSign::codesign(bool p_use_hardened_runtime, bool p_force, const String
 		String bundle_path;
 		bool bundle = false;
 		bool ios_bundle = false;
-		if (da->file_exists(p_path.plus_file("Contents/Info.plist"))) {
-			info_path = p_path.plus_file("Contents/Info.plist");
-			main_exe = p_path.plus_file("Contents/MacOS");
-			bundle_path = p_path.plus_file("Contents");
+		if (da->file_exists(p_path.path_join("Contents/Info.plist"))) {
+			info_path = p_path.path_join("Contents/Info.plist");
+			main_exe = p_path.path_join("Contents/MacOS");
+			bundle_path = p_path.path_join("Contents");
 			bundle = true;
-		} else if (da->file_exists(p_path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) {
-			info_path = p_path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver));
-			main_exe = p_path.plus_file(vformat("Versions/%s", fmw_ver));
-			bundle_path = p_path.plus_file(vformat("Versions/%s", fmw_ver));
+		} else if (da->file_exists(p_path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) {
+			info_path = p_path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver));
+			main_exe = p_path.path_join(vformat("Versions/%s", fmw_ver));
+			bundle_path = p_path.path_join(vformat("Versions/%s", fmw_ver));
 			bundle = true;
-		} else if (da->file_exists(p_path.plus_file("Info.plist"))) {
-			info_path = p_path.plus_file("Info.plist");
+		} else if (da->file_exists(p_path.path_join("Info.plist"))) {
+			info_path = p_path.path_join("Info.plist");
 			main_exe = p_path;
 			bundle_path = p_path;
 			bundle = true;

+ 16 - 16
platform/macos/export/export_plugin.cpp

@@ -305,7 +305,7 @@ void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint
 		if (icon_infos[i].is_png) {
 			// Encode PNG icon.
 			it->set_image(copy);
-			String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png");
+			String path = EditorPaths::get_singleton()->get_cache_dir().path_join("icon.png");
 			ResourceSaver::save(it, path);
 
 			{
@@ -766,7 +766,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
 	dir_access->list_dir_begin();
 	String current_file{ dir_access->get_next() };
 	while (!current_file.is_empty()) {
-		String current_file_path{ p_path.plus_file(current_file) };
+		String current_file_path{ p_path.path_join(current_file) };
 
 		if (current_file == ".." || current_file == ".") {
 			current_file = dir_access->get_next();
@@ -980,9 +980,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
 		tmp_app_path_name = p_path;
 		scr_path = p_path.get_basename() + ".command";
 	} else {
-		tmp_base_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name);
-		tmp_app_path_name = tmp_base_path_name.plus_file(tmp_app_dir_name);
-		scr_path = tmp_base_path_name.plus_file(pkg_name + ".command");
+		tmp_base_path_name = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name);
+		tmp_app_path_name = tmp_base_path_name.path_join(tmp_app_dir_name);
+		scr_path = tmp_base_path_name.path_join(pkg_name + ".command");
 	}
 
 	print_verbose("Exporting to " + tmp_app_path_name);
@@ -1189,7 +1189,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
 			add_message(EXPORT_MESSAGE_INFO, TTR("Export"), TTR("Relative symlinks are not supported on this OS, the exported project might be broken!"));
 #endif
 			// Handle symlinks in the archive.
-			file = tmp_app_path_name.plus_file(file);
+			file = tmp_app_path_name.path_join(file);
 			if (err == OK) {
 				err = tmp_app_dir->make_dir_recursive(file.get_base_dir());
 				if (err != OK) {
@@ -1273,7 +1273,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
 			print_verbose("ADDING: " + file + " size: " + itos(data.size()));
 
 			// Write it into our application bundle.
-			file = tmp_app_path_name.plus_file(file);
+			file = tmp_app_path_name.path_join(file);
 			if (err == OK) {
 				err = tmp_app_dir->make_dir_recursive(file.get_base_dir());
 				if (err != OK) {
@@ -1332,9 +1332,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
 		bool sign_enabled = (p_preset->get("codesign/codesign").operator int() > 0);
 
 		String ent_path = p_preset->get("codesign/entitlements/custom_file");
-		String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + "_helper.entitlements");
+		String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + "_helper.entitlements");
 		if (sign_enabled && (ent_path.is_empty())) {
-			ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
+			ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + ".entitlements");
 
 			Ref<FileAccess> ent_f = FileAccess::open(ent_path, FileAccess::WRITE);
 			if (ent_f.is_valid()) {
@@ -1529,7 +1529,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
 					String path_in_app = tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file();
 					err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true);
 				} else {
-					String path_in_app = tmp_app_path_name.plus_file(shared_objects[i].target).plus_file(src_path.get_file());
+					String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target).path_join(src_path.get_file());
 					err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, false);
 				}
 				if (err != OK) {
@@ -1630,7 +1630,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
 }
 
 void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
-	String dir = p_folder.is_empty() ? p_root_path : p_root_path.plus_file(p_folder);
+	String dir = p_folder.is_empty() ? p_root_path : p_root_path.path_join(p_folder);
 
 	Ref<DirAccess> da = DirAccess::open(dir);
 	da->list_dir_begin();
@@ -1660,7 +1660,7 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
 			zipfi.internal_fa = 0;
 
 			zipOpenNewFileInZip4(p_zip,
-					p_folder.plus_file(f).utf8().get_data(),
+					p_folder.path_join(f).utf8().get_data(),
 					&zipfi,
 					nullptr,
 					0,
@@ -1682,7 +1682,7 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
 			zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
 			zipCloseFileInZip(p_zip);
 		} else if (da->current_is_dir()) {
-			_zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name);
+			_zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name);
 		} else {
 			bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers") || f.ends_with(".command");
 
@@ -1705,7 +1705,7 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
 			zipfi.internal_fa = 0;
 
 			zipOpenNewFileInZip4(p_zip,
-					p_folder.plus_file(f).utf8().get_data(),
+					p_folder.path_join(f).utf8().get_data(),
 					&zipfi,
 					nullptr,
 					0,
@@ -1723,9 +1723,9 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
 					0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
 					0);
 
-			Ref<FileAccess> fa = FileAccess::open(dir.plus_file(f), FileAccess::READ);
+			Ref<FileAccess> fa = FileAccess::open(dir.path_join(f), FileAccess::READ);
 			if (fa.is_null()) {
-				add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.plus_file(f)));
+				add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.path_join(f)));
 				return;
 			}
 			const int bufsize = 16384;

+ 6 - 6
platform/macos/os_macos.mm

@@ -48,8 +48,8 @@
 _FORCE_INLINE_ String OS_MacOS::get_framework_executable(const String &p_path) {
 	// Append framework executable name, or return as is if p_path is not a framework.
 	Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
-	if (da->dir_exists(p_path) && da->file_exists(p_path.plus_file(p_path.get_file().get_basename()))) {
-		return p_path.plus_file(p_path.get_file().get_basename());
+	if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) {
+		return p_path.path_join(p_path.get_file().get_basename());
 	} else {
 		return p_path;
 	}
@@ -155,12 +155,12 @@ Error OS_MacOS::open_dynamic_library(const String p_path, void *&p_library_handl
 
 	if (!FileAccess::exists(path)) {
 		// Load .dylib or framework from within the executable path.
-		path = get_framework_executable(get_executable_path().get_base_dir().plus_file(p_path.get_file()));
+		path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file()));
 	}
 
 	if (!FileAccess::exists(path)) {
 		// Load .dylib or framework from a standard macOS location.
-		path = get_framework_executable(get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file()));
+		path = get_framework_executable(get_executable_path().get_base_dir().path_join("../Frameworks").path_join(p_path.get_file()));
 	}
 
 	p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
@@ -187,7 +187,7 @@ String OS_MacOS::get_config_path() const {
 		}
 	}
 	if (has_environment("HOME")) {
-		return get_environment("HOME").plus_file("Library/Application Support");
+		return get_environment("HOME").path_join("Library/Application Support");
 	}
 	return ".";
 }
@@ -214,7 +214,7 @@ String OS_MacOS::get_cache_path() const {
 		}
 	}
 	if (has_environment("HOME")) {
-		return get_environment("HOME").plus_file("Library/Caches");
+		return get_environment("HOME").path_join("Library/Caches");
 	}
 	return get_config_path();
 }

+ 2 - 2
platform/uwp/export/app_packager.cpp

@@ -408,7 +408,7 @@ void AppxPackager::finish() {
 	// Create and add block map file
 	EditorNode::progress_task_step("export", "Creating block map...", 4);
 
-	const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml");
+	const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpblockmap.xml");
 	make_block_map(tmp_blockmap_file_path);
 
 	{
@@ -425,7 +425,7 @@ void AppxPackager::finish() {
 
 	EditorNode::progress_task_step("export", "Setting content types...", 5);
 
-	const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml");
+	const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpcontenttypes.xml");
 	make_content_types(tmp_content_types_file_path);
 
 	{

+ 1 - 1
platform/uwp/export/export_plugin.h

@@ -329,7 +329,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
 			return data;
 		}
 
-		String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
+		String tmp_path = EditorPaths::get_singleton()->get_cache_dir().path_join("uwp_tmp_logo.png");
 
 		Error err = texture->get_image()->save_png(tmp_path);
 

+ 2 - 2
platform/web/api/web_tools_editor_plugin.cpp

@@ -76,7 +76,7 @@ void WebToolsEditorPlugin::_download_zip(Variant p_v) {
 	const String datetime_safe =
 			Time::get_singleton()->get_datetime_string_from_system(false, true).replace(" ", "_");
 	const String output_name = OS::get_singleton()->get_safe_dir_name(vformat("%s_%s.zip"));
-	const String output_path = String("/tmp").plus_file(output_name);
+	const String output_path = String("/tmp").path_join(output_name);
 
 	zipFile zip = zipOpen2(output_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io);
 	const String base_path = resource_path.substr(0, resource_path.rfind("/")) + "/";
@@ -131,7 +131,7 @@ void WebToolsEditorPlugin::_zip_recursive(String p_path, String p_base_path, zip
 	String cur = dir->get_next();
 	String project_data_dir_name = ProjectSettings::get_singleton()->get_project_data_dir_name();
 	while (!cur.is_empty()) {
-		String cs = p_path.plus_file(cur);
+		String cs = p_path.path_join(cur);
 		if (cur == "." || cur == ".." || cur == project_data_dir_name) {
 			// Skip
 		} else if (dir->current_is_dir()) {

+ 4 - 4
platform/web/export/editor_http_server.h

@@ -62,8 +62,8 @@ private:
 
 	void _set_internal_certs(Ref<Crypto> p_crypto) {
 		const String cache_path = EditorPaths::get_singleton()->get_cache_dir();
-		const String key_path = cache_path.plus_file("html5_server.key");
-		const String crt_path = cache_path.plus_file("html5_server.crt");
+		const String key_path = cache_path.path_join("html5_server.key");
+		const String crt_path = cache_path.path_join("html5_server.crt");
 		bool regen = !FileAccess::exists(key_path) || !FileAccess::exists(crt_path);
 		if (!regen) {
 			key = Ref<CryptoKey>(CryptoKey::create());
@@ -139,8 +139,8 @@ public:
 
 		const String req_file = path.get_file();
 		const String req_ext = path.get_extension();
-		const String cache_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
-		const String filepath = cache_path.plus_file(req_file);
+		const String cache_path = EditorPaths::get_singleton()->get_cache_dir().path_join("web");
+		const String filepath = cache_path.path_join(req_file);
 
 		if (!mimes.has(req_ext) || !FileAccess::exists(filepath)) {
 			String s = "HTTP/1.1 404 Not Found\r\n";

+ 9 - 9
platform/web/export/export_plugin.cpp

@@ -75,7 +75,7 @@ Error EditorExportPlatformWeb::_extract_template(const String &p_template, const
 		unzCloseCurrentFile(pkg);
 
 		//write
-		String dst = p_dir.plus_file(file.replace("godot", p_name));
+		String dst = p_dir.path_join(file.replace("godot", p_name));
 		Ref<FileAccess> f = FileAccess::open(dst, FileAccess::WRITE);
 		if (f.is_null()) {
 			add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not write file: \"%s\"."), dst));
@@ -162,7 +162,7 @@ void EditorExportPlatformWeb::_fix_html(Vector<uint8_t> &p_html, const Ref<Edito
 Error EditorExportPlatformWeb::_add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr) {
 	const String name = p_path.get_file().get_basename();
 	const String icon_name = vformat("%s.%dx%d.png", name, p_size, p_size);
-	const String icon_dest = p_path.get_base_dir().plus_file(icon_name);
+	const String icon_dest = p_path.get_base_dir().path_join(icon_name);
 
 	Ref<Image> icon;
 	if (!p_icon.is_empty()) {
@@ -234,7 +234,7 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
 	}
 	replaces["@GODOT_OPT_CACHE@"] = Variant(opt_cache_files).to_json_string();
 
-	const String sw_path = dir.plus_file(name + ".service.worker.js");
+	const String sw_path = dir.path_join(name + ".service.worker.js");
 	Vector<uint8_t> sw;
 	{
 		Ref<FileAccess> f = FileAccess::open(sw_path, FileAccess::READ);
@@ -246,7 +246,7 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
 		f->get_buffer(sw.ptrw(), sw.size());
 	}
 	_replace_strings(replaces, sw);
-	Error err = _write_or_error(sw.ptr(), sw.size(), dir.plus_file(name + ".service.worker.js"));
+	Error err = _write_or_error(sw.ptr(), sw.size(), dir.path_join(name + ".service.worker.js"));
 	if (err != OK) {
 		return err;
 	}
@@ -255,7 +255,7 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
 	const String offline_page = p_preset->get("progressive_web_app/offline_page");
 	if (!offline_page.is_empty()) {
 		Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
-		const String offline_dest = dir.plus_file(name + ".offline.html");
+		const String offline_dest = dir.path_join(name + ".offline.html");
 		err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest);
 		if (err != OK) {
 			add_message(EXPORT_MESSAGE_ERROR, TTR("PWA"), vformat(TTR("Could not read file: \"%s\"."), offline_dest));
@@ -295,7 +295,7 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
 	manifest["icons"] = icons_arr;
 
 	CharString cs = Variant(manifest).to_json_string().utf8();
-	err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.plus_file(name + ".manifest.json"));
+	err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.path_join(name + ".manifest.json"));
 	if (err != OK) {
 		return err;
 	}
@@ -481,7 +481,7 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
 	{
 		Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 		for (int i = 0; i < shared_objects.size(); i++) {
-			String dst = base_dir.plus_file(shared_objects[i].path.get_file());
+			String dst = base_dir.path_join(shared_objects[i].path.get_file());
 			error = da->copy(shared_objects[i].path, dst);
 			if (error != OK) {
 				add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), shared_objects[i].path.get_file()));
@@ -601,7 +601,7 @@ Error EditorExportPlatformWeb::run(const Ref<EditorExportPreset> &p_preset, int
 		return OK;
 	}
 
-	const String dest = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
+	const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("web");
 	Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 	if (!da->dir_exists(dest)) {
 		Error err = da->make_dir_recursive(dest);
@@ -611,7 +611,7 @@ Error EditorExportPlatformWeb::run(const Ref<EditorExportPreset> &p_preset, int
 		}
 	}
 
-	const String basepath = dest.plus_file("tmp_js_export");
+	const String basepath = dest.path_join("tmp_js_export");
 	Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
 	if (err != OK) {
 		// Export generates several files, clean them up on failure.

+ 4 - 4
platform/windows/os_windows.cpp

@@ -237,7 +237,7 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
 
 	if (!FileAccess::exists(path)) {
 		//this code exists so gdnative can load .dll files from within the executable path
-		path = get_executable_path().get_base_dir().plus_file(p_path.get_file());
+		path = get_executable_path().get_base_dir().path_join(p_path.get_file());
 	}
 
 	typedef DLL_DIRECTORY_COOKIE(WINAPI * PAddDllDirectory)(PCWSTR);
@@ -1071,13 +1071,13 @@ String OS_Windows::get_user_data_dir() const {
 			if (custom_dir.is_empty()) {
 				custom_dir = appname;
 			}
-			return get_data_path().plus_file(custom_dir).replace("\\", "/");
+			return get_data_path().path_join(custom_dir).replace("\\", "/");
 		} else {
-			return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file(appname).replace("\\", "/");
+			return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname).replace("\\", "/");
 		}
 	}
 
-	return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file("[unnamed project]");
+	return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]");
 }
 
 String OS_Windows::get_unique_id() const {

+ 8 - 8
scene/gui/file_dialog.cpp

@@ -163,7 +163,7 @@ Vector<String> FileDialog::get_selected_files() const {
 
 	TreeItem *item = tree->get_root();
 	while ((item = tree->get_next_selected(item))) {
-		list.push_back(dir_access->get_current_dir().plus_file(item->get_text(0)));
+		list.push_back(dir_access->get_current_dir().path_join(item->get_text(0)));
 	};
 
 	return list;
@@ -192,7 +192,7 @@ void FileDialog::update_dir() {
 }
 
 void FileDialog::_dir_submitted(String p_dir) {
-	_change_dir(root_prefix.plus_file(p_dir));
+	_change_dir(root_prefix.path_join(p_dir));
 	file->set_text("");
 	_push_history();
 }
@@ -202,7 +202,7 @@ void FileDialog::_file_submitted(const String &p_file) {
 }
 
 void FileDialog::_save_confirm_pressed() {
-	String f = dir_access->get_current_dir().plus_file(file->get_text());
+	String f = dir_access->get_current_dir().path_join(file->get_text());
 	emit_signal(SNAME("file_selected"), f);
 	hide();
 }
@@ -252,7 +252,7 @@ void FileDialog::_action_pressed() {
 
 		Vector<String> files;
 		while (ti) {
-			files.push_back(fbase.plus_file(ti->get_text(0)));
+			files.push_back(fbase.path_join(ti->get_text(0)));
 			ti = tree->get_next_selected(ti);
 		}
 
@@ -265,7 +265,7 @@ void FileDialog::_action_pressed() {
 	}
 
 	String file_text = file->get_text();
-	String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().plus_file(file_text);
+	String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().path_join(file_text);
 
 	if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) {
 		emit_signal(SNAME("file_selected"), f);
@@ -278,7 +278,7 @@ void FileDialog::_action_pressed() {
 		if (item) {
 			Dictionary d = item->get_metadata(0);
 			if (d["dir"] && d["name"] != "..") {
-				path = path.plus_file(d["name"]);
+				path = path.path_join(d["name"]);
 			}
 		}
 
@@ -598,7 +598,7 @@ void FileDialog::update_file_list() {
 			ti->set_text(0, files.front()->get());
 
 			if (get_icon_func) {
-				Ref<Texture2D> icon = get_icon_func(base_dir.plus_file(files.front()->get()));
+				Ref<Texture2D> icon = get_icon_func(base_dir.path_join(files.front()->get()));
 				ti->set_icon(0, icon);
 			} else {
 				ti->set_icon(0, file_icon);
@@ -706,7 +706,7 @@ String FileDialog::get_current_file() const {
 }
 
 String FileDialog::get_current_path() const {
-	return dir->get_text().plus_file(file->get_text());
+	return dir->get_text().path_join(file->get_text());
 }
 
 void FileDialog::set_current_dir(const String &p_dir) {

+ 2 - 2
scene/main/scene_tree.cpp

@@ -1370,9 +1370,9 @@ void SceneTree::get_argument_options(const StringName &p_function, int p_idx, Li
 				}
 
 				if (dir_access->dir_exists(filename)) {
-					directories.push_back(dir_access->get_current_dir().plus_file(filename));
+					directories.push_back(dir_access->get_current_dir().path_join(filename));
 				} else if (filename.ends_with(".tscn") || filename.ends_with(".scn")) {
-					r_options->push_back("\"" + dir_access->get_current_dir().plus_file(filename) + "\"");
+					r_options->push_back("\"" + dir_access->get_current_dir().path_join(filename) + "\"");
 				}
 
 				filename = dir_access->get_next();

+ 2 - 2
scene/resources/font.cpp

@@ -1427,7 +1427,7 @@ Error FontFile::load_bitmap_font(const String &p_path) {
 					while (!f->eof_reached() && f->get_position() <= off + block_size) {
 						if (c == '\0') {
 							String base_dir = p_path.get_base_dir();
-							String file = base_dir.plus_file(String::utf8(cs.ptr(), cs.length()));
+							String file = base_dir.path_join(String::utf8(cs.ptr(), cs.length()));
 							if (RenderingServer::get_singleton() != nullptr) {
 								Ref<Image> img;
 								img.instantiate();
@@ -1660,7 +1660,7 @@ Error FontFile::load_bitmap_font(const String &p_path) {
 				}
 				if (keys.has("file")) {
 					String base_dir = p_path.get_base_dir();
-					String file = base_dir.plus_file(keys["file"]);
+					String file = base_dir.path_join(keys["file"]);
 					if (RenderingServer::get_singleton() != nullptr) {
 						Ref<Image> img;
 						img.instantiate();

+ 3 - 3
scene/resources/resource_format_text.cpp

@@ -451,7 +451,7 @@ Error ResourceLoaderText::load() {
 
 		if (!path.contains("://") && path.is_relative_path()) {
 			// path is relative to file being loaded, so convert to a resource path
-			path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
+			path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().path_join(path));
 		}
 
 		if (remaps.has(path)) {
@@ -861,7 +861,7 @@ void ResourceLoaderText::get_dependencies(Ref<FileAccess> p_f, List<String> *p_d
 
 		if (!using_uid && !path.contains("://") && path.is_relative_path()) {
 			// path is relative to file being loaded, so convert to a resource path
-			path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
+			path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().path_join(path));
 		}
 
 		if (p_add_types) {
@@ -938,7 +938,7 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String
 			}
 			bool relative = false;
 			if (!path.begins_with("res://")) {
-				path = base_path.plus_file(path).simplify_path();
+				path = base_path.path_join(path).simplify_path();
 				relative = true;
 			}
 

+ 1 - 1
servers/movie_writer/movie_writer.cpp

@@ -191,7 +191,7 @@ void MovieWriter::end() {
 	if (movie_path.is_relative_path()) {
 		// Print absolute path to make finding the file easier,
 		// and to make it clickable in terminal emulators that support this.
-		movie_path = ProjectSettings::get_singleton()->globalize_path("res://").plus_file(movie_path);
+		movie_path = ProjectSettings::get_singleton()->globalize_path("res://").path_join(movie_path);
 	}
 	print_line(vformat("Done recording movie at path: %s", movie_path));
 

+ 1 - 1
servers/rendering/renderer_rd/renderer_compositor_rd.cpp

@@ -267,7 +267,7 @@ RendererCompositorRD::RendererCompositorRD() {
 			if (err != OK) {
 				ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
 			} else {
-				shader_cache_dir = shader_cache_dir.plus_file("shader_cache");
+				shader_cache_dir = shader_cache_dir.path_join("shader_cache");
 
 				bool shader_cache_enabled = GLOBAL_GET("rendering/shader_compiler/shader_cache/enabled");
 				if (!Engine::get_singleton()->is_editor_hint() && !shader_cache_enabled) {

+ 2 - 2
servers/rendering/renderer_rd/shader_rd.cpp

@@ -380,7 +380,7 @@ static const uint32_t cache_file_version = 2;
 
 bool ShaderRD::_load_from_cache(Version *p_version) {
 	String sha1 = _version_get_sha1(p_version);
-	String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+	String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache";
 
 	Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ);
 	if (f.is_null()) {
@@ -443,7 +443,7 @@ bool ShaderRD::_load_from_cache(Version *p_version) {
 
 void ShaderRD::_save_to_cache(Version *p_version) {
 	String sha1 = _version_get_sha1(p_version);
-	String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+	String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache";
 
 	Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE);
 	ERR_FAIL_COND(f.is_null());

+ 1 - 1
tests/core/io/test_config_file.h

@@ -127,7 +127,7 @@ TEST_CASE("[ConfigFile] Saving file") {
 	config_file.set_value("quoted", "a=b", 7);
 
 #ifdef WINDOWS_ENABLED
-	const String config_path = OS::get_singleton()->get_environment("TEMP").plus_file("config.ini");
+	const String config_path = OS::get_singleton()->get_environment("TEMP").path_join("config.ini");
 #else
 	const String config_path = "/tmp/config.ini";
 #endif

+ 2 - 2
tests/core/io/test_image.h

@@ -78,8 +78,8 @@ TEST_CASE("[Image] Instantiation") {
 
 TEST_CASE("[Image] Saving and loading") {
 	Ref<Image> image = memnew(Image(4, 4, false, Image::FORMAT_RGBA8));
-	const String save_path_png = OS::get_singleton()->get_cache_path().plus_file("image.png");
-	const String save_path_exr = OS::get_singleton()->get_cache_path().plus_file("image.exr");
+	const String save_path_png = OS::get_singleton()->get_cache_path().path_join("image.png");
+	const String save_path_exr = OS::get_singleton()->get_cache_path().path_join("image.exr");
 
 	// Save PNG
 	Error err;

+ 8 - 8
tests/core/io/test_pck_packer.h

@@ -42,7 +42,7 @@ namespace TestPCKPacker {
 
 TEST_CASE("[PCKPacker] Pack an empty PCK file") {
 	PCKPacker pck_packer;
-	const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_empty.pck");
+	const String output_pck_path = OS::get_singleton()->get_cache_path().path_join("output_empty.pck");
 	CHECK_MESSAGE(
 			pck_packer.pck_start(output_pck_path) == OK,
 			"Starting a PCK file should return an OK error code.");
@@ -66,7 +66,7 @@ TEST_CASE("[PCKPacker] Pack an empty PCK file") {
 
 TEST_CASE("[PCKPacker] Pack empty with zero alignment invalid") {
 	PCKPacker pck_packer;
-	const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_empty.pck");
+	const String output_pck_path = OS::get_singleton()->get_cache_path().path_join("output_empty.pck");
 	ERR_PRINT_OFF;
 	CHECK_MESSAGE(pck_packer.pck_start(output_pck_path, 0) != OK, "PCK with zero alignment should fail.");
 	ERR_PRINT_ON;
@@ -74,7 +74,7 @@ TEST_CASE("[PCKPacker] Pack empty with zero alignment invalid") {
 
 TEST_CASE("[PCKPacker] Pack empty with invalid key") {
 	PCKPacker pck_packer;
-	const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_empty.pck");
+	const String output_pck_path = OS::get_singleton()->get_cache_path().path_join("output_empty.pck");
 	ERR_PRINT_OFF;
 	CHECK_MESSAGE(pck_packer.pck_start(output_pck_path, 32, "") != OK, "PCK with invalid key should fail.");
 	ERR_PRINT_ON;
@@ -82,7 +82,7 @@ TEST_CASE("[PCKPacker] Pack empty with invalid key") {
 
 TEST_CASE("[PCKPacker] Pack a PCK file with some files and directories") {
 	PCKPacker pck_packer;
-	const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_with_files.pck");
+	const String output_pck_path = OS::get_singleton()->get_cache_path().path_join("output_with_files.pck");
 	CHECK_MESSAGE(
 			pck_packer.pck_start(output_pck_path) == OK,
 			"Starting a PCK file should return an OK error code.");
@@ -90,16 +90,16 @@ TEST_CASE("[PCKPacker] Pack a PCK file with some files and directories") {
 	const String base_dir = OS::get_singleton()->get_executable_path().get_base_dir();
 
 	CHECK_MESSAGE(
-			pck_packer.add_file("version.py", base_dir.plus_file("../version.py"), "version.py") == OK,
+			pck_packer.add_file("version.py", base_dir.path_join("../version.py"), "version.py") == OK,
 			"Adding a file to the PCK should return an OK error code.");
 	CHECK_MESSAGE(
-			pck_packer.add_file("some/directories with spaces/to/create/icon.png", base_dir.plus_file("../icon.png")) == OK,
+			pck_packer.add_file("some/directories with spaces/to/create/icon.png", base_dir.path_join("../icon.png")) == OK,
 			"Adding a file to a new subdirectory in the PCK should return an OK error code.");
 	CHECK_MESSAGE(
-			pck_packer.add_file("some/directories with spaces/to/create/icon.svg", base_dir.plus_file("../icon.svg")) == OK,
+			pck_packer.add_file("some/directories with spaces/to/create/icon.svg", base_dir.path_join("../icon.svg")) == OK,
 			"Adding a file to an existing subdirectory in the PCK should return an OK error code.");
 	CHECK_MESSAGE(
-			pck_packer.add_file("some/directories with spaces/to/create/icon.png", base_dir.plus_file("../logo.png")) == OK,
+			pck_packer.add_file("some/directories with spaces/to/create/icon.png", base_dir.path_join("../logo.png")) == OK,
 			"Overriding a non-flushed file to an existing subdirectory in the PCK should return an OK error code.");
 	CHECK_MESSAGE(
 			pck_packer.flush() == OK,

+ 2 - 2
tests/core/io/test_resource.h

@@ -74,8 +74,8 @@ TEST_CASE("[Resource] Saving and loading") {
 	Ref<Resource> child_resource = memnew(Resource);
 	child_resource->set_name("I'm a child resource");
 	resource->set_meta("other_resource", child_resource);
-	const String save_path_binary = OS::get_singleton()->get_cache_path().plus_file("resource.res");
-	const String save_path_text = OS::get_singleton()->get_cache_path().plus_file("resource.tres");
+	const String save_path_binary = OS::get_singleton()->get_cache_path().path_join("resource.res");
+	const String save_path_text = OS::get_singleton()->get_cache_path().path_join("resource.tres");
 	ResourceSaver::save(resource, save_path_binary);
 	ResourceSaver::save(resource, save_path_text);
 

+ 1 - 1
tests/core/string/test_string.h

@@ -1359,7 +1359,7 @@ TEST_CASE("[String] Path functions") {
 		CHECK(String(path[i]).get_file() == file[i]);
 		CHECK(String(path[i]).is_absolute_path() == abs[i]);
 		CHECK(String(path[i]).is_relative_path() != abs[i]);
-		CHECK(String(path[i]).simplify_path().get_base_dir().plus_file(file[i]) == String(path[i]).simplify_path());
+		CHECK(String(path[i]).simplify_path().get_base_dir().path_join(file[i]) == String(path[i]).simplify_path());
 	}
 
 	static const char *file_name[3] = { "test.tscn", "test://.xscn", "?tes*t.scn" };

+ 3 - 3
tests/scene/test_audio_stream_wav.h

@@ -115,7 +115,7 @@ Vector<uint8_t> gen_pcm16_test(float wav_rate, int wav_count, bool stereo) {
 }
 
 void run_test(String file_name, AudioStreamWAV::Format data_format, bool stereo, float wav_rate, float wav_count) {
-	String save_path = OS::get_singleton()->get_cache_path().plus_file(file_name);
+	String save_path = OS::get_singleton()->get_cache_path().path_join(file_name);
 
 	Vector<uint8_t> test_data;
 	if (data_format == AudioStreamWAV::FORMAT_8_BITS) {
@@ -200,7 +200,7 @@ TEST_CASE("[AudioStreamWAV] Alternate mix rate") {
 }
 
 TEST_CASE("[AudioStreamWAV] save_to_wav() adds '.wav' file extension automatically") {
-	String save_path = OS::get_singleton()->get_cache_path().plus_file("test_wav_extension");
+	String save_path = OS::get_singleton()->get_cache_path().path_join("test_wav_extension");
 	Vector<uint8_t> test_data = gen_pcm8_test(WAV_RATE, WAV_COUNT, false);
 	Ref<AudioStreamWAV> stream = memnew(AudioStreamWAV);
 	stream->set_data(test_data);
@@ -230,7 +230,7 @@ TEST_CASE("[AudioStreamWAV] Save empty file") {
 }
 
 TEST_CASE("[AudioStreamWAV] Saving IMA ADPCM is not supported") {
-	String save_path = OS::get_singleton()->get_cache_path().plus_file("test_adpcm.wav");
+	String save_path = OS::get_singleton()->get_cache_path().path_join("test_adpcm.wav");
 	Ref<AudioStreamWAV> stream = memnew(AudioStreamWAV);
 	stream->set_format(AudioStreamWAV::FORMAT_IMA_ADPCM);
 	ERR_PRINT_OFF;

+ 1 - 1
tests/test_utils.cpp

@@ -34,7 +34,7 @@
 
 String TestUtils::get_data_path(const String &p_file) {
 	String data_path = "../tests/data";
-	return get_executable_dir().plus_file(data_path.plus_file(p_file));
+	return get_executable_dir().path_join(data_path.path_join(p_file));
 }
 
 String TestUtils::get_executable_dir() {