diff options
173 files changed, 2537 insertions, 2159 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index d46e242610..74c06123e1 100644 --- a/core/config/project_settings.cpp +++ b/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#"); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index bcc87d78c4..9daf58cb71 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -437,114 +437,6 @@ bool OS::is_stdout_verbose() const { return ::OS::get_singleton()->is_stdout_verbose(); } -struct OSCoreBindImg { - String path; - Size2 size; - int fmt = 0; - ObjectID id; - int vram = 0; - bool operator<(const OSCoreBindImg &p_img) const { return vram == p_img.vram ? id < p_img.id : vram > p_img.vram; } -}; - -void OS::print_all_textures_by_size() { - List<OSCoreBindImg> imgs; - uint64_t total = 0; - { - List<Ref<Resource>> rsrc; - ResourceCache::get_cached_resources(&rsrc); - - for (Ref<Resource> &res : rsrc) { - if (!res->is_class("Texture")) { - continue; - } - - Size2 size = res->call("get_size"); - int fmt = res->call("get_format"); - - OSCoreBindImg img; - img.size = size; - img.fmt = fmt; - img.path = res->get_path(); - img.vram = Image::get_image_data_size(img.size.width, img.size.height, Image::Format(img.fmt)); - img.id = res->get_instance_id(); - total += img.vram; - imgs.push_back(img); - } - } - - imgs.sort(); - - if (imgs.size() == 0) { - print_line("No textures seem used in this project."); - } else { - print_line("Textures currently in use, sorted by VRAM usage:\n" - "Path - VRAM usage (Dimensions)"); - } - - for (const OSCoreBindImg &img : imgs) { - print_line(vformat("%s - %s %s", - img.path, - String::humanize_size(img.vram), - img.size)); - } - - print_line(vformat("Total VRAM usage: %s.", String::humanize_size(total))); -} - -void OS::print_resources_by_type(const Vector<String> &p_types) { - ERR_FAIL_COND_MSG(p_types.size() == 0, - "At least one type should be provided to print resources by type."); - - print_line(vformat("Resources currently in use for the following types: %s", p_types)); - - RBMap<String, int> type_count; - List<Ref<Resource>> resources; - ResourceCache::get_cached_resources(&resources); - - for (const Ref<Resource> &r : resources) { - bool found = false; - - for (int i = 0; i < p_types.size(); i++) { - if (r->is_class(p_types[i])) { - found = true; - } - } - if (!found) { - continue; - } - - if (!type_count.has(r->get_class())) { - type_count[r->get_class()] = 0; - } - - type_count[r->get_class()]++; - - print_line(vformat("%s: %s", r->get_class(), r->get_path())); - - List<StringName> metas; - r->get_meta_list(&metas); - for (const StringName &meta : metas) { - print_line(vformat(" %s: %s", meta, r->get_meta(meta))); - } - } - - for (const KeyValue<String, int> &E : type_count) { - print_line(vformat("%s count: %d", E.key, E.value)); - } -} - -void OS::print_all_resources(const String &p_to_file) { - ::OS::get_singleton()->print_all_resources(p_to_file); -} - -void OS::print_resources_in_use(bool p_short) { - ::OS::get_singleton()->print_resources_in_use(p_short); -} - -void OS::dump_resources_to_file(const String &p_file) { - ::OS::get_singleton()->dump_resources_to_file(p_file.utf8().get_data()); -} - Error OS::move_to_trash(const String &p_path) const { return ::OS::get_singleton()->move_to_trash(p_path); } @@ -663,10 +555,6 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("is_debug_build"), &OS::is_debug_build); - ClassDB::bind_method(D_METHOD("dump_resources_to_file", "file"), &OS::dump_resources_to_file); - ClassDB::bind_method(D_METHOD("print_resources_in_use", "short"), &OS::print_resources_in_use, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("print_all_resources", "tofile"), &OS::print_all_resources, DEFVAL("")); - ClassDB::bind_method(D_METHOD("get_static_memory_usage"), &OS::get_static_memory_usage); ClassDB::bind_method(D_METHOD("get_static_memory_peak_usage"), &OS::get_static_memory_peak_usage); @@ -678,9 +566,6 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_cache_dir"), &OS::get_cache_dir); ClassDB::bind_method(D_METHOD("get_unique_id"), &OS::get_unique_id); - ClassDB::bind_method(D_METHOD("print_all_textures_by_size"), &OS::print_all_textures_by_size); - ClassDB::bind_method(D_METHOD("print_resources_by_type", "types"), &OS::print_resources_by_type); - ClassDB::bind_method(D_METHOD("get_keycode_string", "code"), &OS::get_keycode_string); ClassDB::bind_method(D_METHOD("is_keycode_unicode", "code"), &OS::is_keycode_unicode); ClassDB::bind_method(D_METHOD("find_keycode_from_string", "string"), &OS::find_keycode_from_string); diff --git a/core/core_bind.h b/core/core_bind.h index 642a0c00c7..cd382d2915 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -201,13 +201,6 @@ public: String get_model_name() const; - void dump_resources_to_file(const String &p_file); - - void print_resources_in_use(bool p_short = false); - void print_all_resources(const String &p_to_file); - void print_all_textures_by_size(); - void print_resources_by_type(const Vector<String> &p_types); - bool is_debug_build() const; String get_unique_id() const; diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp index fdb4e50d90..6418da2235 100644 --- a/core/extension/native_extension.cpp +++ b/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; diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp index f82d6f077f..bed41b8d89 100644 --- a/core/io/dir_access.cpp +++ b/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; diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 595a6e9873..adae0db0f4 100644 --- a/core/io/file_access_pack.cpp +++ b/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; diff --git a/core/io/resource.cpp b/core/io/resource.cpp index fec5ca5c7b..d117f86f39 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -543,43 +543,3 @@ int ResourceCache::get_cached_resource_count() { return rc; } - -void ResourceCache::dump(const char *p_file, bool p_short) { -#ifdef DEBUG_ENABLED - lock.lock(); - - HashMap<String, int> type_count; - - Ref<FileAccess> f; - if (p_file) { - f = FileAccess::open(String::utf8(p_file), FileAccess::WRITE); - ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file at path '" + String::utf8(p_file) + "'."); - } - - for (KeyValue<String, Resource *> &E : resources) { - Resource *r = E.value; - - if (!type_count.has(r->get_class())) { - type_count[r->get_class()] = 0; - } - - type_count[r->get_class()]++; - - if (!p_short) { - if (f.is_valid()) { - f->store_line(r->get_class() + ": " + r->get_path()); - } - } - } - - for (const KeyValue<String, int> &E : type_count) { - if (f.is_valid()) { - f->store_line(E.key + " count: " + itos(E.value)); - } - } - - lock.unlock(); -#else - WARN_PRINT("ResourceCache::dump only with in debug builds."); -#endif -} diff --git a/core/io/resource.h b/core/io/resource.h index a2cde87990..a76a3920be 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -167,7 +167,6 @@ public: static void reload_externals(); static bool has(const String &p_path); static Ref<Resource> get_ref(const String &p_path); - static void dump(const char *p_file = nullptr, bool p_short = false); static void get_cached_resources(List<Ref<Resource>> *p_resources); static int get_cached_resource_count(); }; diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index b731608b4f..4f1204fc48 100644 --- a/core/io/resource_format_binary.cpp +++ b/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; } diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index e059fc842b..aa7f96a047 100644 --- a/core/io/resource_importer.cpp +++ b/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 { diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp index fc324a26da..5324c5dd84 100644 --- a/core/io/resource_uid.cpp +++ b/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 { diff --git a/core/os/os.cpp b/core/os/os.cpp index 26a1b0e160..526b31ae7e 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -186,46 +186,6 @@ void OS::set_stderr_enabled(bool p_enabled) { _stderr_enabled = p_enabled; } -static Ref<FileAccess> _OSPRF; - -static void _OS_printres(Object *p_obj) { - Resource *res = Object::cast_to<Resource>(p_obj); - if (!res) { - return; - } - - String str = vformat("%s - %s - %s", res->to_string(), res->get_name(), res->get_path()); - if (_OSPRF.is_valid()) { - _OSPRF->store_line(str); - } else { - print_line(str); - } -} - -void OS::print_all_resources(String p_to_file) { - ERR_FAIL_COND(!p_to_file.is_empty() && _OSPRF.is_valid()); - if (!p_to_file.is_empty()) { - Error err; - _OSPRF = FileAccess::open(p_to_file, FileAccess::WRITE, &err); - if (err != OK) { - _OSPRF.unref(); - ERR_FAIL_MSG("Can't print all resources to file: " + String(p_to_file) + "."); - } - } - - ObjectDB::debug_objects(_OS_printres); - - _OSPRF.unref(); -} - -void OS::print_resources_in_use(bool p_short) { - ResourceCache::dump(nullptr, p_short); -} - -void OS::dump_resources_to_file(const char *p_file) { - ResourceCache::dump(p_file); -} - int OS::get_exit_code() const { return _exit_code; } diff --git a/core/os/os.h b/core/os/os.h index ff769cc4f1..0e8a2d0398 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -246,10 +246,6 @@ public: virtual bool is_disable_crash_handler() const { return false; } virtual void initialize_debugging() {} - virtual void dump_resources_to_file(const char *p_file); - virtual void print_resources_in_use(bool p_short = false); - virtual void print_all_resources(String p_to_file = ""); - virtual uint64_t get_static_memory_usage() const; virtual uint64_t get_static_memory_peak_usage() const; virtual uint64_t get_free_static_memory() const; diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 0c43ba9ccc..d8b93998af 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -970,62 +970,71 @@ const char32_t *String::get_data() const { return size() ? &operator[](0) : &zero; } -String String::capitalize() const { - String aux = this->camelcase_to_underscore(true).replace("_", " ").strip_edges(); - String cap; - for (int i = 0; i < aux.get_slice_count(" "); i++) { - String slice = aux.get_slicec(' ', i); - if (slice.length() > 0) { - slice[0] = _find_upper(slice[0]); - if (i > 0) { - cap += " "; - } - cap += slice; - } - } - - return cap; -} - -String String::camelcase_to_underscore(bool lowercase) const { +String String::_camelcase_to_underscore() const { const char32_t *cstr = get_data(); String new_string; int start_index = 0; for (int i = 1; i < this->size(); i++) { - bool is_upper = is_ascii_upper_case(cstr[i]); - bool is_number = is_digit(cstr[i]); + bool is_prev_upper = is_ascii_upper_case(cstr[i - 1]); + bool is_prev_lower = is_ascii_lower_case(cstr[i - 1]); + bool is_prev_digit = is_digit(cstr[i - 1]); - bool are_next_2_lower = false; - bool is_next_lower = false; - bool is_next_number = false; - bool was_precedent_upper = is_ascii_upper_case(cstr[i - 1]); - bool was_precedent_number = is_digit(cstr[i - 1]); - - if (i + 2 < this->size()) { - are_next_2_lower = is_ascii_lower_case(cstr[i + 1]) && is_ascii_lower_case(cstr[i + 2]); - } + bool is_curr_upper = is_ascii_upper_case(cstr[i]); + bool is_curr_lower = is_ascii_lower_case(cstr[i]); + bool is_curr_digit = is_digit(cstr[i]); + bool is_next_lower = false; if (i + 1 < this->size()) { is_next_lower = is_ascii_lower_case(cstr[i + 1]); - is_next_number = is_digit(cstr[i + 1]); } - const bool cond_a = is_upper && !was_precedent_upper && !was_precedent_number; - const bool cond_b = was_precedent_upper && is_upper && are_next_2_lower; - const bool cond_c = is_number && !was_precedent_number; - const bool can_break_number_letter = is_number && !was_precedent_number && is_next_lower; - const bool can_break_letter_number = !is_number && was_precedent_number && (is_next_lower || is_next_number); + const bool cond_a = is_prev_lower && is_curr_upper; // aA + const bool cond_b = (is_prev_upper || is_prev_digit) && is_curr_upper && is_next_lower; // AAa, 2Aa + const bool cond_c = is_prev_digit && is_curr_lower && is_next_lower; // 2aa + const bool cond_d = (is_prev_upper || is_prev_lower) && is_curr_digit; // A2, a2 - bool should_split = cond_a || cond_b || cond_c || can_break_number_letter || can_break_letter_number; - if (should_split) { + if (cond_a || cond_b || cond_c || cond_d) { new_string += this->substr(start_index, i - start_index) + "_"; start_index = i; } } new_string += this->substr(start_index, this->size() - start_index); - return lowercase ? new_string.to_lower() : new_string; + return new_string.to_lower(); +} + +String String::capitalize() const { + String aux = this->_camelcase_to_underscore().replace("_", " ").strip_edges(); + String cap; + for (int i = 0; i < aux.get_slice_count(" "); i++) { + String slice = aux.get_slicec(' ', i); + if (slice.length() > 0) { + slice[0] = _find_upper(slice[0]); + if (i > 0) { + cap += " "; + } + cap += slice; + } + } + + return cap; +} + +String String::to_camel_case() const { + String s = this->to_pascal_case(); + if (!s.is_empty()) { + s[0] = _find_lower(s[0]); + } + return s; +} + +String String::to_pascal_case() const { + return this->capitalize().replace(" ", ""); +} + +String String::to_snake_case() const { + return this->_camelcase_to_underscore().replace(" ", "_").strip_edges(); } String String::get_with_code_lines() const { @@ -4451,7 +4460,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; } diff --git a/core/string/ustring.h b/core/string/ustring.h index 6c3169f136..31de7cc464 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -196,6 +196,7 @@ class String { bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const; int _count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const; + String _camelcase_to_underscore() const; public: enum { @@ -335,7 +336,9 @@ public: static double to_float(const char32_t *p_str, const char32_t **r_end = nullptr); String capitalize() const; - String camelcase_to_underscore(bool lowercase = true) const; + String to_camel_case() const; + String to_pascal_case() const; + String to_snake_case() const; String get_with_code_lines() const; int get_slice_count(String p_splitter) const; @@ -370,7 +373,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); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 9b7dc5012b..8af2a09111 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1506,6 +1506,9 @@ static void _register_variant_builtin_methods() { bind_method(String, repeat, sarray("count"), varray()); bind_method(String, insert, sarray("position", "what"), varray()); bind_method(String, capitalize, sarray(), varray()); + bind_method(String, to_camel_case, sarray(), varray()); + bind_method(String, to_pascal_case, sarray(), varray()); + bind_method(String, to_snake_case, sarray(), varray()); bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0)); bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0)); bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true)); @@ -1523,7 +1526,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()); diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index 33a129a48e..2262c4fe47 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -82,7 +82,7 @@ The hashing scale for Alpha Hash. Recommended values between [code]0[/code] and [code]2[/code]. </member> <member name="alpha_scissor_threshold" type="float" setter="set_alpha_scissor_threshold" getter="get_alpha_scissor_threshold"> - Threshold at which the alpha scissor will discard values. + Threshold at which the alpha scissor will discard values. Higher values will result in more pixels being discarded. If the material becomes too opaque at a distance, try increasing [member alpha_scissor_threshold]. If the material disappears at a distance, try decreasing [member alpha_scissor_threshold]. </member> <member name="anisotropy" type="float" setter="set_anisotropy" getter="get_anisotropy" default="0.0"> The strength of the anisotropy effect. This is multiplied by [member anisotropy_flowmap]'s alpha channel if a texture is defined there and the texture contains an alpha channel. diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml index 99fd0501fc..6b39c08b3f 100644 --- a/doc/classes/CPUParticles3D.xml +++ b/doc/classes/CPUParticles3D.xml @@ -123,13 +123,16 @@ Minimum particle animation speed. </member> <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> - Each particle's initial color. To have particle display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D.vertex_color_use_as_albedo] to [code]true[/code]. + Each particle's initial color. + [b]Note:[/b] [member color] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color] will have no visible effect. </member> <member name="color_initial_ramp" type="Gradient" setter="set_color_initial_ramp" getter="get_color_initial_ramp"> Each particle's initial color will vary along this [GradientTexture1D] (multiplied with [member color]). + [b]Note:[/b] [member color_initial_ramp] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color_initial_ramp] will have no visible effect. </member> <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp"> Each particle's color will vary along this [GradientTexture1D] over its lifetime (multiplied with [member color]). + [b]Note:[/b] [member color_ramp] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color_ramp] will have no visible effect. </member> <member name="damping_curve" type="Curve" setter="set_param_curve" getter="get_param_curve"> Damping will vary along this [Curve]. @@ -151,6 +154,7 @@ </member> <member name="emission_colors" type="PackedColorArray" setter="set_emission_colors" getter="get_emission_colors" default="PackedColorArray()"> Sets the [Color]s to modulate particles by when using [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS]. + [b]Note:[/b] [member emission_colors] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member emission_colors] will have no visible effect. </member> <member name="emission_normals" type="PackedVector3Array" setter="set_emission_normals" getter="get_emission_normals"> Sets the direction the particles will be emitted in when using [constant EMISSION_SHAPE_DIRECTED_POINTS]. diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml index 67d5a667e8..ee69015ae1 100644 --- a/doc/classes/CollisionObject2D.xml +++ b/doc/classes/CollisionObject2D.xml @@ -20,6 +20,32 @@ [b]Note:[/b] [method _input_event] requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. </description> </method> + <method name="_mouse_enter" qualifiers="virtual"> + <return type="void" /> + <description> + Called when the mouse pointer enters any of this object's shapes. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. Note that moving between different shapes within a single [CollisionObject2D] won't cause this function to be called. + </description> + </method> + <method name="_mouse_exit" qualifiers="virtual"> + <return type="void" /> + <description> + Called when the mouse pointer exits all this object's shapes. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. Note that moving between different shapes within a single [CollisionObject2D] won't cause this function to be called. + </description> + </method> + <method name="_mouse_shape_enter" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="shape_idx" type="int" /> + <description> + Called when the mouse pointer enters any of this object's shapes or moves from one shape to another. [param shape_idx] is the child index of the newly entered [Shape2D]. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be called. + </description> + </method> + <method name="_mouse_shape_exit" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="shape_idx" type="int" /> + <description> + Called when the mouse pointer exits any of this object's shapes. [param shape_idx] is the child index of the exited [Shape2D]. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be called. + </description> + </method> <method name="create_shape_owner"> <return type="int" /> <param index="0" name="owner" type="Object" /> diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml index 4d10a33032..f10136521a 100644 --- a/doc/classes/CollisionObject3D.xml +++ b/doc/classes/CollisionObject3D.xml @@ -21,6 +21,18 @@ [b]Note:[/b] [method _input_event] requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. </description> </method> + <method name="_mouse_enter" qualifiers="virtual"> + <return type="void" /> + <description> + Called when the mouse pointer enters any of this object's shapes. Requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. Note that moving between different shapes within a single [CollisionObject3D] won't cause this function to be called. + </description> + </method> + <method name="_mouse_exit" qualifiers="virtual"> + <return type="void" /> + <description> + Called when the mouse pointer exits all this object's shapes. Requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. Note that moving between different shapes within a single [CollisionObject3D] won't cause this function to be called. + </description> + </method> <method name="create_shape_owner"> <return type="int" /> <param index="0" name="owner" type="Object" /> diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml index 67204f2a15..7bac4bf7ac 100644 --- a/doc/classes/EditorProperty.xml +++ b/doc/classes/EditorProperty.xml @@ -105,6 +105,8 @@ <signal name="property_changed"> <param index="0" name="property" type="StringName" /> <param index="1" name="value" type="Variant" /> + <param index="2" name="field" type="StringName" /> + <param index="3" name="changing" type="bool" /> <description> Do not emit this manually, use the [method emit_changed] method instead. </description> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index b882425960..87edc7de0a 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -856,8 +856,8 @@ <constant name="NOTIFICATION_UNPARENTED" value="19"> Notification received when a node is unparented (parent removed it from the list of children). </constant> - <constant name="NOTIFICATION_INSTANCED" value="20"> - Notification received when the node is instantiated. + <constant name="NOTIFICATION_SCENE_INSTANTIATED" value="20"> + Notification received by scene owner when its scene is instantiated. </constant> <constant name="NOTIFICATION_DRAG_BEGIN" value="21"> Notification received when a drag operation begins. All nodes receive this notification, not only the dragged one. diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 13cd9c9ab0..059766656f 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -88,15 +88,6 @@ [b]Note:[/b] When [method delay_usec] is called on the main thread, it will freeze the project and will prevent it from redrawing and registering input until the delay has passed. When using [method delay_usec] as part of an [EditorPlugin] or [EditorScript], it will freeze the editor but won't freeze the project if it is currently running (since the project is an independent child process). </description> </method> - <method name="dump_resources_to_file"> - <return type="void" /> - <param index="0" name="file" type="String" /> - <description> - Dumps all used resources to file (only works in debug). - Entry format per line: "Resource Type : Resource Location". - At the end of the file is a statistic of all used Resource Types. - </description> - </method> <method name="execute"> <return type="int" /> <param index="0" name="path" type="String" /> @@ -526,33 +517,6 @@ [b]Note:[/b] This method is implemented on Linux, macOS and Windows. </description> </method> - <method name="print_all_resources"> - <return type="void" /> - <param index="0" name="tofile" type="String" default="""" /> - <description> - Shows all resources in the game. Optionally, the list can be written to a file by specifying a file path in [param tofile]. - </description> - </method> - <method name="print_all_textures_by_size"> - <return type="void" /> - <description> - Shows the list of loaded textures sorted by size in memory. - </description> - </method> - <method name="print_resources_by_type"> - <return type="void" /> - <param index="0" name="types" type="PackedStringArray" /> - <description> - Shows the number of resources loaded by the game of the given types. - </description> - </method> - <method name="print_resources_in_use"> - <return type="void" /> - <param index="0" name="short" type="bool" default="false" /> - <description> - Shows all resources currently used by the game. - </description> - </method> <method name="request_permission"> <return type="bool" /> <param index="0" name="name" type="String" /> diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml index 754d3ac73d..97595a6984 100644 --- a/doc/classes/PackedScene.xml +++ b/doc/classes/PackedScene.xml @@ -92,7 +92,7 @@ <return type="Node" /> <param index="0" name="edit_state" type="int" enum="PackedScene.GenEditState" default="0" /> <description> - Instantiates the scene's node hierarchy. Triggers child scene instantiation(s). Triggers a [constant Node.NOTIFICATION_INSTANCED] notification on the root node. + Instantiates the scene's node hierarchy. Triggers child scene instantiation(s). Triggers a [constant Node.NOTIFICATION_SCENE_INSTANTIATED] notification on the root node. </description> </method> <method name="pack"> diff --git a/doc/classes/ParticleProcessMaterial.xml b/doc/classes/ParticleProcessMaterial.xml index 1526658eed..a41207e9b3 100644 --- a/doc/classes/ParticleProcessMaterial.xml +++ b/doc/classes/ParticleProcessMaterial.xml @@ -129,13 +129,16 @@ Should collision take scale into account. </member> <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> - Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. To have particle display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D.vertex_color_use_as_albedo] to [code]true[/code]. + Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. + [b]Note:[/b] [member color] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color] will have no visible effect. </member> <member name="color_initial_ramp" type="Texture2D" setter="set_color_initial_ramp" getter="get_color_initial_ramp"> Each particle's initial color will vary along this [GradientTexture1D] (multiplied with [member color]). + [b]Note:[/b] [member color_initial_ramp] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color_initial_ramp] will have no visible effect. </member> <member name="color_ramp" type="Texture2D" setter="set_color_ramp" getter="get_color_ramp"> Each particle's color will vary along this [GradientTexture1D] over its lifetime (multiplied with [member color]). + [b]Note:[/b] [member color_ramp] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color_ramp] will have no visible effect. </member> <member name="damping_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Damping will vary along this [CurveTexture]. @@ -154,6 +157,7 @@ </member> <member name="emission_color_texture" type="Texture2D" setter="set_emission_color_texture" getter="get_emission_color_texture"> Particle color will be modulated by color determined by sampling this texture at the same point as the [member emission_point_texture]. + [b]Note:[/b] [member emission_color_texture] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member emission_color_texture] will have no visible effect. </member> <member name="emission_normal_texture" type="Texture2D" setter="set_emission_normal_texture" getter="get_emission_normal_texture"> Particle velocity and rotation will be set by sampling this texture at the same point as the [member emission_point_texture]. Used only in [constant EMISSION_SHAPE_DIRECTED_POINTS]. Can be created automatically from mesh or node by selecting "Create Emission Points from Mesh/Node" under the "Particles" tool in the toolbar. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 8f749f3a37..fa7fad9e40 100644 --- a/doc/classes/ProjectSettings.xml +++ b/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> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index f1cd4d72f7..316bb923b7 100644 --- a/doc/classes/String.xml +++ b/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"> @@ -775,6 +775,12 @@ Converts the String (which is a character array) to ASCII/Latin-1 encoded [PackedByteArray] (which is an array of bytes). The conversion is faster compared to [method to_utf8_buffer], as this method assumes that all the characters in the String are ASCII/Latin-1 characters, unsupported characters are replaced with spaces. </description> </method> + <method name="to_camel_case" qualifiers="const"> + <return type="String" /> + <description> + Returns the string converted to [code]camelCase[/code]. + </description> + </method> <method name="to_float" qualifiers="const"> <return type="float" /> <description> @@ -804,6 +810,18 @@ Returns the string converted to lowercase. </description> </method> + <method name="to_pascal_case" qualifiers="const"> + <return type="String" /> + <description> + Returns the string converted to [code]PascalCase[/code]. + </description> + </method> + <method name="to_snake_case" qualifiers="const"> + <return type="String" /> + <description> + Returns the string converted to [code]snake_case[/code]. + </description> + </method> <method name="to_upper" qualifiers="const"> <return type="String" /> <description> diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 6d4408cf61..fdae6d205d 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -16,9 +16,9 @@ <param index="1" name="button" type="Texture2D" /> <param index="2" name="id" type="int" default="-1" /> <param index="3" name="disabled" type="bool" default="false" /> - <param index="4" name="tooltip" type="String" default="""" /> + <param index="4" name="tooltip_text" type="String" default="""" /> <description> - Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip]. + Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip_text]. </description> </method> <method name="call_recursive" qualifiers="vararg"> @@ -96,12 +96,12 @@ Returns the id for the button at index [param button_idx] in column [param column]. </description> </method> - <method name="get_button_tooltip" qualifiers="const"> + <method name="get_button_tooltip_text" qualifiers="const"> <return type="String" /> <param index="0" name="column" type="int" /> <param index="1" name="button_idx" type="int" /> <description> - Returns the tooltip string for the button at index [param button_idx] in column [param column]. + Returns the tooltip text for the button at index [param button_idx] in column [param column]. </description> </method> <method name="get_cell_mode" qualifiers="const"> @@ -308,11 +308,11 @@ Returns item's text base writing direction. </description> </method> - <method name="get_tooltip" qualifiers="const"> + <method name="get_tooltip_text" qualifiers="const"> <return type="String" /> <param index="0" name="column" type="int" /> <description> - Returns the given column's tooltip. + Returns the given column's tooltip text. </description> </method> <method name="get_tree" qualifiers="const"> @@ -639,7 +639,7 @@ Sets item's text base writing direction. </description> </method> - <method name="set_tooltip"> + <method name="set_tooltip_text"> <return type="void" /> <param index="0" name="column" type="int" /> <param index="1" name="tooltip" type="String" /> diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 21ccef3518..033f10dbc5 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/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()); diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index b8b72b8d30..55ea952696 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/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); diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 0fbd9f7b8f..384f46c8df 100644 --- a/drivers/unix/os_unix.cpp +++ b/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 { diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index afc3e78372..b52179b4f3 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -1436,6 +1436,24 @@ bool VulkanContext::_use_validation_layers() { return Engine::get_singleton()->is_validation_layers_enabled(); } +VkExtent2D VulkanContext::_compute_swapchain_extent(const VkSurfaceCapabilitiesKHR &p_surf_capabilities, int *p_window_width, int *p_window_height) const { + // Width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF. + if (p_surf_capabilities.currentExtent.width == 0xFFFFFFFF) { + // If the surface size is undefined, the size is set to the size + // of the images requested, which must fit within the minimum and + // maximum values. + VkExtent2D extent = {}; + extent.width = CLAMP((uint32_t)(*p_window_width), p_surf_capabilities.minImageExtent.width, p_surf_capabilities.maxImageExtent.width); + extent.height = CLAMP((uint32_t)(*p_window_height), p_surf_capabilities.minImageExtent.height, p_surf_capabilities.maxImageExtent.height); + return extent; + } else { + // If the surface size is defined, the swap chain size must match. + *p_window_width = p_surf_capabilities.currentExtent.width; + *p_window_height = p_surf_capabilities.currentExtent.height; + return p_surf_capabilities.currentExtent; + } +} + Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height) { ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER); @@ -1576,32 +1594,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { ERR_FAIL_V(ERR_CANT_CREATE); } - VkExtent2D swapchainExtent; - // Width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF. - if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) { - // If the surface size is undefined, the size is set to the size - // of the images requested, which must fit within the minimum and - // maximum values. - swapchainExtent.width = window->width; - swapchainExtent.height = window->height; - - if (swapchainExtent.width < surfCapabilities.minImageExtent.width) { - swapchainExtent.width = surfCapabilities.minImageExtent.width; - } else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width) { - swapchainExtent.width = surfCapabilities.maxImageExtent.width; - } - - if (swapchainExtent.height < surfCapabilities.minImageExtent.height) { - swapchainExtent.height = surfCapabilities.minImageExtent.height; - } else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height) { - swapchainExtent.height = surfCapabilities.maxImageExtent.height; - } - } else { - // If the surface size is defined, the swap chain size must match. - swapchainExtent = surfCapabilities.currentExtent; - window->width = surfCapabilities.currentExtent.width; - window->height = surfCapabilities.currentExtent.height; - } + VkExtent2D swapchainExtent = _compute_swapchain_extent(surfCapabilities, &window->width, &window->height); if (window->width == 0 || window->height == 0) { free(presentModes); diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h index 5cc3b515d9..9889cf336b 100644 --- a/drivers/vulkan/vulkan_context.h +++ b/drivers/vulkan/vulkan_context.h @@ -266,6 +266,8 @@ protected: Error _get_preferred_validation_layers(uint32_t *count, const char *const **names); + virtual VkExtent2D _compute_swapchain_extent(const VkSurfaceCapabilitiesKHR &p_surf_capabilities, int *p_window_width, int *p_window_height) const; + public: // Extension calls. VkResult vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass); diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 2125709b32..11fd29c8f5 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/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); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 587c16c229..dce9ca2b93 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -753,22 +753,12 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) { } Dictionary subst; - - String s = node_name.capitalize().replace(" ", ""); - subst["NodeName"] = s; - if (!s.is_empty()) { - s[0] = s.to_lower()[0]; - } - subst["nodeName"] = s; - subst["node_name"] = node_name.capitalize().replace(" ", "_").to_lower(); - - s = signal_name.capitalize().replace(" ", ""); - subst["SignalName"] = s; - if (!s.is_empty()) { - s[0] = s.to_lower()[0]; - } - subst["signalName"] = s; - subst["signal_name"] = signal_name.capitalize().replace(" ", "_").to_lower(); + subst["NodeName"] = node_name.to_pascal_case(); + subst["nodeName"] = node_name.to_camel_case(); + subst["node_name"] = node_name.to_snake_case(); + subst["SignalName"] = signal_name.to_pascal_case(); + subst["signalName"] = signal_name.to_camel_case(); + subst["signal_name"] = signal_name.to_snake_case(); String dst_method = String(EDITOR_GET("interface/editors/default_signal_callback_name")).format(subst); @@ -1070,7 +1060,7 @@ void ConnectionsDock::update_tree() { } // "::" separators used in make_custom_tooltip for formatting. - signal_item->set_tooltip(0, String(signal_name) + "::" + signaldesc + "::" + descr); + signal_item->set_tooltip_text(0, String(signal_name) + "::" + signaldesc + "::" + descr); } // List existing connections. diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 03e636d43a..8ccfda1145 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -313,7 +313,7 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String } const String &description = DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description); - r_item->set_tooltip(0, description); + r_item->set_tooltip_text(0, description); if (p_type_category == TypeCategory::OTHER_TYPE && !script_type) { Ref<Texture2D> icon = EditorNode::get_editor_data().get_custom_types()[custom_type_parents[p_type]][custom_type_indices[p_type]].icon; @@ -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(); diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp index dbd2c61d44..76efcd7190 100644 --- a/editor/debugger/editor_debugger_tree.cpp +++ b/editor/debugger/editor_debugger_tree.cpp @@ -155,7 +155,7 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int const SceneDebuggerTree::RemoteNode &node = p_tree->nodes[i]; TreeItem *item = create_item(parent); item->set_text(0, node.name); - item->set_tooltip(0, TTR("Type:") + " " + node.type_name); + item->set_tooltip_text(0, TTR("Type:") + " " + node.type_name); Ref<Texture2D> icon = EditorNode::get_singleton()->get_class_icon(node.type_name, ""); if (icon.is_valid()) { item->set_icon(0, icon); diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp index 22f1b93f71..10b50a81e4 100644 --- a/editor/debugger/editor_performance_profiler.cpp +++ b/editor/debugger/editor_performance_profiler.cpp @@ -61,7 +61,7 @@ void EditorPerformanceProfiler::Monitor::update_value(float p_value) { } break; } item->set_text(1, label); - item->set_tooltip(1, tooltip); + item->set_tooltip_text(1, tooltip); if (p_value > max) { max = p_value; @@ -73,7 +73,7 @@ void EditorPerformanceProfiler::Monitor::reset() { max = 0.0f; if (item) { item->set_text(1, ""); - item->set_tooltip(1, ""); + item->set_tooltip_text(1, ""); } } diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp index 6a3fe47976..cf48366bd3 100644 --- a/editor/debugger/editor_profiler.cpp +++ b/editor/debugger/editor_profiler.cpp @@ -356,7 +356,7 @@ void EditorProfiler::_update_frame() { item->set_metadata(1, it.script); item->set_metadata(2, it.line); item->set_text_alignment(2, HORIZONTAL_ALIGNMENT_RIGHT); - item->set_tooltip(0, it.name + "\n" + it.script + ":" + itos(it.line)); + item->set_tooltip_text(0, it.name + "\n" + it.script + ":" + itos(it.line)); float time = dtime == DISPLAY_SELF_TIME ? it.self : it.total; diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index fab211f18c..5baa9970af 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -580,8 +580,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da stack_trace->set_text(1, frame_txt); } - error->set_tooltip(0, tooltip); - error->set_tooltip(1, tooltip); + error->set_tooltip_text(0, tooltip); + error->set_tooltip_text(1, tooltip); if (warning_count == 0 && error_count == 0) { expand_all_button->set_disabled(false); diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 489a55ede0..ec9a744e57 100644 --- a/editor/doc_tools.cpp +++ b/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 + "."); diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp index 8dc8a0ab6b..aaa5956c17 100644 --- a/editor/editor_asset_installer.cpp +++ b/editor/editor_asset_installer.cpp @@ -215,11 +215,11 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) { if (FileAccess::exists(res_path)) { num_file_conflicts += 1; ti->set_custom_color(0, tree->get_theme_color(SNAME("error_color"), SNAME("Editor"))); - ti->set_tooltip(0, vformat(TTR("%s (already exists)"), res_path)); + ti->set_tooltip_text(0, vformat(TTR("%s (already exists)"), res_path)); ti->set_checked(0, false); ti->propagate_check(0); } else { - ti->set_tooltip(0, res_path); + ti->set_tooltip_text(0, res_path); } ti->set_metadata(0, res_path); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 120ac5b984..544b6c7141 100644 --- a/editor/editor_autoload_settings.cpp +++ b/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().to_snake_case())), false, false); dialog->popup_centered(); } else { if (autoload_add(autoload_add_name->get_text(), autoload_add_path->get_text())) { @@ -371,7 +371,7 @@ void EditorAutoloadSettings::_autoload_open(const String &fpath) { void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) { // Convert the file name to PascalCase, which is the convention for classes in GDScript. - const String class_name = p_path.get_file().get_basename().capitalize().replace(" ", ""); + const String class_name = p_path.get_file().get_basename().to_pascal_case(); // If the name collides with a built-in class, prefix the name to make it possible to add without having to edit the name. // The prefix is subjective, but it provides better UX than leaving the Add button disabled :) @@ -580,7 +580,7 @@ void EditorAutoloadSettings::_script_created(Ref<Script> p_script) { FileSystemDock::get_singleton()->get_script_create_dialog()->hide(); path = p_script->get_path().get_base_dir(); autoload_add_path->set_text(p_script->get_path()); - autoload_add_name->set_text(p_script->get_path().get_file().get_basename().capitalize().replace(" ", "")); + autoload_add_name->set_text(p_script->get_path().get_file().get_basename().to_pascal_case()); _autoload_add(); } diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp index 4071722185..3bb050ce77 100644 --- a/editor/editor_dir_dialog.cpp +++ b/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 diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index f0bf9fd5b3..708173ea26 100644 --- a/editor/editor_feature_profile.cpp +++ b/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; @@ -630,7 +630,7 @@ void EditorFeatureProfileManager::_class_list_item_selected() { property->set_selectable(0, true); property->set_checked(0, !edited->is_class_property_disabled(class_name, name)); property->set_text(0, text); - property->set_tooltip(0, tooltip); + property->set_tooltip_text(0, tooltip); property->set_metadata(0, name); String icon_type = Variant::get_type_name(E.type); property->set_icon(0, EditorNode::get_singleton()->get_class_icon(icon_type)); @@ -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(); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 5d249b0fab..e24aa995c8 100644 --- a/editor/editor_file_dialog.cpp +++ b/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())); } } diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index bda2e283ef..177bc6d2b2 100644 --- a/editor/editor_file_system.cpp +++ b/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; } diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp index c1d6e505db..d455e0248e 100644 --- a/editor/editor_folding.cpp +++ b/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); } diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index fe03166a01..97f5363bb8 100644 --- a/editor/editor_help.cpp +++ b/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 { diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index b4678d8363..2e35f21e47 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -562,8 +562,8 @@ TreeItem *EditorHelpSearch::Runner::_create_class_item(TreeItem *p_parent, const item->set_icon(0, icon); item->set_text(0, p_doc->name); item->set_text(1, TTR("Class")); - item->set_tooltip(0, tooltip); - item->set_tooltip(1, tooltip); + item->set_tooltip_text(0, tooltip); + item->set_tooltip_text(1, tooltip); item->set_metadata(0, "class_name:" + p_doc->name); if (p_gray) { item->set_custom_color(0, disabled_color); @@ -639,8 +639,8 @@ TreeItem *EditorHelpSearch::Runner::_create_member_item(TreeItem *p_parent, cons item->set_icon(0, icon); item->set_text(0, text); item->set_text(1, TTRGET(p_type)); - item->set_tooltip(0, p_tooltip); - item->set_tooltip(1, p_tooltip); + item->set_tooltip_text(0, p_tooltip); + item->set_tooltip_text(1, p_tooltip); item->set_metadata(0, "class_" + p_metatype + ":" + p_class_name + ":" + p_name); _match_item(item, p_name); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 587c84af3d..6aa0bd3f99 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -961,7 +961,7 @@ void EditorProperty::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keying"), "set_keying", "is_keying"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deletable"), "set_deletable", "is_deletable"); - ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); + ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::STRING_NAME, "field"), PropertyInfo(Variant::BOOL, "changing"))); ADD_SIGNAL(MethodInfo("multiple_properties_changed", PropertyInfo(Variant::PACKED_STRING_ARRAY, "properties"), PropertyInfo(Variant::ARRAY, "value"))); ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING_NAME, "property"))); ADD_SIGNAL(MethodInfo("property_deleted", PropertyInfo(Variant::STRING_NAME, "property"))); diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 86b0145240..a3d4296edb 100644 --- a/editor/editor_log.cpp +++ b/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"; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 98052cb2c6..7d4c376709 100644 --- a/editor/editor_node.cpp +++ b/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"); @@ -1314,7 +1314,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String file->set_current_file(p_resource->get_path().get_file()); } else { if (extensions.size()) { - String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore(); + String resource_name_snake_case = p_resource->get_class().to_snake_case(); file->set_current_file("new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower()); } else { file->set_current_file(String()); @@ -1331,7 +1331,7 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String } else if (preferred.size()) { String existing; if (extensions.size()) { - String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore(); + String resource_name_snake_case = p_resource->get_class().to_snake_case(); existing = "new_" + resource_name_snake_case + "." + preferred.front()->get().to_lower(); } file->set_current_path(existing); @@ -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"; @@ -2730,10 +2730,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { // Use casing of the root node. break; case SCENE_NAME_CASING_PASCAL_CASE: { - root_name = root_name.capitalize().replace(" ", ""); + root_name = root_name.to_pascal_case(); } break; case SCENE_NAME_CASING_SNAKE_CASE: - root_name = root_name.capitalize().replace(" ", "").replace("-", "_").camelcase_to_underscore(); + root_name = root_name.replace("-", "_").to_snake_case(); break; } file->set_current_path(root_name + "." + extensions.front()->get().to_lower()); @@ -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(); } diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp index b6364e1ab7..54d4660cb6 100644 --- a/editor/editor_paths.cpp +++ b/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); diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index 5a010a66c1..a8df486381 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -102,7 +102,7 @@ void EditorPluginSettings::update_plugins() { TreeItem *item = plugin_list->create_item(root); item->set_text(0, name); - item->set_tooltip(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + script + "\n" + TTR("Description:") + " " + description); + item->set_tooltip_text(0, TTR("Name:") + " " + name + "\n" + TTR("Path:") + " " + path + "\n" + TTR("Main Script:") + " " + script + "\n" + TTR("Description:") + " " + description); item->set_metadata(0, path); item->set_text(1, version); item->set_metadata(1, script); @@ -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 { diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index c0ea2b743e..706b77c142 100644 --- a/editor/editor_resource_preview.cpp +++ b/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 diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index 1faefb5af7..94ee741db5 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -283,7 +283,7 @@ void SectionedInspector::update_category_list() { const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], tooltip_style); ms->set_text(0, text); - ms->set_tooltip(0, tooltip); + ms->set_tooltip_text(0, tooltip); ms->set_metadata(0, metasection); ms->set_selectable(0, false); } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index f5d3b4842d..edd44b0a3a 100644 --- a/editor/editor_settings.cpp +++ b/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 { diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index 67c602ad2d..d190ab57c3 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -440,7 +440,7 @@ void EditorSettingsDialog::_update_shortcuts() { const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style); section->set_text(0, item_name); - section->set_tooltip(0, tooltip); + section->set_tooltip_text(0, tooltip); section->set_selectable(0, false); section->set_selectable(1, false); section->set_custom_bg_color(0, shortcuts->get_theme_color(SNAME("prop_subsection"), SNAME("Editor"))); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 827a657a31..d20caef51c 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -476,6 +476,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color font_color = mono_color.lerp(base_color, 0.25); const Color font_hover_color = mono_color.lerp(base_color, 0.125); const Color font_focus_color = mono_color.lerp(base_color, 0.125); + const Color font_hover_pressed_color = font_hover_color.lerp(accent_color, 0.74); const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.3); const Color font_readonly_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.65); const Color font_placeholder_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.6); @@ -750,6 +751,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "MenuButton", font_color); theme->set_color("font_hover_color", "MenuButton", font_hover_color); + theme->set_color("font_hover_pressed_color", "MenuButton", font_hover_pressed_color); theme->set_color("font_focus_color", "MenuButton", font_focus_color); theme->set_stylebox("MenuHover", "EditorStyles", style_widget_hover); @@ -763,6 +765,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "Button", font_color); theme->set_color("font_hover_color", "Button", font_hover_color); + theme->set_color("font_hover_pressed_color", "Button", font_hover_pressed_color); theme->set_color("font_focus_color", "Button", font_focus_color); theme->set_color("font_pressed_color", "Button", accent_color); theme->set_color("font_disabled_color", "Button", font_disabled_color); @@ -815,6 +818,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "MenuBar", font_color); theme->set_color("font_hover_color", "MenuBar", font_hover_color); + theme->set_color("font_hover_pressed_color", "MenuBar", font_hover_pressed_color); theme->set_color("font_focus_color", "MenuBar", font_focus_color); theme->set_color("font_pressed_color", "MenuBar", accent_color); theme->set_color("font_disabled_color", "MenuBar", font_disabled_color); @@ -851,6 +855,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "OptionButton", font_color); theme->set_color("font_hover_color", "OptionButton", font_hover_color); + theme->set_color("font_hover_pressed_color", "OptionButton", font_hover_pressed_color); theme->set_color("font_focus_color", "OptionButton", font_focus_color); theme->set_color("font_pressed_color", "OptionButton", accent_color); theme->set_color("font_disabled_color", "OptionButton", font_disabled_color); @@ -885,6 +890,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "CheckButton", font_color); theme->set_color("font_hover_color", "CheckButton", font_hover_color); + theme->set_color("font_hover_pressed_color", "CheckButton", font_hover_pressed_color); theme->set_color("font_focus_color", "CheckButton", font_focus_color); theme->set_color("font_pressed_color", "CheckButton", accent_color); theme->set_color("font_disabled_color", "CheckButton", font_disabled_color); @@ -921,6 +927,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "CheckBox", font_color); theme->set_color("font_hover_color", "CheckBox", font_hover_color); + theme->set_color("font_hover_pressed_color", "CheckBox", font_hover_pressed_color); theme->set_color("font_focus_color", "CheckBox", font_focus_color); theme->set_color("font_pressed_color", "CheckBox", accent_color); theme->set_color("font_disabled_color", "CheckBox", font_disabled_color); @@ -1478,6 +1485,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("focus", "LinkButton", style_empty); theme->set_color("font_color", "LinkButton", font_color); theme->set_color("font_hover_color", "LinkButton", font_hover_color); + theme->set_color("font_hover_pressed_color", "LinkButton", font_hover_pressed_color); theme->set_color("font_focus_color", "LinkButton", font_focus_color); theme->set_color("font_pressed_color", "LinkButton", accent_color); theme->set_color("font_disabled_color", "LinkButton", font_disabled_color); @@ -1508,8 +1516,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { control_editor_popup_style->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE); control_editor_popup_style->set_border_width_all(0); - theme->set_stylebox("panel", "ControlEditorPopupButton", control_editor_popup_style); - theme->set_type_variation("ControlEditorPopupButton", "PopupPanel"); + theme->set_stylebox("panel", "ControlEditorPopupPanel", control_editor_popup_style); + theme->set_type_variation("ControlEditorPopupPanel", "PopupPanel"); // SpinBox theme->set_icon("updown", "SpinBox", theme->get_icon(SNAME("GuiSpinboxUpdown"), SNAME("EditorIcons"))); diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp index cb188f9c3e..53cc8d5b22 100644 --- a/editor/editor_vcs_interface.cpp +++ b/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 { diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 8283c24e61..e07b5e4cdb 100644 --- a/editor/export/editor_export_platform.cpp +++ b/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)); diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp index 9fca4c908a..8538414523 100644 --- a/editor/export/editor_export_platform_pc.cpp +++ b/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)) { diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp index cf3a9b0810..27a671a919 100644 --- a/editor/export/editor_export_plugin.cpp +++ b/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); diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp index a0afcf4237..0ecbc9a8a3 100644 --- a/editor/export/export_template_manager.cpp +++ b/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()); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index a42433caee..19788e70da 100644 --- a/editor/filesystem_dock.cpp +++ b/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); @@ -276,7 +276,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo ti->set_text(0, text); ti->set_icon(0, icon); ti->set_icon_modulate(0, color); - ti->set_tooltip(0, fave); + ti->set_tooltip_text(0, fave); ti->set_selectable(0, true); ti->set_metadata(0, fave); if (p_select_in_favorites && fave == path) { @@ -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)"; } diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 56387e87f5..16c5003fdc 100644 --- a/editor/find_in_files.cpp +++ b/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)); } } } diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 15add50fd4..dac86acae4 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -89,7 +89,7 @@ void GroupDialog::_load_nodes(Node *p_current) { if (keep) { node->set_text(0, item_name); node->set_metadata(0, path); - node->set_tooltip(0, path); + node->set_tooltip_text(0, path); Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(p_current, "Node"); node->set_icon(0, icon); diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp index 5b9ed2c1d2..5d8e453395 100644 --- a/editor/import/collada.cpp +++ b/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:///", ""); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index d1c4e1f8dd..fe70fd58b5 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/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) { diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp index d3079141e0..55afd71c76 100644 --- a/editor/import/resource_importer_shader_file.cpp +++ b/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); diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index 6c12464b5a..1ff771bcce 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -176,7 +176,7 @@ void SceneImportSettings::_fill_material(Tree *p_tree, const Ref<Material> &p_ma item->set_meta("type", "Material"); item->set_meta("import_id", import_id); - item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id)); + item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id)); item->set_selectable(0, true); if (p_tree == scene_tree) { @@ -232,7 +232,7 @@ void SceneImportSettings::_fill_mesh(Tree *p_tree, const Ref<Mesh> &p_mesh, Tree item->set_meta("type", "Mesh"); item->set_meta("import_id", import_id); - item->set_tooltip(0, vformat(TTR("Import ID: %s"), import_id)); + item->set_tooltip_text(0, vformat(TTR("Import ID: %s"), import_id)); item->set_selectable(0, true); @@ -331,7 +331,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) { item->set_meta("type", "Node"); item->set_meta("class", type); item->set_meta("import_id", import_id); - item->set_tooltip(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id)); + item->set_tooltip_text(0, vformat(TTR("Type: %s\nImport ID: %s"), type, import_id)); item->set_selectable(0, true); @@ -979,7 +979,7 @@ void SceneImportSettings::_save_path_changed(const String &p_path) { if (FileAccess::exists(p_path)) { save_path_item->set_text(2, "Warning: File exists"); - save_path_item->set_tooltip(2, TTR("Existing file with the same name will be replaced.")); + save_path_item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced.")); save_path_item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); } else { @@ -1024,12 +1024,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { if (md.has_import_id) { if (md.settings.has("use_external/enabled") && bool(md.settings["use_external/enabled"])) { item->set_text(2, "Already External"); - item->set_tooltip(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again.")); + item->set_tooltip_text(2, TTR("This material already references an external file, no action will be taken.\nDisable the external property for it to be extracted again.")); } else { 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 { @@ -1039,7 +1039,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { item->set_text(1, path); if (FileAccess::exists(path)) { item->set_text(2, "Warning: File exists"); - item->set_tooltip(2, TTR("Existing file with the same name will be replaced.")); + item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced.")); item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); } else { @@ -1052,7 +1052,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { } else { item->set_text(2, "No import ID"); - item->set_tooltip(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID.")); + item->set_tooltip_text(2, TTR("Material has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID.")); item->set_icon(2, get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons"))); } @@ -1077,12 +1077,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { if (md.has_import_id) { if (md.settings.has("save_to_file/enabled") && bool(md.settings["save_to_file/enabled"])) { item->set_text(2, "Already Saving"); - item->set_tooltip(2, TTR("This mesh already saves to an external resource, no action will be taken.")); + item->set_tooltip_text(2, TTR("This mesh already saves to an external resource, no action will be taken.")); } else { 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 { @@ -1092,7 +1092,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { item->set_text(1, path); if (FileAccess::exists(path)) { item->set_text(2, "Warning: File exists"); - item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import.")); + item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import.")); item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); } else { @@ -1105,7 +1105,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { } else { item->set_text(2, "No import ID"); - item->set_tooltip(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID.")); + item->set_tooltip_text(2, TTR("Mesh has no name nor any other way to identify on re-import.\nPlease name it or ensure it is exported with an unique ID.")); item->set_icon(2, get_theme_icon(SNAME("StatusError"), SNAME("EditorIcons"))); } @@ -1129,12 +1129,12 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { if (ad.settings.has("save_to_file/enabled") && bool(ad.settings["save_to_file/enabled"])) { item->set_text(2, "Already Saving"); - item->set_tooltip(2, TTR("This animation already saves to an external resource, no action will be taken.")); + item->set_tooltip_text(2, TTR("This animation already saves to an external resource, no action will be taken.")); } else { 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 { @@ -1144,7 +1144,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) { item->set_text(1, path); if (FileAccess::exists(path)) { item->set_text(2, "Warning: File exists"); - item->set_tooltip(2, TTR("Existing file with the same name will be replaced on import.")); + item->set_tooltip_text(2, TTR("Existing file with the same name will be replaced on import.")); item->set_icon(2, get_theme_icon(SNAME("StatusWarning"), SNAME("EditorIcons"))); } else { diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 02270e163f..4732268256 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -628,6 +628,9 @@ ImportDock::ImportDock() { content->add_margin_child(TTR("Import As:"), hb); import_as = memnew(OptionButton); import_as->set_disabled(true); + import_as->set_fit_to_longest_item(false); + import_as->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); + import_as->set_h_size_flags(SIZE_EXPAND_FILL); import_as->connect("item_selected", callable_mp(this, &ImportDock::_importer_selected)); hb->add_child(import_as); import_as->set_h_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp index 77a1700ebf..683481ecc1 100644 --- a/editor/localization_editor.cpp +++ b/editor/localization_editor.cpp @@ -193,7 +193,7 @@ void LocalizationEditor::_translation_res_option_popup(bool p_arrow_clicked) { TreeItem *ed = translation_remap_options->get_edited(); ERR_FAIL_COND(!ed); - locale_select->set_locale(ed->get_tooltip(1)); + locale_select->set_locale(ed->get_tooltip_text(1)); locale_select->popup_locale_dialog(); } @@ -202,7 +202,7 @@ void LocalizationEditor::_translation_res_option_selected(const String &p_locale ERR_FAIL_COND(!ed); ed->set_text(1, TranslationServer::get_singleton()->get_locale_name(p_locale)); - ed->set_tooltip(1, p_locale); + ed->set_tooltip_text(1, p_locale); LocalizationEditor::_translation_res_option_changed(); } @@ -226,7 +226,7 @@ void LocalizationEditor::_translation_res_option_changed() { String key = k->get_metadata(0); int idx = ed->get_metadata(0); String path = ed->get_metadata(1); - String locale = ed->get_tooltip(1); + String locale = ed->get_tooltip_text(1); ERR_FAIL_COND(!remaps.has(key)); PackedStringArray r = remaps[key]; @@ -486,7 +486,7 @@ void LocalizationEditor::update_translations() { TreeItem *t = translation_list->create_item(root); t->set_editable(0, false); t->set_text(0, translations[i].replace_first("res://", "")); - t->set_tooltip(0, translations[i]); + t->set_tooltip_text(0, translations[i]); t->set_metadata(0, i); t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove")); } @@ -520,14 +520,14 @@ void LocalizationEditor::update_translations() { TreeItem *t = translation_remap->create_item(root); t->set_editable(0, false); t->set_text(0, keys[i].replace_first("res://", "")); - t->set_tooltip(0, keys[i]); + t->set_tooltip_text(0, keys[i]); t->set_metadata(0, keys[i]); t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove")); // Display that it has been removed if this is the case. if (!FileAccess::exists(keys[i])) { t->set_text(0, t->get_text(0) + vformat(" (%s)", TTR("Removed"))); - t->set_tooltip(0, vformat(TTR("%s cannot be found."), t->get_tooltip(0))); + t->set_tooltip_text(0, vformat(TTR("%s cannot be found."), t->get_tooltip_text(0))); } if (keys[i] == remap_selected) { @@ -544,19 +544,19 @@ void LocalizationEditor::update_translations() { TreeItem *t2 = translation_remap_options->create_item(root2); t2->set_editable(0, false); t2->set_text(0, path.replace_first("res://", "")); - t2->set_tooltip(0, path); + t2->set_tooltip_text(0, path); t2->set_metadata(0, j); t2->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove")); t2->set_cell_mode(1, TreeItem::CELL_MODE_CUSTOM); t2->set_text(1, TranslationServer::get_singleton()->get_locale_name(locale)); t2->set_editable(1, true); t2->set_metadata(1, path); - t2->set_tooltip(1, locale); + t2->set_tooltip_text(1, locale); // Display that it has been removed if this is the case. if (!FileAccess::exists(path)) { t2->set_text(0, t2->get_text(0) + vformat(" (%s)", TTR("Removed"))); - t2->set_tooltip(0, vformat(TTR("%s cannot be found."), t2->get_tooltip(0))); + t2->set_tooltip_text(0, vformat(TTR("%s cannot be found."), t2->get_tooltip_text(0))); } } } @@ -573,7 +573,7 @@ void LocalizationEditor::update_translations() { TreeItem *t = translation_pot_list->create_item(root); t->set_editable(0, false); t->set_text(0, pot_translations[i].replace_first("res://", "")); - t->set_tooltip(0, pot_translations[i]); + t->set_tooltip_text(0, pot_translations[i]); t->set_metadata(0, i); t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove")); } diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp index 88aa6354e4..71ff77e9bc 100644 --- a/editor/plugin_config_dialog.cpp +++ b/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(); diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index f9e5aa799a..50ba1a71c0 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -635,7 +635,7 @@ void AnimationLibraryEditor::update_tree() { String al_path = al->get_path(); if (!al_path.is_resource_file()) { libitem->set_text(1, TTR("[built-in]")); - libitem->set_tooltip(1, al_path); + libitem->set_tooltip_text(1, al_path); int srpos = al_path.find("::"); if (srpos != -1) { String base = al_path.substr(0, srpos); @@ -687,7 +687,7 @@ void AnimationLibraryEditor::update_tree() { String anim_path = anim->get_path(); if (!anim_path.is_resource_file()) { anitem->set_text(1, TTR("[built-in]")); - anitem->set_tooltip(1, anim_path); + anitem->set_tooltip_text(1, anim_path); int srpos = anim_path.find("::"); if (srpos != -1) { String base = anim_path.substr(0, srpos); diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index bce4c9de8e..ed231c446b 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -59,10 +59,11 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) { Vector<String> path; if (tree && tree->has_meta("_tree_edit_path")) { path = tree->get_meta("_tree_edit_path"); - edit_path(path); } else { current_root = ObjectID(); } + + edit_path(path); } void AnimationTreeEditor::_path_button_pressed(int p_path) { @@ -129,6 +130,11 @@ void AnimationTreeEditor::edit_path(const Vector<String> &p_path) { } else { current_root = ObjectID(); edited_path = button_path; + + for (int i = 0; i < editors.size(); i++) { + editors[i]->edit(Ref<AnimationNode>()); + editors[i]->hide(); + } } _update_path(); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 025312c38c..41383edafe 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/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")) { diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index c16dca00a3..988f9cc394 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -609,7 +609,7 @@ int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_pic } BoneMapper::BoneSegregation BoneMapper::guess_bone_segregation(String p_bone_name) { - String fixed_bn = p_bone_name.camelcase_to_underscore().to_lower(); + String fixed_bn = p_bone_name.to_snake_case(); LocalVector<String> left_words; left_words.push_back("(?<![a-zA-Z])left"); diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp index 69f32a3a98..bb6092755e 100644 --- a/editor/plugins/control_editor_plugin.cpp +++ b/editor/plugins/control_editor_plugin.cpp @@ -523,7 +523,7 @@ ControlEditorPopupButton::ControlEditorPopupButton() { set_focus_mode(FOCUS_NONE); popup_panel = memnew(PopupPanel); - popup_panel->set_theme_type_variation("ControlEditorPopupButton"); + popup_panel->set_theme_type_variation("ControlEditorPopupPanel"); add_child(popup_panel); popup_panel->connect("about_to_popup", callable_mp(this, &ControlEditorPopupButton::_popup_visibility_changed).bind(true)); popup_panel->connect("popup_hide", callable_mp(this, &ControlEditorPopupButton::_popup_visibility_changed).bind(false)); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 0196214ceb..f4a718119e 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/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 diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index 80566419b1..21647d1b69 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -196,7 +196,7 @@ void ResourcePreloaderEditor::_update_library() { String type = r->get_class(); ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(type, "Object")); - ti->set_tooltip(0, TTR("Instance:") + " " + r->get_path() + "\n" + TTR("Type:") + " " + type); + ti->set_tooltip_text(0, TTR("Instance:") + " " + r->get_path() + "\n" + TTR("Type:") + " " + type); ti->set_text(1, r->get_path()); ti->set_editable(1, false); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 98be34cb86..aa1d630372 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/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; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 55776c19ae..fff956a05e 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/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(); } @@ -1590,7 +1590,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data } } - String variable_name = String(node->get_name()).camelcase_to_underscore(true).validate_identifier(); + String variable_name = String(node->get_name()).to_snake_case().validate_identifier(); if (use_type) { text_to_drop += vformat("@onready var %s: %s = %s%s\n", variable_name, node->get_class_name(), is_unique ? "%" : "$", path); } else { diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 53bc6fbdf4..6674d15268 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/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: { diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 91436db957..026d957407 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -690,8 +690,6 @@ void Skeleton3DEditor::update_editors() { void Skeleton3DEditor::create_editors() { set_h_size_flags(SIZE_EXPAND_FILL); - add_theme_constant_override("separation", 0); - set_focus_mode(FOCUS_ALL); Node3DEditor *ne = Node3DEditor::get_singleton(); @@ -823,20 +821,11 @@ void Skeleton3DEditor::create_editors() { void Skeleton3DEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { - edit_mode_button->set_icon(get_theme_icon(SNAME("ToolBoneSelect"), SNAME("EditorIcons"))); - key_loc_button->set_icon(get_theme_icon(SNAME("KeyPosition"), SNAME("EditorIcons"))); - key_rot_button->set_icon(get_theme_icon(SNAME("KeyRotation"), SNAME("EditorIcons"))); - key_scale_button->set_icon(get_theme_icon(SNAME("KeyScale"), SNAME("EditorIcons"))); - key_insert_button->set_icon(get_theme_icon(SNAME("Key"), SNAME("EditorIcons"))); - key_insert_all_button->set_icon(get_theme_icon(SNAME("NewKey"), SNAME("EditorIcons"))); - get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Object::CONNECT_ONESHOT); - break; - } case NOTIFICATION_ENTER_TREE: { create_editors(); update_joint_tree(); update_editors(); + joint_tree->connect("item_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed)); joint_tree->connect("item_mouse_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select)); #ifdef TOOLS_ENABLED @@ -845,8 +834,23 @@ void Skeleton3DEditor::_notification(int p_what) { skeleton->connect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed)); skeleton->connect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible)); #endif - break; - } + + get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Object::CONNECT_ONESHOT); + } break; + case NOTIFICATION_READY: { + // Will trigger NOTIFICATION_THEME_CHANGED, but won't cause any loops if called here. + add_theme_constant_override("separation", 0); + } break; + case NOTIFICATION_THEME_CHANGED: { + edit_mode_button->set_icon(get_theme_icon(SNAME("ToolBoneSelect"), SNAME("EditorIcons"))); + key_loc_button->set_icon(get_theme_icon(SNAME("KeyPosition"), SNAME("EditorIcons"))); + key_rot_button->set_icon(get_theme_icon(SNAME("KeyRotation"), SNAME("EditorIcons"))); + key_scale_button->set_icon(get_theme_icon(SNAME("KeyScale"), SNAME("EditorIcons"))); + key_insert_button->set_icon(get_theme_icon(SNAME("Key"), SNAME("EditorIcons"))); + key_insert_all_button->set_icon(get_theme_icon(SNAME("NewKey"), SNAME("EditorIcons"))); + + update_joint_tree(); + } break; } } diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index cdd088f0b1..83275a2a7b 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -41,9 +41,7 @@ const int ERROR_CODE = 77; #include "core/os/time.h" #include "core/templates/hash_map.h" #include "core/templates/list.h" - -const uint64_t CONVERSION_MAX_FILE_SIZE_MB = 4; -const uint64_t CONVERSION_MAX_FILE_SIZE = 1024 * 1024 * CONVERSION_MAX_FILE_SIZE_MB; +#include "core/templates/local_vector.h" static const char *enum_renames[][2] = { //// constants @@ -230,7 +228,6 @@ static const char *gdscript_function_renames[][2] = { { "add_stylebox_override", "add_theme_stylebox_override" }, // Control { "add_torque", "apply_torque" }, //RigidBody2D { "apply_changes", "_apply_changes" }, // EditorPlugin - { "bind_child_node_to_bone", "set_bone_children" }, // Skeleton3D { "body_add_force", "body_apply_force" }, // PhysicsServer2D { "body_add_torque", "body_apply_torque" }, // PhysicsServer2D { "bumpmap_to_normalmap", "bump_map_to_normal_map" }, // Image @@ -298,11 +295,11 @@ static const char *gdscript_function_renames[][2] = { { "get_d", "get_distance" }, // LineShape2D { "get_drag_data", "_get_drag_data" }, // Control { "get_drag_data_fw", "_get_drag_data_fw" }, // ScriptEditor - { "get_editor_description", "_get_editor_description" }, // Node { "get_editor_viewport", "get_viewport" }, // EditorPlugin { "get_enabled_focus_mode", "get_focus_mode" }, // BaseButton { "get_endian_swap", "is_big_endian" }, // File { "get_error_string", "get_error_message" }, // JSON + { "get_filename", "get_scene_file_path" }, // Node, WARNING, this may be used in a lot of other places { "get_focus_neighbour", "get_focus_neighbor" }, // Control { "get_font_types", "get_font_type_list" }, // Theme { "get_frame_color", "get_color" }, // ColorRect @@ -398,7 +395,6 @@ static const char *gdscript_function_renames[][2] = { { "has_stylebox_override", "has_theme_stylebox_override" }, // Control { "http_escape", "uri_encode" }, // String { "http_unescape", "uri_decode" }, // String - { "import_animation_from_other_importer", "_import_animation" }, //EditorSceneFormatImporter { "import_scene_from_other_importer", "_import_scene" }, //EditorSceneFormatImporter { "instance_set_surface_material", "instance_set_surface_override_material" }, // RenderingServer { "intersect_polygons_2d", "intersect_polygons" }, // Geometry2D @@ -546,7 +542,6 @@ static const char *gdscript_function_renames[][2] = { { "targeting_property", "tween_property" }, // Tween { "track_remove_key_at_position", "track_remove_key_at_time" }, // Animation { "triangulate_delaunay_2d", "triangulate_delaunay" }, // Geometry2D - { "unbind_child_node_from_bone", "remove_bone_child" }, // Skeleton3D { "unselect", "deselect" }, // ItemList { "unselect_all", "deselect_all" }, // ItemList { "update_configuration_warning", "update_configuration_warnings" }, // Node @@ -555,6 +550,7 @@ static const char *gdscript_function_renames[][2] = { { "warp_mouse_position", "warp_mouse" }, // Input // Builtin types + // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed // { "empty", "is_empty" }, // Array - Used as custom rule // Be careful, this will be used everywhere { "clamped", "clamp" }, // Vector2 // Be careful, this will be used everywhere { "get_rotation_quat", "get_rotation_quaternion" }, // Basis @@ -568,6 +564,7 @@ static const char *gdscript_function_renames[][2] = { { "to_wchar", "to_utf32_buffer" }, // String // TODO - utf32 or utf16? // @GlobalScope + // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed { "bytes2var", "bytes_to_var" }, { "bytes2var_with_objects", "bytes_to_var_with_objects" }, { "db2linear", "db_to_linear" }, @@ -582,6 +579,7 @@ static const char *gdscript_function_renames[][2] = { { "var2bytes_with_objects", "var_to_bytes_with_objects" }, // @GDScript + // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed { "dict2inst", "dict_to_inst" }, { "inst2dict", "inst_to_dict" }, @@ -1057,6 +1055,14 @@ static const char *gdscript_properties_renames[][2] = { { "pause_mode", "process_mode" }, // Node { "physical_scancode", "physical_keycode" }, // InputEventKey { "popup_exclusive", "exclusive" }, // Window + { "rect_position", "position" }, // Control + { "rect_global_position", "global_position" }, // Control + { "rect_size", "size" }, // Control + { "rect_min_size", "minimum_size" }, // Control + { "rect_rotation", "rotation" }, // Control + { "rect_scale", "scale" }, // Control + { "rect_pivot_offset", "pivot_offset" }, // Control + { "rect_clip_content", "clip_contents" }, // Control { "refuse_new_network_connections", "refuse_new_connections" }, // MultiplayerAPI { "region_filter_clip", "region_filter_clip_enabled" }, // Sprite2D { "selectedframe", "selected_frame" }, // Theme @@ -1271,9 +1277,19 @@ static const char *builtin_types_renames[][2] = { static const char *shaders_renames[][2] = { { "ALPHA_SCISSOR", "ALPHA_SCISSOR_THRESHOLD" }, + { "CAMERA_MATRIX", "INV_VIEW_MATRIX" }, + { "INV_CAMERA_MATRIX", "VIEW_MATRIX" }, { "NORMALMAP", "NORMAL_MAP" }, { "NORMALMAP_DEPTH", "NORMAL_MAP_DEPTH" }, - { "TRANSMISSION", "SSS_TRANSMITTANCE_COLOR" }, + { "TRANSMISSION", "BACKLIGHT" }, + { "WORLD_MATRIX", "MODEL_MATRIX" }, + { "depth_draw_alpha_prepass", "depth_draw_opaque" }, + { "hint_albedo", "source_color" }, + { "hint_aniso", "hint_anisotropy" }, + { "hint_black", "hint_default_black" }, + { "hint_black_albedo", "hint_default_black" }, + { "hint_color", "source_color" }, + { "hint_white", "hint_default_white" }, { nullptr, nullptr }, }; @@ -1494,7 +1510,7 @@ static const char *class_renames[][2] = { }; // TODO - this colors needs to be validated(not all are valid) -static const char *colors_renames[][2] = { +static const char *color_renames[][2] = { { "aliceblue", "ALICE_BLUE" }, { "antiquewhite", "ANTIQUE_WHITE" }, { "aqua", "AQUA" }, @@ -1647,6 +1663,7 @@ static const char *colors_renames[][2] = { class ProjectConverter3To4::RegExContainer { public: + // Custom GDScript RegEx reg_is_empty = RegEx("\\bempty\\("); RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])"); RegEx reg_json_to = RegEx("\\bto_json\\b"); @@ -1658,24 +1675,196 @@ public: RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^a-z^A-Z^0-9^_]*$"); RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$"); RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)"); - RegEx reg_mixed_tab_space = RegEx("([\t]+)([ ]+)"); RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)"); RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)"); RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)"); RegEx reg_instantiate = RegEx("\\.instance\\(([^\\)]*)\\)"); + + // GDScript keywords + RegEx keyword_gdscript_tool = RegEx("^tool"); + RegEx keyword_gdscript_export_single = RegEx("^export"); + RegEx keyword_gdscript_export_mutli = RegEx("([\t]+)export\\b"); + RegEx keyword_gdscript_onready = RegEx("^onready"); + RegEx keyword_gdscript_remote = RegEx("^remote func"); + RegEx keyword_gdscript_remotesync = RegEx("^remotesync func"); + RegEx keyword_gdscript_sync = RegEx("^sync func"); + RegEx keyword_gdscript_slave = RegEx("^slave func"); + RegEx keyword_gdscript_puppet = RegEx("^puppet func"); + RegEx keyword_gdscript_puppetsync = RegEx("^puppetsync func"); + RegEx keyword_gdscript_master = RegEx("^master func"); + RegEx keyword_gdscript_mastersync = RegEx("^mastersync func"); + + // CSharp keywords + RegEx keyword_csharp_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]"); + RegEx keyword_csharp_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]"); + RegEx keyword_csharp_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]"); + RegEx keyword_csharp_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]"); + RegEx keyword_csharp_master = RegEx("\\[Master(Attribute)?(\\(\\))?\\]"); + RegEx keyword_csharp_mastersync = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]"); + + // Colors + LocalVector<RegEx *> color_regexes; + LocalVector<String> color_renamed; + + // Classes + LocalVector<RegEx *> class_tscn_regexes; + LocalVector<RegEx *> class_gd_regexes; + LocalVector<RegEx *> class_shader_regexes; + + LocalVector<RegEx *> class_regexes; + + RegEx class_temp_tscn = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b"); + RegEx class_temp_gd = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b"); + RegEx class_temp_shader = RegEx("\\bTEMP_RENAMED_CLASS.shader\\b"); + + LocalVector<String> class_temp_tscn_renames; + LocalVector<String> class_temp_gd_renames; + LocalVector<String> class_temp_shader_renames; + + // Common + LocalVector<RegEx *> enum_regexes; + LocalVector<RegEx *> gdscript_function_regexes; + LocalVector<RegEx *> project_settings_regexes; + LocalVector<RegEx *> gdscript_properties_regexes; + LocalVector<RegEx *> gdscript_signals_regexes; + LocalVector<RegEx *> shaders_regexes; + LocalVector<RegEx *> builtin_types_regexes; + LocalVector<RegEx *> csharp_function_regexes; + LocalVector<RegEx *> csharp_properties_regexes; + LocalVector<RegEx *> csharp_signal_regexes; + + RegExContainer() { + // Common + { + // Enum + for (unsigned int current_index = 0; enum_renames[current_index][0]; current_index++) { + enum_regexes.push_back(memnew(RegEx(String("\\b") + enum_renames[current_index][0] + "\\b"))); + } + // GDScript functions + for (unsigned int current_index = 0; gdscript_function_renames[current_index][0]; current_index++) { + gdscript_function_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_function_renames[current_index][0] + "\\b"))); + } + // Project Settings + for (unsigned int current_index = 0; project_settings_renames[current_index][0]; current_index++) { + project_settings_regexes.push_back(memnew(RegEx(String("\\b") + project_settings_renames[current_index][0] + "\\b"))); + } + // GDScript properties + for (unsigned int current_index = 0; gdscript_properties_renames[current_index][0]; current_index++) { + gdscript_properties_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_properties_renames[current_index][0] + "\\b"))); + } + // GDScript Signals + for (unsigned int current_index = 0; gdscript_signals_renames[current_index][0]; current_index++) { + gdscript_signals_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_signals_renames[current_index][0] + "\\b"))); + } + // Shaders + for (unsigned int current_index = 0; shaders_renames[current_index][0]; current_index++) { + shaders_regexes.push_back(memnew(RegEx(String("\\b") + shaders_renames[current_index][0] + "\\b"))); + } + // Builtin types + for (unsigned int current_index = 0; builtin_types_renames[current_index][0]; current_index++) { + builtin_types_regexes.push_back(memnew(RegEx(String("\\b") + builtin_types_renames[current_index][0] + "\\b"))); + } + // CSharp function renames + for (unsigned int current_index = 0; csharp_function_renames[current_index][0]; current_index++) { + csharp_function_regexes.push_back(memnew(RegEx(String("\\b") + csharp_function_renames[current_index][0] + "\\b"))); + } + // CSharp properties renames + for (unsigned int current_index = 0; csharp_properties_renames[current_index][0]; current_index++) { + csharp_properties_regexes.push_back(memnew(RegEx(String("\\b") + csharp_properties_renames[current_index][0] + "\\b"))); + } + // CSharp signals renames + for (unsigned int current_index = 0; csharp_signals_renames[current_index][0]; current_index++) { + csharp_signal_regexes.push_back(memnew(RegEx(String("\\b") + csharp_signals_renames[current_index][0] + "\\b"))); + } + } + + // Colors + { + for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) { + color_regexes.push_back(memnew(RegEx(String("\\bColor.") + color_renames[current_index][0] + "\\b"))); + color_renamed.push_back(String("Color.") + color_renames[current_index][1]); + } + } + // Classes + { + for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) { + class_tscn_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b"))); + class_gd_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b"))); + class_shader_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".shader\\b"))); + + class_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + "\\b"))); + + class_temp_tscn_renames.push_back(String(class_renames[current_index][0]) + ".tscn"); + class_temp_gd_renames.push_back(String(class_renames[current_index][0]) + ".gd"); + class_temp_shader_renames.push_back(String(class_renames[current_index][0]) + ".shader"); + } + } + } + ~RegExContainer() { + for (unsigned int i = 0; i < color_regexes.size(); i++) { + memdelete(color_regexes[i]); + } + for (unsigned int i = 0; i < class_tscn_regexes.size(); i++) { + memdelete(class_tscn_regexes[i]); + memdelete(class_gd_regexes[i]); + memdelete(class_shader_regexes[i]); + memdelete(class_regexes[i]); + } + for (unsigned int i = 0; i < enum_regexes.size(); i++) { + memdelete(enum_regexes[i]); + } + for (unsigned int i = 0; i < gdscript_function_regexes.size(); i++) { + memdelete(gdscript_function_regexes[i]); + } + for (unsigned int i = 0; i < project_settings_regexes.size(); i++) { + memdelete(project_settings_regexes[i]); + } + for (unsigned int i = 0; i < gdscript_properties_regexes.size(); i++) { + memdelete(gdscript_properties_regexes[i]); + } + for (unsigned int i = 0; i < gdscript_signals_regexes.size(); i++) { + memdelete(gdscript_signals_regexes[i]); + } + for (unsigned int i = 0; i < shaders_regexes.size(); i++) { + memdelete(shaders_regexes[i]); + } + for (unsigned int i = 0; i < builtin_types_regexes.size(); i++) { + memdelete(builtin_types_regexes[i]); + } + for (unsigned int i = 0; i < csharp_function_regexes.size(); i++) { + memdelete(csharp_function_regexes[i]); + } + for (unsigned int i = 0; i < csharp_properties_regexes.size(); i++) { + memdelete(csharp_properties_regexes[i]); + } + for (unsigned int i = 0; i < csharp_signal_regexes.size(); i++) { + memdelete(csharp_signal_regexes[i]); + } + } }; +ProjectConverter3To4::ProjectConverter3To4(int maximum_file_size_kb, int maximum_line_length) { + this->maximum_file_size = maximum_file_size_kb * 1024; + this->maximum_line_length = maximum_line_length; +} + // Function responsible for converting project int ProjectConverter3To4::convert() { print_line("Starting conversion."); + uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec(); RegExContainer reg_container = RegExContainer(); + int cached_maximum_line_length = maximum_line_length; + maximum_line_length = 10000; // Use only for tests bigger value, to not break them + ERR_FAIL_COND_V_MSG(!test_array_names(), ERROR_CODE, "Cannot start converting due to problems with data in arrays."); ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), ERROR_CODE, "Cannot start converting due to problems with converting arrays."); + maximum_line_length = cached_maximum_line_length; + // Checking if folder contains valid Godot 3 project. - // Project cannot be converted 2 times + // Project should not be converted more than 1 times { String conventer_text = "; Project was converted by built-in tool to Godot 4.0"; @@ -1685,7 +1874,7 @@ int ProjectConverter3To4::convert() { String project_godot_content = FileAccess::get_file_as_string("project.godot", &err); ERR_FAIL_COND_V_MSG(err != OK, ERROR_CODE, "Failed to read content of \"project.godot\" file."); - ERR_FAIL_COND_V_MSG(project_godot_content.find(conventer_text) != -1, ERROR_CODE, "Project already was converted with this tool."); + ERR_FAIL_COND_V_MSG(project_godot_content.contains(conventer_text), ERROR_CODE, "Project already was converted with this tool."); Ref<FileAccess> file = FileAccess::open("project.godot", FileAccess::WRITE); ERR_FAIL_COND_V_MSG(file.is_null(), ERROR_CODE, "Failed to open project.godot file."); @@ -1700,11 +1889,19 @@ int ProjectConverter3To4::convert() { // Check file by file for (int i = 0; i < collected_files.size(); i++) { String file_name = collected_files[i]; - Error err = OK; - String file_content = FileAccess::get_file_as_string(file_name, &err); - ERR_CONTINUE_MSG(err != OK, "Failed to read content of \"" + file_name + "\"."); - uint64_t hash_before = file_content.hash64(); - uint64_t file_size = file_content.size(); + Vector<String> lines; + uint32_t ignored_lines = 0; + { + Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ); + ERR_CONTINUE_MSG(file.is_null(), "Failed to read content of \"" + file_name + "\"."); + while (!file->eof_reached()) { + String line = file->get_line(); + lines.append(line); + } + } + String file_content_before = collect_string_from_vector(lines); + uint64_t hash_before = file_content_before.hash(); + uint64_t file_size = file_content_before.size(); print_line("Trying to convert\t" + itos(i + 1) + "/" + itos(collected_files.size()) + " file - \"" + file_name.trim_prefix("res://") + "\" with size - " + itos(file_size / 1024) + " KB"); Vector<String> reason; @@ -1716,78 +1913,87 @@ int ProjectConverter3To4::convert() { file_name = file_name.replace(".shader", ".gdshader"); } - if (file_size < CONVERSION_MAX_FILE_SIZE) { + if (file_size < uint64_t(maximum_file_size)) { // TSCN must be the same work exactly same as .gd file because it may contains builtin script if (file_name.ends_with(".gd")) { - rename_classes(file_content); // Using only specialized function + rename_classes(lines, reg_container); // Using only specialized function - rename_common(enum_renames, file_content); - rename_enums(file_content); // Require to additional rename + rename_common(enum_renames, reg_container.enum_regexes, lines); + rename_colors(lines, reg_container); // Require to additional rename - rename_common(gdscript_function_renames, file_content); - rename_gdscript_functions(file_content, reg_container, false); // Require to additional rename + rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines); + rename_gdscript_functions(lines, reg_container, false); // Require to additional rename - rename_common(project_settings_renames, file_content); - rename_gdscript_keywords(file_content); - rename_common(gdscript_properties_renames, file_content); - rename_common(gdscript_signals_renames, file_content); - rename_common(shaders_renames, file_content); - rename_common(builtin_types_renames, file_content); + rename_common(project_settings_renames, reg_container.project_settings_regexes, lines); + rename_gdscript_keywords(lines, reg_container); + rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines); + rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines); + rename_common(shaders_renames, reg_container.shaders_regexes, lines); + rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); - custom_rename(file_content, "\\.shader", ".gdshader"); + custom_rename(lines, "\\.shader", ".gdshader"); } else if (file_name.ends_with(".tscn")) { - rename_classes(file_content); // Using only specialized function + rename_classes(lines, reg_container); // Using only specialized function - rename_common(enum_renames, file_content); - rename_enums(file_content); // Require to additional rename + rename_common(enum_renames, reg_container.enum_regexes, lines); + rename_colors(lines, reg_container); // Require to additional rename - rename_common(gdscript_function_renames, file_content); - rename_gdscript_functions(file_content, reg_container, true); // Require to additional rename + rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines); + rename_gdscript_functions(lines, reg_container, true); // Require to additional rename - rename_common(project_settings_renames, file_content); - rename_gdscript_keywords(file_content); - rename_common(gdscript_properties_renames, file_content); - rename_common(gdscript_signals_renames, file_content); - rename_common(shaders_renames, file_content); - rename_common(builtin_types_renames, file_content); + rename_common(project_settings_renames, reg_container.project_settings_regexes, lines); + rename_gdscript_keywords(lines, reg_container); + rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines); + rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines); + rename_common(shaders_renames, reg_container.shaders_regexes, lines); + rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); - custom_rename(file_content, "\\.shader", ".gdshader"); + custom_rename(lines, "\\.shader", ".gdshader"); } else if (file_name.ends_with(".cs")) { // TODO, C# should use different methods - rename_classes(file_content); // Using only specialized function - rename_common(csharp_function_renames, file_content); - rename_common(builtin_types_renames, file_content); - rename_common(csharp_properties_renames, file_content); - rename_common(csharp_signals_renames, file_content); - rename_csharp_functions(file_content); - rename_csharp_attributes(file_content); - custom_rename(file_content, "public class ", "public partial class "); + rename_classes(lines, reg_container); // Using only specialized function + rename_common(csharp_function_renames, reg_container.csharp_function_regexes, lines); + rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); + rename_common(csharp_properties_renames, reg_container.csharp_properties_regexes, lines); + rename_common(csharp_signals_renames, reg_container.csharp_signal_regexes, lines); + rename_csharp_functions(lines, reg_container); + rename_csharp_attributes(lines, reg_container); + custom_rename(lines, "public class ", "public partial class "); } else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) { - rename_common(shaders_renames, file_content); + rename_common(shaders_renames, reg_container.shaders_regexes, lines); } else if (file_name.ends_with("tres")) { - rename_classes(file_content); // Using only specialized function + rename_classes(lines, reg_container); // Using only specialized function - rename_common(shaders_renames, file_content); - rename_common(builtin_types_renames, file_content); + rename_common(shaders_renames, reg_container.shaders_regexes, lines); + rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); - custom_rename(file_content, "\\.shader", ".gdshader"); + custom_rename(lines, "\\.shader", ".gdshader"); } else if (file_name.ends_with("project.godot")) { - rename_common(project_settings_renames, file_content); - rename_common(builtin_types_renames, file_content); + rename_common(project_settings_renames, reg_container.project_settings_regexes, lines); + rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines); } else if (file_name.ends_with(".csproj")) { // TODO } else { ERR_PRINT(file_name + " is not supported!"); continue; } + + for (String &line : lines) { + if (uint64_t(line.length()) > maximum_line_length) { + ignored_lines += 1; + } + } } else { - reason.append(" ERROR: File has exceeded the maximum size allowed - " + itos(CONVERSION_MAX_FILE_SIZE_MB) + " MB"); + reason.append(" ERROR: File has exceeded the maximum size allowed - " + itos(maximum_file_size / 1024) + " KB"); is_ignored = true; } uint64_t end_time = Time::get_singleton()->get_ticks_msec(); - - if (!is_ignored) { - uint64_t hash_after = file_content.hash64(); + if (is_ignored) { + String end_message = " Checking file took " + itos(end_time - start_time) + " ms."; + print_line(end_message); + } else { + String file_content_after = collect_string_from_vector(lines); + uint64_t hash_after = file_content_after.hash64(); // Don't need to save file without any changes // Save if this is a shader, because it was renamed if (hash_before != hash_after || file_name.ends_with(".gdshader")) { @@ -1795,11 +2001,14 @@ int ProjectConverter3To4::convert() { Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::WRITE); ERR_CONTINUE_MSG(file.is_null(), "Failed to open \"" + file_name + "\" to save data to file."); - file->store_string(file_content); + file->store_string(file_content_after); reason.append(" File was changed, conversion took " + itos(end_time - start_time) + " ms."); } else { reason.append(" File was not changed, checking took " + itos(end_time - start_time) + " ms."); } + if (ignored_lines != 0) { + reason.append(" Ignored " + itos(ignored_lines) + " lines, because their length exceeds maximum allowed characters - " + itos(maximum_line_length)); + } } for (int k = 0; k < reason.size(); k++) { print_line(reason[k]); @@ -1807,20 +2016,28 @@ int ProjectConverter3To4::convert() { } print_line("Conversion ended - all files(" + itos(collected_files.size()) + "), converted files(" + itos(converted_files) + "), not converted files(" + itos(collected_files.size() - converted_files) + ")."); + uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec(); + print_line("Conversion of all files took " + itos(conversion_end_time - conversion_start_time) + " ms."); return 0; }; // Function responsible for validating project conversion. int ProjectConverter3To4::validate_conversion() { print_line("Starting checking if project conversion can be done."); + uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec(); RegExContainer reg_container = RegExContainer(); + int cached_maximum_line_length = maximum_line_length; + maximum_line_length = 10000; // Use only for tests bigger value, to not break them + ERR_FAIL_COND_V_MSG(!test_array_names(), ERROR_CODE, "Cannot start converting due to problems with data in arrays."); ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), ERROR_CODE, "Cannot start converting due to problems with converting arrays."); + maximum_line_length = cached_maximum_line_length; + // Checking if folder contains valid Godot 3 project. - // Project cannot be converted 2 times + // Project should not be converted more than 1 times { String conventer_text = "; Project was converted by built-in tool to Godot 4.0"; @@ -1830,7 +2047,7 @@ int ProjectConverter3To4::validate_conversion() { String project_godot_content = FileAccess::get_file_as_string("project.godot", &err); ERR_FAIL_COND_V_MSG(err != OK, ERROR_CODE, "Failed to read content of \"project.godot\" file."); - ERR_FAIL_COND_V_MSG(project_godot_content.find(conventer_text) != -1, ERROR_CODE, "Project already was converted with this tool."); + ERR_FAIL_COND_V_MSG(project_godot_content.contains(conventer_text), ERROR_CODE, "Project already was converted with this tool."); } Vector<String> collected_files = check_for_files(); @@ -1840,7 +2057,8 @@ int ProjectConverter3To4::validate_conversion() { // Check file by file for (int i = 0; i < collected_files.size(); i++) { String file_name = collected_files[i]; - Vector<String> file_content; + Vector<String> lines; + uint32_t ignored_lines = 0; uint64_t file_size = 0; { Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ); @@ -1848,7 +2066,7 @@ int ProjectConverter3To4::validate_conversion() { while (!file->eof_reached()) { String line = file->get_line(); file_size += line.size(); - file_content.append(line); + lines.append(line); } } print_line("Checking for conversion - " + itos(i + 1) + "/" + itos(collected_files.size()) + " file - \"" + file_name.trim_prefix("res://") + "\" with size - " + itos(file_size / 1024) + " KB"); @@ -1862,75 +2080,85 @@ int ProjectConverter3To4::validate_conversion() { reason.append("\tFile extension will be renamed from `shader` to `gdshader`."); } - if (file_size < CONVERSION_MAX_FILE_SIZE) { + if (file_size < uint64_t(maximum_file_size)) { if (file_name.ends_with(".gd")) { - changed_elements.append_array(check_for_rename_classes(file_content)); + changed_elements.append_array(check_for_rename_classes(lines, reg_container)); - changed_elements.append_array(check_for_rename_common(enum_renames, file_content)); - changed_elements.append_array(check_for_rename_enums(file_content)); + changed_elements.append_array(check_for_rename_common(enum_renames, reg_container.enum_regexes, lines)); + changed_elements.append_array(check_for_rename_colors(lines, reg_container)); - changed_elements.append_array(check_for_rename_common(gdscript_function_renames, file_content)); - changed_elements.append_array(check_for_rename_gdscript_functions(file_content, reg_container, false)); + changed_elements.append_array(check_for_rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines)); + changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, false)); - changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content)); - changed_elements.append_array(check_for_rename_gdscript_keywords(file_content)); - changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, file_content)); - changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, file_content)); - changed_elements.append_array(check_for_rename_common(shaders_renames, file_content)); - changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content)); + changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines)); + changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container)); + changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines)); + changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines)); + changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines)); + changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); - changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader")); + changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader")); } else if (file_name.ends_with(".tscn")) { - changed_elements.append_array(check_for_rename_classes(file_content)); + changed_elements.append_array(check_for_rename_classes(lines, reg_container)); - changed_elements.append_array(check_for_rename_common(enum_renames, file_content)); - changed_elements.append_array(check_for_rename_enums(file_content)); + changed_elements.append_array(check_for_rename_common(enum_renames, reg_container.enum_regexes, lines)); + changed_elements.append_array(check_for_rename_colors(lines, reg_container)); - changed_elements.append_array(check_for_rename_common(gdscript_function_renames, file_content)); - changed_elements.append_array(check_for_rename_gdscript_functions(file_content, reg_container, true)); + changed_elements.append_array(check_for_rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines)); + changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, true)); - changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content)); - changed_elements.append_array(check_for_rename_gdscript_keywords(file_content)); - changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, file_content)); - changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, file_content)); - changed_elements.append_array(check_for_rename_common(shaders_renames, file_content)); - changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content)); + changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines)); + changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container)); + changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines)); + changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines)); + changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines)); + changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); - changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader")); + changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader")); } else if (file_name.ends_with(".cs")) { - changed_elements.append_array(check_for_rename_common(class_renames, file_content)); - changed_elements.append_array(check_for_rename_common(csharp_function_renames, file_content)); - changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content)); - changed_elements.append_array(check_for_rename_common(csharp_properties_renames, file_content)); - changed_elements.append_array(check_for_rename_common(csharp_signals_renames, file_content)); - changed_elements.append_array(check_for_rename_csharp_functions(file_content)); - changed_elements.append_array(check_for_rename_csharp_attributes(file_content)); - changed_elements.append_array(check_for_custom_rename(file_content, "public class ", "public partial class ")); + changed_elements.append_array(check_for_rename_classes(lines, reg_container)); + changed_elements.append_array(check_for_rename_common(csharp_function_renames, reg_container.csharp_function_regexes, lines)); + changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); + changed_elements.append_array(check_for_rename_common(csharp_properties_renames, reg_container.csharp_properties_regexes, lines)); + changed_elements.append_array(check_for_rename_common(csharp_signals_renames, reg_container.csharp_signal_regexes, lines)); + changed_elements.append_array(check_for_rename_csharp_functions(lines, reg_container)); + changed_elements.append_array(check_for_rename_csharp_attributes(lines, reg_container)); + changed_elements.append_array(check_for_custom_rename(lines, "public class ", "public partial class ")); } else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) { - changed_elements.append_array(check_for_rename_common(shaders_renames, file_content)); + changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines)); } else if (file_name.ends_with("tres")) { - changed_elements.append_array(check_for_rename_classes(file_content)); + changed_elements.append_array(check_for_rename_classes(lines, reg_container)); - changed_elements.append_array(check_for_rename_common(shaders_renames, file_content)); - changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content)); + changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines)); + changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); - changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader")); + changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader")); } else if (file_name.ends_with("project.godot")) { - changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content)); - changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content)); + changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines)); + changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines)); } else if (file_name.ends_with(".csproj")) { // TODO } else { ERR_PRINT(file_name + " is not supported!"); continue; } + + for (String &line : lines) { + if (uint64_t(line.length()) > maximum_line_length) { + ignored_lines += 1; + } + } } else { - reason.append("\tERROR: File has exceeded the maximum size allowed - " + itos(CONVERSION_MAX_FILE_SIZE_MB) + " MB"); + reason.append("\tERROR: File has exceeded the maximum size allowed - " + itos(maximum_file_size / 1024) + " KB"); is_ignored = true; } uint64_t end_time = Time::get_singleton()->get_ticks_msec(); - print_line(" Checking file took " + itos(end_time - start_time) + " ms."); + String end_message = " Checking file took " + itos(end_time - start_time) + " ms."; + if (ignored_lines != 0) { + end_message += " Ignored " + itos(ignored_lines) + " lines, because their length exceeds maximum allowed characters - " + itos(maximum_line_length); + } + print_line(end_message); for (int k = 0; k < reason.size(); k++) { print_line(reason[k]); @@ -1946,6 +2174,8 @@ int ProjectConverter3To4::validate_conversion() { } print_line("Checking for valid conversion ended - all files(" + itos(collected_files.size()) + "), files which would be converted(" + itos(converted_files) + "), files which would not be converted(" + itos(collected_files.size() - converted_files) + ")."); + uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec(); + print_line("Conversion of all files took " + itos(conversion_end_time - conversion_start_time) + " ms."); return 0; } @@ -1972,14 +2202,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(); @@ -1991,218 +2221,230 @@ Vector<String> ProjectConverter3To4::check_for_files() { return collected_files; } -bool ProjectConverter3To4::test_conversion_single_additional(String name, String expected, void (ProjectConverter3To4::*func)(String &), String what) { - String got = name; - (this->*func)(got); - if (expected != got) { - ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`"); +// Test expected results of gdscript +bool ProjectConverter3To4::test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin_script) { + Vector<String> got = name.split("\n"); + (this->*func)(got, reg_container, builtin_script); + String got_str = collect_string_from_vector(got); + if (expected != got_str) { + ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got_str + "`"); return false; } return true; } -bool ProjectConverter3To4::test_conversion_single_additional_builtin(String name, String expected, void (ProjectConverter3To4::*func)(String &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin_script) { - String got = name; - (this->*func)(got, reg_container, builtin_script); - if (expected != got) { - ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`"); +bool ProjectConverter3To4::test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &), String what, const RegExContainer ®_container) { + Vector<String> got = name.split("\n"); + (this->*func)(got, reg_container); + String got_str = collect_string_from_vector(got); + if (expected != got_str) { + ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got_str + "`"); return false; } return true; } -bool ProjectConverter3To4::test_conversion_single_normal(String name, String expected, const char *array[][2], String what) { - String got = name; - rename_common(array, got); - if (expected != got) { - ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`"); +bool ProjectConverter3To4::test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> ®ex_cache, String what) { + Vector<String> got = name.split("\n"); + rename_common(array, regex_cache, got); + String got_str = collect_string_from_vector(got); + if (expected != got_str) { + ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got_str + "`"); return false; } return true; } // Validate if conversions are proper -bool ProjectConverter3To4::test_conversion(const RegExContainer ®_container) { +bool ProjectConverter3To4::test_conversion(RegExContainer ®_container) { bool valid = true; - valid = valid & test_conversion_single_normal("Spatial", "Node3D", class_renames, "class"); + valid = valid & test_conversion_basic("TYPE_REAL", "TYPE_FLOAT", enum_renames, reg_container.enum_regexes, "enum"); - valid = valid & test_conversion_single_normal("TYPE_REAL", "TYPE_FLOAT", enum_renames, "enum"); + valid = valid & test_conversion_basic("can_instance", "can_instantiate", gdscript_function_renames, reg_container.gdscript_function_regexes, "gdscript function"); - valid = valid & test_conversion_single_normal("can_instance", "can_instantiate", gdscript_function_renames, "gdscript function"); + valid = valid & test_conversion_basic("CanInstance", "CanInstantiate", csharp_function_renames, reg_container.csharp_function_regexes, "csharp function"); - valid = valid & test_conversion_single_normal("CanInstance", "CanInstantiate", csharp_function_renames, "csharp function"); + valid = valid & test_conversion_basic("translation", "position", gdscript_properties_renames, reg_container.gdscript_properties_regexes, "gdscript property"); - valid = valid & test_conversion_single_normal("translation", "position", gdscript_properties_renames, "gdscript property"); + valid = valid & test_conversion_basic("Translation", "Position", csharp_properties_renames, reg_container.csharp_properties_regexes, "csharp property"); - valid = valid & test_conversion_single_normal("Translation", "Position", csharp_properties_renames, "csharp property"); + valid = valid & test_conversion_basic("NORMALMAP", "NORMAL_MAP", shaders_renames, reg_container.shaders_regexes, "shader"); - valid = valid & test_conversion_single_normal("NORMALMAP", "NORMAL_MAP", shaders_renames, "shader"); + valid = valid & test_conversion_basic("text_entered", "text_submitted", gdscript_signals_renames, reg_container.gdscript_signals_regexes, "gdscript signal"); - valid = valid & test_conversion_single_normal("text_entered", "text_submitted", gdscript_signals_renames, "gdscript signal"); + valid = valid & test_conversion_basic("TextEntered", "TextSubmitted", csharp_signals_renames, reg_container.csharp_signal_regexes, "csharp signal"); - valid = valid & test_conversion_single_normal("TextEntered", "TextSubmitted", csharp_signals_renames, "csharp signal"); + valid = valid & test_conversion_basic("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, reg_container.project_settings_regexes, "project setting"); - valid = valid & test_conversion_single_normal("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, "project setting"); - - valid = valid & test_conversion_single_normal("Transform", "Transform3D", builtin_types_renames, "builtin type"); + valid = valid & test_conversion_basic("Transform", "Transform3D", builtin_types_renames, reg_container.builtin_types_regexes, "builtin type"); // Custom Renames - valid = valid & test_conversion_single_additional("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A,new Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp"); - valid = valid & test_conversion_single_additional("(Disconnect(A,B,C) != OK):", "(Disconnect(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp"); - valid = valid & test_conversion_single_additional("(IsConnected(A,B,C) != OK):", "(IsConnected(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename"); - - valid = valid & test_conversion_single_additional("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - valid = valid & test_conversion_single_additional("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp"); - - valid = valid & test_conversion_single_additional_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true); - valid = valid & test_conversion_single_additional_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional(" onready", " onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\nexport", "\n@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\texport", "\t@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\texport_dialog", "\texport_dialog", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("export", "@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional(" export", " export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("tool", "@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n tool", "\n tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\ntool", "\n\n@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nremote func", "\n\n@rpc(any_peer) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nremotesync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nsync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\npuppetsync func", "\n\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - valid = valid & test_conversion_single_additional("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword"); - - valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("yield(this, \\\"timeout\\\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true); - - valid = valid & test_conversion_single_additional_builtin(" Transform.xform(Vector3(a,b,c)) ", " Transform * Vector3(a,b,c) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(" Transform.xform_inv(Vector3(a,b,c)) ", " Vector3(a,b,c) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); // TODO, this is only a workaround - valid = valid & test_conversion_single_additional_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,D) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D,E]) != OK):", "(connect(A,Callable(B,C).bind(D,E)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,[D,E],F) != OK):", "(connect(A,Callable(B,C).bind(D,E),F) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A,B).bind(C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("(tween_method(A,B,C,D,E).foo())", "(tween_method(Callable(A,B),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(tween_method(A,B,C,D,E,[F,G]).foo())", "(tween_method(Callable(A,B).bind(F,G),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(tween_callback(A,B).foo())", "(tween_callback(Callable(A,B)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("(tween_callback(A,B,[C,D]).foo())", "(tween_callback(Callable(A,B).bind(C,D)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("map_to_world(a, b,c)", "map_to_world(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin(" aa", " aa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\taa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("\t aa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin(" \taa", " \taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - valid = valid & test_conversion_single_additional_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); - - valid = valid & test_conversion_single_additional("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_enums, "custom rename"); + valid = valid & test_conversion_with_regex("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A,new Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("(Disconnect(A,B,C) != OK):", "(Disconnect(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("(IsConnected(A,B,C) != OK):", "(IsConnected(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename", reg_container); + + valid = valid & test_conversion_with_regex("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + valid = valid & test_conversion_with_regex("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container); + + valid = valid & test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true); + valid = valid & test_conversion_gdscript_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_with_regex("extends CSGBox", "extends CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("CSGBox", "CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("Spatial", "Node3D", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("Spatial.tscn", "Spatial.tscn", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("Spatial.gd", "Spatial.gd", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("Spatial.shader", "Spatial.shader", &ProjectConverter3To4::rename_classes, "classes", reg_container); + valid = valid & test_conversion_with_regex("Spatial.other", "Node3D.other", &ProjectConverter3To4::rename_classes, "classes", reg_container); + + valid = valid & test_conversion_with_regex("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex(" onready", " onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\nexport", "\n@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\texport", "\t@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\texport_dialog", "\texport_dialog", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("export", "@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex(" export", " export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("tool", "@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n tool", "\n tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\ntool", "\n\n@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nremote func", "\n\n@rpc(any_peer) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nremotesync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nsync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\npuppetsync func", "\n\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + valid = valid & test_conversion_with_regex("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container); + + valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("yield(this, \\\"timeout\\\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true); + + valid = valid & test_conversion_gdscript_builtin(" Transform.xform(Vector3(a,b,c)) ", " Transform * Vector3(a,b,c) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin(" Transform.xform_inv(Vector3(a,b,c)) ", " Vector3(a,b,c) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); // TODO, this is only a workaround + valid = valid & test_conversion_gdscript_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,D) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,[D,E]) != OK):", "(connect(A,Callable(B,C).bind(D,E)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,[D,E],F) != OK):", "(connect(A,Callable(B,C).bind(D,E),F) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A,B).bind(C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E).foo())", "(tween_method(Callable(A,B),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E,[F,G]).foo())", "(tween_method(Callable(A,B).bind(F,G),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(tween_callback(A,B).foo())", "(tween_callback(Callable(A,B)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("(tween_callback(A,B,[C,D]).foo())", "(tween_callback(Callable(A,B).bind(C,D)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("func _init(", "func _init(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("map_to_world(a, b,c)", "map_to_world(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_gdscript_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("draw_rect(a,b,c,d,e).abc", "draw_rect(a,b,c,d).abc# e) TODOGODOT4 Antialiasing argument is missing", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("get_focus_owner()", "get_viewport().gui_get_focus_owner()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("button.pressed = 1", "button.button_pressed = 1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("button.pressed=1", "button.button_pressed=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + valid = valid & test_conversion_gdscript_builtin("button.pressed SF", "button.pressed SF", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); + + valid = valid & test_conversion_with_regex("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_colors, "custom rename", reg_container); // Custom rule conversion { String from = "instance"; String to = "instantiate"; String name = "AA.instance()"; - String got = "AA.instance()"; + Vector<String> got = String("AA.instance()").split("\n"); String expected = "AA.instantiate()"; custom_rename(got, from, to); - if (got != expected) { - ERR_PRINT("Failed to convert custom rename `" + name + "` to `" + expected + "`, got instead `" + got + "`"); + String got_str = collect_string_from_vector(got); + if (got_str != expected) { + ERR_PRINT("Failed to convert custom rename `" + name + "` to `" + expected + "`, got instead `" + got_str + "`"); } - valid = valid & (got == expected); + valid = valid & (got_str == expected); } // get_object_of_execution @@ -2317,8 +2559,7 @@ bool ProjectConverter3To4::test_array_names() { // Validate if all classes are valid { - int current_index = 0; - while (class_renames[current_index][0]) { + for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) { const String old_class = class_renames[current_index][0]; const String new_class = class_renames[current_index][1]; @@ -2333,84 +2574,65 @@ bool ProjectConverter3To4::test_array_names() { ERR_PRINT(String("Class `") + new_class + "` doesn't exists in Godot 4.0, so cannot be used in conversion."); valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI } - current_index++; - } - } - - // // TODO To be able to fully work, it needs https://github.com/godotengine/godot/pull/49053 - // // TODO this needs to be changed to hashset when available https://github.com/godotengine/godot-proposals/issues/867, to speedup searchng - // { - // OrderedHashMap<String, bool> all_functions; - - // List<StringName> classes_list; - // ClassDB::get_class_list(&classes_list); - // for (StringName &name_of_class : classes_list) { - // List<MethodInfo> method_list; - // ClassDB::get_method_list(name_of_class, &method_list, true); - // for (MethodInfo &function_data : method_list) { - // if (!all_functions.has(function_data.name)) { - // all_functions.insert(function_data.name, false); - // } - // } - // } - - // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) { - // List<MethodInfo> method_list; - // Variant::get_method_list_by_type(&method_list, Variant::Type(type)); - // for (MethodInfo &function_data : method_list) { - // if (!all_functions.has(function_data.name)) { - // all_functions.insert(function_data.name, false); - // } - // } - // } - - // int current_element = 0; - // while (gdscript_function_renames[current_element][0] != nullptr) { - // if (!all_functions.has(gdscript_function_renames[current_element][1])) { - // ERR_PRINT(String("Missing gdscript function in pair (") + gdscript_function_renames[current_element][0] + " - ===> " + gdscript_function_renames[current_element][1] + " <===)"); - // valid = false; - // } - // // // DEBUG, disable below after tests - // // if (all_functions.has(gdscript_function_renames[current_element][0])) { - // // String used_in_classes = ""; - // // - // // for (StringName &name_of_class : classes_list) { - // // List<MethodInfo> method_list; - // // ClassDB::get_method_list(name_of_class, &method_list, true); - // // for (MethodInfo &function_data : method_list) { - // // if (function_data.name == gdscript_function_renames[current_element][0]) { - // // used_in_classes += String(name_of_class) + ", "; - // // } - // // } - // // } - // // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) { - // // List<MethodInfo> method_list; - // // Variant::get_method_list_by_type(&method_list, Variant::Type(type)); - // // for (MethodInfo &function_data : method_list) { - // // if (function_data.name == gdscript_function_renames[current_element][0]) { - // // used_in_classes += Variant::get_type_name(Variant::Type(type)) + ", "; - // // } - // // } - // // } - // // used_in_classes = used_in_classes.trim_suffix(", "); - // // - // // WARN_PRINT(String("Godot contains function which will be renamed in pair ( ===> ") + gdscript_function_renames[current_element][0] + " <=== - " + gdscript_function_renames[current_element][1] + ") in class " + used_in_classes + " - check for possible invalid rule."); - // // } - // current_element++; - // } - // } + } + } + + { + HashSet<String> all_functions; + + // List of excluded functions from builtin types and global namespace, because currently it is not possible to get list of functions from them + // This will be available when https://github.com/godotengine/godot/pull/49053 or similar will be included into Godot + static const char *builtin_types_excluded_functions[] = { "dict_to_inst", "inst_to_dict", "bytes_to_var", "bytes_to_var_with_objects", "db_to_linear", "deg_to_rad", "linear_to_db", "rad_to_deg", "randf_range", "snapped", "str_to_var", "var_to_str", "var_to_bytes", "var_to_bytes_with_objects", "move_toward", "uri_encode", "uri_decode", "remove_at", "get_rotation_quaternion", "clamp", "grow_side", "is_absolute_path", "is_valid_int", "lerp", "to_ascii_buffer", "to_utf8_buffer", "to_utf32_buffer", "snapped", nullptr }; + for (int current_index = 0; builtin_types_excluded_functions[current_index]; current_index++) { + all_functions.insert(builtin_types_excluded_functions[current_index]); + } + + // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) { + // List<MethodInfo> method_list; + // Variant::get_method_list_by_type(&method_list, Variant::Type(type)); + // for (MethodInfo &function_data : method_list) { + // if (!all_functions.has(function_data.name)) { + // all_functions.insert(function_data.name); + // } + // } + // } + + List<StringName> classes_list; + ClassDB::get_class_list(&classes_list); + for (StringName &name_of_class : classes_list) { + List<MethodInfo> method_list; + ClassDB::get_method_list(name_of_class, &method_list, true); + for (MethodInfo &function_data : method_list) { + if (!all_functions.has(function_data.name)) { + all_functions.insert(function_data.name); + } + } + } + + int current_element = 0; + while (gdscript_function_renames[current_element][0] != nullptr) { + if (!all_functions.has(gdscript_function_renames[current_element][1])) { + ERR_PRINT(String("Missing gdscript function in pair (") + gdscript_function_renames[current_element][0] + " - ===> " + gdscript_function_renames[current_element][1] + " <===)"); + valid = false; + } + current_element++; + } + } + if (!valid) { + ERR_PRINT("Found function which is used in converter, but cannot be found in Godot 4. Rename this element to new name or remove entire rule about it if is obsolete."); + } valid = valid & test_single_array(enum_renames); valid = valid & test_single_array(class_renames, true); valid = valid & test_single_array(gdscript_function_renames, true); valid = valid & test_single_array(csharp_function_renames, true); - valid = valid & test_single_array(gdscript_properties_renames); + valid = valid & test_single_array(gdscript_properties_renames, true); valid = valid & test_single_array(csharp_properties_renames); - valid = valid & test_single_array(shaders_renames); + valid = valid & test_single_array(shaders_renames, true); valid = valid & test_single_array(gdscript_signals_renames); valid = valid & test_single_array(project_settings_renames); valid = valid & test_single_array(builtin_types_renames); - valid = valid & test_single_array(colors_renames); + valid = valid & test_single_array(color_renames); return valid; } @@ -2419,10 +2641,9 @@ bool ProjectConverter3To4::test_array_names() { // Also checks if in name contains spaces at the end or beginning bool ProjectConverter3To4::test_single_array(const char *array[][2], bool ignore_second_check) { bool valid = true; - int current_index = 0; Vector<String> names = Vector<String>(); - while (array[current_index][0]) { + for (unsigned int current_index = 0; array[current_index][0]; current_index++) { if (String(array[current_index][0]).begins_with(" ") || String(array[current_index][0]).ends_with(" ")) { { ERR_PRINT(String("Entry \"") + array[current_index][0] + "\" ends or stars with space."); @@ -2448,7 +2669,6 @@ bool ProjectConverter3To4::test_single_array(const char *array[][2], bool ignore if (!ignore_second_check) { names.append(array[current_index][1]); } - current_index++; } return valid; }; @@ -2458,18 +2678,17 @@ bool ProjectConverter3To4::test_single_array(const char *array[][2], bool ignore Vector<String> ProjectConverter3To4::parse_arguments(const String &line) { Vector<String> parts; int string_size = line.length(); - int current_index = 0; int start_part = 0; // Index of beginning of start par int parts_counter = 0; char32_t previous_character = '\0'; bool is_inside_string = false; // if true, it ignore this 3 characters ( , ) inside string if (line.count("(") != line.count(")")) { - ERR_PRINT("Bug: substring should have equal number of open and close parenthess - `" + line + "`"); + ERR_PRINT("Converter internal bug: substring should have equal number of open and close parenthess in line - `" + line + "`"); return parts; } - while (current_index < string_size) { + for (int current_index = 0; current_index < string_size; current_index++) { char32_t character = line.get(current_index); switch (character) { case '(': { @@ -2514,7 +2733,6 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) { is_inside_string = !is_inside_string; } } - current_index++; previous_character = character; } @@ -2532,9 +2750,8 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) { // Finds latest parenthess owned by function // `function(abc(a,b),DD)):` finds this parenthess `function(abc(a,b),DD => ) <= ):` int ProjectConverter3To4::get_end_parenthess(const String &line) const { - int current_index = 0; int current_state = 0; - while (line.length() > current_index) { + for (int current_index = 0; line.length() > current_index; current_index++) { char32_t character = line.get(current_index); if (character == '(') { current_state++; @@ -2545,7 +2762,6 @@ int ProjectConverter3To4::get_end_parenthess(const String &line) const { return current_index; } } - current_index++; } return -1; } @@ -2647,229 +2863,217 @@ String ProjectConverter3To4::get_object_of_execution(const String &line) const { return line.substr(variable_start, (end - variable_start)); } -void ProjectConverter3To4::rename_enums(String &file_content) { - int current_index = 0; - - // Rename colors - if (file_content.find("Color.") != -1) { - while (colors_renames[current_index][0]) { - RegEx reg = RegEx(String("\\bColor.") + colors_renames[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); - file_content = reg.sub(file_content, String("Color.") + colors_renames[current_index][1], true); - current_index++; +void ProjectConverter3To4::rename_colors(Vector<String> &lines, const RegExContainer ®_container) { + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + if (line.contains("Color.")) { + for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) { + line = reg_container.color_regexes[current_index]->sub(line, reg_container.color_renamed[current_index], true); + } + } } } }; -Vector<String> ProjectConverter3To4::check_for_rename_enums(Vector<String> &file_content) { - int current_index = 0; - - Vector<String> found_things; +Vector<String> ProjectConverter3To4::check_for_rename_colors(Vector<String> &lines, const RegExContainer ®_container) { + Vector<String> found_renames; - // Rename colors - if (file_content.find("Color.") != -1) { - while (colors_renames[current_index][0]) { - RegEx reg = RegEx(String("\\bColor.") + colors_renames[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); - - int current_line = 1; - for (String &line : file_content) { - TypedArray<RegExMatch> reg_match = reg.search_all(line); - if (reg_match.size() > 0) { - found_things.append(line_formatter(current_line, colors_renames[current_index][0], colors_renames[current_index][1], line)); + int current_line = 1; + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + if (line.contains("Color.")) { + for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) { + TypedArray<RegExMatch> reg_match = reg_container.color_regexes[current_index]->search_all(line); + if (reg_match.size() > 0) { + found_renames.append(line_formatter(current_line, color_renames[current_index][0], color_renames[current_index][1], line)); + } } - current_line++; } - current_index++; } + current_line++; } - return found_things; + return found_renames; } -void ProjectConverter3To4::rename_classes(String &file_content) { - int current_index = 0; - - // TODO Maybe it is better way to not rename gd, tscn and other files which are named as classes - while (class_renames[current_index][0]) { - // Begin renaming workaround `Resource.gd` -> `RefCounter.gd` - RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b"); - CRASH_COND(!reg_before.is_valid()); - file_content = reg_before.sub(file_content, "TEMP_RENAMED_CLASS.tscn", true); - RegEx reg_before2 = RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b"); - CRASH_COND(!reg_before2.is_valid()); - file_content = reg_before2.sub(file_content, "TEMP_RENAMED_CLASS.gd", true); - RegEx reg_before3 = RegEx(String("\\b") + class_renames[current_index][0] + ".shader\\b"); - CRASH_COND(!reg_before3.is_valid()); - file_content = reg_before3.sub(file_content, "TEMP_RENAMED_CLASS.gd", true); - // End - - RegEx reg = RegEx(String("\\b") + class_renames[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); - file_content = reg.sub(file_content, class_renames[current_index][1], true); - - // Begin renaming workaround `Resource.gd` -> `RefCounter.gd` - RegEx reg_after = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b"); - CRASH_COND(!reg_after.is_valid()); - file_content = reg_after.sub(file_content, String(class_renames[current_index][0]) + ".tscn", true); - RegEx reg_after2 = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b"); - CRASH_COND(!reg_after2.is_valid()); - file_content = reg_after2.sub(file_content, String(class_renames[current_index][0]) + ".gd", true); - RegEx reg_after3 = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b"); - CRASH_COND(!reg_after3.is_valid()); - file_content = reg_after3.sub(file_content, String(class_renames[current_index][0]) + ".shader", true); - // End - - current_index++; - } - - // OS.get_ticks_msec -> Time.get_ticks_msec - RegEx reg_time1 = RegEx("OS.get_ticks_msec"); - CRASH_COND(!reg_time1.is_valid()); - file_content = reg_time1.sub(file_content, "Time.get_ticks_msec", true); - RegEx reg_time2 = RegEx("OS.get_ticks_usec"); - CRASH_COND(!reg_time2.is_valid()); - file_content = reg_time2.sub(file_content, "Time.get_ticks_usec", true); -}; - -Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &file_content) { - int current_index = 0; - - Vector<String> found_things; - - while (class_renames[current_index][0]) { - RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b"); - CRASH_COND(!reg_before.is_valid()); - RegEx reg_before2 = RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b"); - CRASH_COND(!reg_before2.is_valid()); - - RegEx reg = RegEx(String("\\b") + class_renames[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); +void ProjectConverter3To4::rename_classes(Vector<String> &lines, const RegExContainer ®_container) { + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) { + if (line.contains(class_renames[current_index][0])) { + bool found_ignored_items = false; + // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn + if (line.contains(String(class_renames[current_index][0]) + ".")) { + found_ignored_items = true; + line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true); + line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true); + line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true); + } - int current_line = 1; - for (String &line : file_content) { - line = reg_before.sub(line, "TEMP_RENAMED_CLASS.tscn", true); - line = reg_before2.sub(line, "TEMP_RENAMED_CLASS.gd", true); + // Causal renaming Spatial -> Node3D + line = reg_container.class_regexes[current_index]->sub(line, class_renames[current_index][1], true); - TypedArray<RegExMatch> reg_match = reg.search_all(line); - if (reg_match.size() > 0) { - found_things.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], line)); + // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn + if (found_ignored_items) { + line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true); + line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true); + line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true); + } + } } - current_line++; } - current_index++; } +}; + +Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &lines, const RegExContainer ®_container) { + Vector<String> found_renames; - // TODO OS -> TIME int current_line = 1; - RegEx reg_time1 = RegEx("OS.get_ticks_msec"); - CRASH_COND(!reg_time1.is_valid()); - RegEx reg_time2 = RegEx("OS.get_ticks_usec"); - CRASH_COND(!reg_time2.is_valid()); - for (String &line : file_content) { - String old = line; - line = reg_time1.sub(line, "Time.get_ticks_msec", true); - line = reg_time2.sub(line, "Time.get_ticks_usec", true); + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) { + if (line.contains(class_renames[current_index][0])) { + String old_line = line; + bool found_ignored_items = false; + // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn + if (line.contains(String(class_renames[current_index][0]) + ".")) { + found_ignored_items = true; + line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true); + line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true); + line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true); + } - if (old != line) { - found_things.append(simple_line_formatter(current_line, old, line)); + // Causal renaming Spatial -> Node3D + TypedArray<RegExMatch> reg_match = reg_container.class_regexes[current_index]->search_all(line); + if (reg_match.size() > 0) { + found_renames.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], old_line)); + } + + // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn + if (found_ignored_items) { + line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true); + line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true); + line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true); + } + } + } } current_line++; } - return found_things; + return found_renames; } -void ProjectConverter3To4::rename_gdscript_functions(String &file_content, const RegExContainer ®_container, bool builtin) { - Vector<String> lines = file_content.split("\n"); - +void ProjectConverter3To4::rename_gdscript_functions(Vector<String> &lines, const RegExContainer ®_container, bool builtin) { for (String &line : lines) { - process_gdscript_line(line, reg_container, builtin); - } - - // Collect vector to string - file_content = ""; - for (int i = 0; i < lines.size(); i++) { - file_content += lines[i]; - - if (i != lines.size() - 1) { - file_content += "\n"; + if (uint64_t(line.length()) <= maximum_line_length) { + process_gdscript_line(line, reg_container, builtin); } } }; -Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer ®_container, bool builtin) { +Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer ®_container, bool builtin) { int current_line = 1; - Vector<String> found_things; + Vector<String> found_renames; - for (String &line : file_content) { - String old_line = line; - process_gdscript_line(line, reg_container, builtin); - if (old_line != line) { - found_things.append(simple_line_formatter(current_line, old_line, line)); + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + String old_line = line; + process_gdscript_line(line, reg_container, builtin); + if (old_line != line) { + found_renames.append(simple_line_formatter(current_line, old_line, line)); + } } } - return found_things; + return found_renames; } + +// TODO, this function should run only on all .gd files and also on lines in tscn files which void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContainer ®_container, bool builtin) { - if (line.find("mtx") == -1 && line.find("mutex") == -1 && line.find("Mutex") == -1) { + // In this and other functions, reg.sub are used only after checking line with str.contains function which is sometimes few times faster with bigger line lengths + + if ((line.contains(".lock") || line.contains(".unlock")) && !line.contains("mtx") && !line.contains("mutex") && !line.contains("Mutex")) { line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true); line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true); } - // Mixed use of spaces and tabs - tabs as first - TODO, this probably is problem problem, but not sure - line = reg_container.reg_mixed_tab_space.sub(line, "$1", true); - // PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray - line = reg_container.reg_join.sub(line, "$2.join($1)", true); + if (line.contains(".join")) { + line = reg_container.reg_join.sub(line, "$2.join($1)", true); + } // -- empty() -> is_empty() Pool*Array - line = reg_container.reg_is_empty.sub(line, "is_empty(", true); + if (line.contains("empty")) { + line = reg_container.reg_is_empty.sub(line, "is_empty(", true); + } // -- \t.func() -> \tsuper.func() Object - line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this brake String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore" + if (line.contains("(") && line.contains(".")) { + line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this broke String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore" + } // -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON - line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); + if (line.contains("parse")) { + line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); + } // -- to_json(a) -> JSON.new().stringify(a) Object - line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true); - + if (line.contains("to_json")) { + line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true); + } // -- parse_json(a) -> JSON.get_data() etc. Object - line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); + if (line.contains("parse_json")) { + line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true); + } // -- get_node(@ -> get_node( Node - line = line.replace("get_node(@", "get_node("); + if (line.contains("get_node")) { + line = line.replace("get_node(@", "get_node("); + } // export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript - line = reg_container.reg_export.sub(line, "export var $2: $1"); + if (line.contains("export")) { + line = reg_container.reg_export.sub(line, "export var $2: $1"); + } // export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript - line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)"); + if (line.contains("export")) { + line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)"); + } // Setget Setget - line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + if (line.contains("setget")) { + line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + } // Setget set - line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + if (line.contains("setget")) { + line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true); + } // Setget get - line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true); + if (line.contains("setget")) { + line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true); + } // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true) - if (builtin) { - line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true); - } else { - line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true); + if (line.contains("window_fullscreen")) { + if (builtin) { + line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true); + } else { + line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true); + } } // Instantiate - line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true); + if (line.contains("instance")) { + line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true); + } // -- r.move_and_slide( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody - if (line.find("move_and_slide(") != -1) { + if (line.contains(("move_and_slide("))) { int start = line.find("move_and_slide("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -2915,7 +3119,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody - if (line.find("move_and_slide_with_snap(") != -1) { + if (line.contains("move_and_slide_with_snap(")) { int start = line.find("move_and_slide_with_snap("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -2966,7 +3170,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object - if (line.find("sort_custom(") != -1) { + if (line.contains("sort_custom(")) { int start = line.find("sort_custom("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -2978,7 +3182,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- list_dir_begin( ) -> list_dir_begin() Object - if (line.find("list_dir_begin(") != -1) { + if (line.contains("list_dir_begin(")) { int start = line.find("list_dir_begin("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -2987,7 +3191,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem - if (line.find("draw_line(") != -1) { + if (line.contains("draw_line(")) { int start = line.find("draw_line("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -2999,7 +3203,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- func c(var a, var b) -> func c(a, b) - if (line.find("func ") != -1 && line.find("var ") != -1) { + if (line.contains("func ") && line.contains("var ")) { int start = line.find("func "); start = line.substr(start).find("(") + start; int end = get_end_parenthess(line.substr(start)) + 1; @@ -3018,7 +3222,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- yield(this, \"timeout\") -> await this.timeout GDScript - if (line.find("yield(") != -1) { + if (line.contains("yield(")) { int start = line.find("yield("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3034,7 +3238,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- parse_json( AA ) -> TODO Object - if (line.find("parse_json(") != -1) { + if (line.contains("parse_json(")) { int start = line.find("parse_json("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3044,7 +3248,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform - if (line.find(".xform(") != -1) { + if (line.contains(".xform(")) { int start = line.find(".xform("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3056,12 +3260,12 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- .xform_inv(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform - if (line.find(".xform_inv(") != -1) { + if (line.contains(".xform_inv(")) { int start = line.find(".xform_inv("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { String object_exec = get_object_of_execution(line.substr(0, start)); - if (line.find(object_exec + ".xform") != -1) { + if (line.contains(object_exec + ".xform")) { int start2 = line.find(object_exec + ".xform"); Vector<String> parts = parse_arguments(line.substr(start, end)); if (parts.size() == 1) { @@ -3072,7 +3276,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- "(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) Object - if (line.find("connect(") != -1) { + if (line.contains("connect(")) { int start = line.find("connect("); // Protection from disconnect if (start == 0 || line.get(start - 1) != 's') { @@ -3088,7 +3292,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object - if (line.find("disconnect(") != -1) { + if (line.contains("disconnect(")) { int start = line.find("disconnect("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3099,7 +3303,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object - if (line.find("is_connected(") != -1) { + if (line.contains("is_connected(")) { int start = line.find("is_connected("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3111,7 +3315,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- "(tween_method(A,B,C,D,E) != OK):", "(tween_method(Callable(A,B),C,D,E) Object // -- "(tween_method(A,B,C,D,E,[F,G]) != OK):", "(tween_method(Callable(A,B).bind(F,G),C,D,E) Object - if (line.find("tween_method(") != -1) { + if (line.contains("tween_method(")) { int start = line.find("tween_method("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3124,7 +3328,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // -- "(tween_callback(A,B,[C,D]) != OK):", "(connect(Callable(A,B).bind(C,D)) Object - if (line.find("tween_callback(") != -1) { + if (line.contains("tween_callback(")) { int start = line.find("tween_callback("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3138,7 +3342,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } // -- start(a,b) -> start(Callable(a,b)) Thread // -- start(a,b,c,d) -> start(Callable(a,b).bind(c),d) Thread - if (line.find("start(") != -1) { + if (line.contains("start(")) { int start = line.find("start("); int end = get_end_parenthess(line.substr(start)) + 1; // Protection from 'func start' @@ -3154,16 +3358,18 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // -- func _init(p_x:int)->void: -> func _init(p_x:int): Object # https://github.com/godotengine/godot/issues/50589 - if (line.find(" _init(") != -1) { + if (line.contains(" _init(")) { int start = line.find(" _init("); - int end = line.rfind(":") + 1; - if (end > -1) { - Vector<String> parts = parse_arguments(line.substr(start, end)); - line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start); + if (line.contains(":")) { + int end = line.rfind(":") + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start); + } } } // assert(speed < 20, str(randi()%10)) -> assert(speed < 20) #,str(randi()%10)) GDScript - GDScript bug constant message - if (line.find("assert(") != -1) { + if (line.contains("assert(")) { int start = line.find("assert("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3174,7 +3380,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture - if (line.find("create_from_image(") != -1) { + if (line.contains("create_from_image(")) { int start = line.find("create_from_image("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3185,7 +3391,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e) - if (line.find("set_cell_item(") != -1) { + if (line.contains("set_cell_item(")) { int start = line.find("set_cell_item("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3196,7 +3402,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c)) - if (line.find("get_cell_item(") != -1) { + if (line.contains("get_cell_item(")) { int start = line.find("get_cell_item("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3207,7 +3413,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c)) - if (line.find("get_cell_item_orientation(") != -1) { + if (line.contains("get_cell_item_orientation(")) { int start = line.find("get_cell_item_orientation("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3218,7 +3424,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // apply_impulse(A, B) -> apply_impulse(B, A) - if (line.find("apply_impulse(") != -1) { + if (line.contains("apply_impulse(")) { int start = line.find("apply_impulse("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3229,7 +3435,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // apply_force(A, B) -> apply_force(B, A) - if (line.find("apply_force(") != -1) { + if (line.contains("apply_force(")) { int start = line.find("apply_force("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3240,7 +3446,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // map_to_world(a, b, c) -> map_to_world(Vector3i(a, b, c)) - if (line.find("map_to_world(") != -1) { + if (line.contains("map_to_world(")) { int start = line.find("map_to_world("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3251,7 +3457,7 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } // OS.get_window_safe_area() -> DisplayServer.get_display_safe_area() - if (line.find("OS.get_window_safe_area(") != -1) { + if (line.contains("OS.get_window_safe_area(")) { int start = line.find("OS.get_window_safe_area("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3261,14 +3467,59 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai } } } + // draw_rect(a,b,c,d,e) -> draw_rect(a,b,c,d)#e) TODOGODOT4 Antialiasing argument is missing + if (line.contains("draw_rect(")) { + int start = line.find("draw_rect("); + int end = get_end_parenthess(line.substr(start)) + 1; + if (end > -1) { + Vector<String> parts = parse_arguments(line.substr(start, end)); + if (parts.size() == 5) { + line = line.substr(0, start) + "draw_rect(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start) + "# " + parts[4] + ") TODOGODOT4 Antialiasing argument is missing"; + } + } + } + // get_focus_owner() -> get_viewport().gui_get_focus_owner() + if (line.contains("get_focus_owner()")) { + line = line.replace("get_focus_owner()", "get_viewport().gui_get_focus_owner()"); + } + + // button.pressed = 1 -> button.button_pressed = 1 + if (line.contains(".pressed")) { + int start = line.find(".pressed"); + bool foundNextEqual = false; + String line_to_check = line.substr(start + String(".pressed").length()); + for (int current_index = 0; line_to_check.length() > current_index; current_index++) { + char32_t chr = line_to_check.get(current_index); + if (chr == '\t' || chr == ' ') { + continue; + } else if (chr == '=') { + foundNextEqual = true; + } else { + break; + } + } + if (foundNextEqual) { + line = line.substr(0, start) + ".button_pressed" + line.substr(start + String(".pressed").length()); + } + } + + // OS -> Time functions + if (line.contains("OS.get_ticks_msec")) { + line = line.replace("OS.get_ticks_msec", "Time.get_ticks_msec"); + } + if (line.contains("OS.get_ticks_usec")) { + line = line.replace("OS.get_ticks_usec", "Time.get_ticks_usec"); + } + if (line.contains("OS.get_unix_time")) { + line = line.replace("OS.get_unix_time", "Time.get_unix_time_from_system"); + } } -void ProjectConverter3To4::process_csharp_line(String &line) { - // TODO maybe this can be changed to normal rule +void ProjectConverter3To4::process_csharp_line(String &line, const RegExContainer ®_container) { line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()"); // -- Connect(,,,things) -> Connect(,Callable(,),things) Object - if (line.find("Connect(") != -1) { + if (line.contains("Connect(")) { int start = line.find("Connect("); // Protection from disconnect if (start == 0 || line.get(start - 1) != 's') { @@ -3282,7 +3533,7 @@ void ProjectConverter3To4::process_csharp_line(String &line) { } } // -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object - if (line.find("Disconnect(") != -1) { + if (line.contains("Disconnect(")) { int start = line.find("Disconnect("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3293,7 +3544,7 @@ void ProjectConverter3To4::process_csharp_line(String &line) { } } // -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object - if (line.find("IsConnected(") != -1) { + if (line.contains("IsConnected(")) { int start = line.find("IsConnected("); int end = get_end_parenthess(line.substr(start)) + 1; if (end > -1) { @@ -3305,415 +3556,317 @@ void ProjectConverter3To4::process_csharp_line(String &line) { } } -void ProjectConverter3To4::rename_csharp_functions(String &file_content) { - Vector<String> lines = file_content.split("\n"); - +void ProjectConverter3To4::rename_csharp_functions(Vector<String> &lines, const RegExContainer ®_container) { for (String &line : lines) { - process_csharp_line(line); - } - - // Collect vector to string - file_content = ""; - for (int i = 0; i < lines.size(); i++) { - file_content += lines[i]; - - if (i != lines.size() - 1) { - file_content += "\n"; + if (uint64_t(line.length()) <= maximum_line_length) { + process_csharp_line(line, reg_container); } } }; -// This is almost 1:1 copy of function which rename gdscript functions -Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &file_content) { +Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer ®_container) { int current_line = 1; - Vector<String> found_things; + Vector<String> found_renames; - for (String &line : file_content) { - String old_line = line; - process_csharp_line(line); - if (old_line != line) { - found_things.append(simple_line_formatter(current_line, old_line, line)); + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + String old_line = line; + process_csharp_line(line, reg_container); + if (old_line != line) { + found_renames.append(simple_line_formatter(current_line, old_line, line)); + } } } - return found_things; + return found_renames; } -void ProjectConverter3To4::rename_csharp_attributes(String &file_content) { - // -- [Remote] -> [RPC(MultiplayerAPI.RPCMode.AnyPeer)] - { - RegEx reg_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_remote.is_valid()); - file_content = reg_remote.sub(file_content, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true); - } - // -- [RemoteSync] -> [RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)] - { - RegEx reg_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_remotesync.is_valid()); - file_content = reg_remotesync.sub(file_content, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true); - } - // -- [Puppet] -> [RPC] - { - RegEx reg_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_puppet.is_valid()); - file_content = reg_puppet.sub(file_content, "[RPC]", true); - } - // -- [PuppetSync] -> [RPC(CallLocal = true)] - { - RegEx reg_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_puppetsync.is_valid()); - file_content = reg_puppetsync.sub(file_content, "[RPC(CallLocal = true)]", true); - } - String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n"; - // -- [Master] -> [RPC] - { - RegEx reg_remote = RegEx("\\[Master(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_remote.is_valid()); - file_content = reg_remote.sub(file_content, error_message + "[RPC]", true); - } - // -- [MasterSync] -> [RPC(CallLocal = true)] - { - RegEx reg_remote = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!reg_remote.is_valid()); - file_content = reg_remote.sub(file_content, error_message + "[RPC(CallLocal = true)]", true); +void ProjectConverter3To4::rename_csharp_attributes(Vector<String> &lines, const RegExContainer ®_container) { + static String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n"; + + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true); + line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true); + line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true); + line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true); + line = reg_container.keyword_csharp_master.sub(line, error_message + "[RPC]", true); + line = reg_container.keyword_csharp_mastersync.sub(line, error_message + "[RPC(CallLocal = true)]", true); + } } } -Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &file_content) { +Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer ®_container) { int current_line = 1; - Vector<String> found_things; + Vector<String> found_renames; - for (String &line : file_content) { - String old; - old = line; - { - RegEx regex = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line)); - } - old = line; - { - RegEx regex = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line)); - } - old = line; - { - RegEx regex = RegEx("\\[Puppet(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[Puppet]", "[RPC]", line)); - } - old = line; - { - RegEx regex = RegEx("\\[(Puppet|Slave)Sync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC(CallLocal = true)]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line)); - } - old = line; - { - RegEx regex = RegEx("\\[Master(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[Master]", "[RPC]", line)); - } - old = line; - { - RegEx regex = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "[RPC(CallLocal = true)]", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line)); - } + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + String old; + old = line; + line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line)); + } + old = line; + line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line)); + } + + old = line; + line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[Puppet]", "[RPC]", line)); + } + + old = line; + line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line)); + } + + old = line; + line = reg_container.keyword_csharp_master.sub(line, "[RPC]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[Master]", "[RPC]", line)); + } + + old = line; + line = reg_container.keyword_csharp_mastersync.sub(line, "[RPC(CallLocal = true)]", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line)); + } + } current_line++; } - return found_things; + return found_renames; } -void ProjectConverter3To4::rename_gdscript_keywords(String &file_content) { - { - RegEx reg_first = RegEx("([\n]+)tool"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@tool", true); - RegEx reg_second = RegEx("^tool"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@tool", true); - } - { - RegEx reg_first = RegEx("([\n\t]+)export\\b"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@export", true); - RegEx reg_second = RegEx("^export"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@export", true); - } - { - RegEx reg_first = RegEx("([\n]+)onready"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@onready", true); - RegEx reg_second = RegEx("^onready"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@onready", true); - } - { - RegEx reg_first = RegEx("([\n]+)remote func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc(any_peer) func", true); - RegEx reg_second = RegEx("^remote func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc(any_peer) func", true); - } - { - RegEx reg_first = RegEx("([\n]+)remotesync func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc(any_peer, call_local) func", true); - RegEx reg_second = RegEx("^remotesync func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc(any_peer, call_local) func", true); - } - { - RegEx reg_first = RegEx("([\n]+)sync func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc(any_peer, call_local) func", true); - RegEx reg_second = RegEx("^sync func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc(any_peer, call_local) func", true); - } - { - RegEx reg_first = RegEx("([\n]+)slave func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc func", true); - RegEx reg_second = RegEx("^slave func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc func", true); - } - { - RegEx reg_first = RegEx("([\n]+)puppet func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc func", true); - RegEx reg_second = RegEx("^puppet func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc func", true); - } - { - RegEx reg_first = RegEx("([\n]+)puppetsync func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1@rpc(call_local) func", true); - RegEx reg_second = RegEx("^puppetsync func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, "@rpc(call_local) func", true); - } - String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n"; - { - RegEx reg_first = RegEx("([\n]+)master func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1" + error_message + "@rpc func", true); - RegEx reg_second = RegEx("^master func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, error_message + "@rpc func", true); - } - { - RegEx reg_first = RegEx("([\n]+)mastersync func"); - CRASH_COND(!reg_first.is_valid()); - file_content = reg_first.sub(file_content, "$1" + error_message + "@rpc(call_local) func", true); - RegEx reg_second = RegEx("^mastersync func"); - CRASH_COND(!reg_second.is_valid()); - file_content = reg_second.sub(file_content, error_message + "@rpc(call_local) func", true); +void ProjectConverter3To4::rename_gdscript_keywords(Vector<String> &lines, const RegExContainer ®_container) { + static String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n"; + + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + if (line.contains("tool")) { + line = reg_container.keyword_gdscript_tool.sub(line, "@tool", true); + } + if (line.contains("export")) { + line = reg_container.keyword_gdscript_export_single.sub(line, "@export", true); + } + if (line.contains("export")) { + line = reg_container.keyword_gdscript_export_mutli.sub(line, "$1@export", true); + } + if (line.contains("onready")) { + line = reg_container.keyword_gdscript_onready.sub(line, "@onready", true); + } + if (line.contains("remote")) { + line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true); + } + if (line.contains("remote")) { + line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local) func", true); + } + if (line.contains("sync")) { + line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local) func", true); + } + if (line.contains("slave")) { + line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true); + } + if (line.contains("puppet")) { + line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true); + } + if (line.contains("puppet")) { + line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true); + } + if (line.contains("master")) { + line = reg_container.keyword_gdscript_master.sub(line, error_message + "@rpc func", true); + } + if (line.contains("master")) { + line = reg_container.keyword_gdscript_mastersync.sub(line, error_message + "@rpc(call_local) func", true); + } + } } } -Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &file_content) { - Vector<String> found_things; +Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &lines, const RegExContainer ®_container) { + Vector<String> found_renames; int current_line = 1; + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + String old; + + if (line.contains("tool")) { + old = line; + line = reg_container.keyword_gdscript_tool.sub(line, "@tool", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "tool", "@tool", line)); + } + } - for (String &line : file_content) { - String old; - old = line; - { - RegEx reg_first = RegEx("^tool"); - CRASH_COND(!reg_first.is_valid()); - line = reg_first.sub(line, "@tool", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "tool", "@tool", line)); - } - old = line; - { - RegEx reg_first = RegEx("([\t]+)export\\b"); - CRASH_COND(!reg_first.is_valid()); - line = reg_first.sub(line, "$1@export", true); - RegEx reg_second = RegEx("^export"); - CRASH_COND(!reg_second.is_valid()); - line = reg_second.sub(line, "@export", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "export", "@export", line)); - } - old = line; - { - RegEx reg_first = RegEx("^onready"); - CRASH_COND(!reg_first.is_valid()); - line = reg_first.sub(line, "@onready", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "onready", "@onready", line)); - } - old = line; - { - RegEx regex = RegEx("^remote func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc(any_peer) func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "remote func", "@rpc(any_peer) func", line)); - } - old = line; - { - RegEx regex = RegEx("^remotesync func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc(any_peer, call_local)) func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "remotesync func", "@rpc(any_peer, call_local)) func", line)); - } - old = line; - { - RegEx regex = RegEx("^sync func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc(any_peer, call_local)) func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "sync func", "@rpc(any_peer, call_local)) func", line)); - } - old = line; - { - RegEx regex = RegEx("^slave func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "slave func", "@rpc func", line)); - } - old = line; - { - RegEx regex = RegEx("^puppet func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "puppet func", "@rpc func", line)); - } - old = line; - { - RegEx regex = RegEx("^puppetsync func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc(call_local) func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "puppetsync func", "@rpc(call_local) func", line)); - } - old = line; - { - RegEx regex = RegEx("^master func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "master func", "@rpc func", line)); - } - old = line; - { - RegEx regex = RegEx("^mastersync func"); - CRASH_COND(!regex.is_valid()); - line = regex.sub(line, "@rpc(call_local) func", true); - } - if (old != line) { - found_things.append(line_formatter(current_line, "mastersync func", "@rpc(call_local) func", line)); - } - old = line; + if (line.contains("export")) { + old = line; + line = reg_container.keyword_gdscript_export_single.sub(line, "$1@export", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "export", "@export", line)); + } + } + if (line.contains("export")) { + old = line; + line = reg_container.keyword_gdscript_export_mutli.sub(line, "@export", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "export", "@export", line)); + } + } + + if (line.contains("onready")) { + old = line; + line = reg_container.keyword_gdscript_tool.sub(line, "@onready", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "onready", "@onready", line)); + } + } + + if (line.contains("remote")) { + old = line; + line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "remote func", "@rpc(any_peer) func", line)); + } + } + + if (line.contains("remote")) { + old = line; + line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local)) func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "remotesync func", "@rpc(any_peer, call_local)) func", line)); + } + } + + if (line.contains("sync")) { + old = line; + line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local)) func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "sync func", "@rpc(any_peer, call_local)) func", line)); + } + } + + if (line.contains("slave")) { + old = line; + line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "slave func", "@rpc func", line)); + } + } + + if (line.contains("puppet")) { + old = line; + line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "puppet func", "@rpc func", line)); + } + } + + if (line.contains("puppet")) { + old = line; + line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "puppetsync func", "@rpc(call_local) func", line)); + } + } + + if (line.contains("master")) { + old = line; + line = reg_container.keyword_gdscript_master.sub(line, "@rpc func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "master func", "@rpc func", line)); + } + } + + if (line.contains("master")) { + old = line; + line = reg_container.keyword_gdscript_master.sub(line, "@rpc(call_local) func", true); + if (old != line) { + found_renames.append(line_formatter(current_line, "mastersync func", "@rpc(call_local) func", line)); + } + } + } current_line++; } - return found_things; + return found_renames; } -void ProjectConverter3To4::custom_rename(String &file_content, String from, String to) { +void ProjectConverter3To4::custom_rename(Vector<String> &lines, String from, String to) { RegEx reg = RegEx(String("\\b") + from + "\\b"); CRASH_COND(!reg.is_valid()); - file_content = reg.sub(file_content, to, true); + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + line = reg.sub(line, to, true); + } + } }; -Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &file_content, String from, String to) { - Vector<String> found_things; +Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &lines, String from, String to) { + Vector<String> found_renames; RegEx reg = RegEx(String("\\b") + from + "\\b"); CRASH_COND(!reg.is_valid()); int current_line = 1; - for (String &line : file_content) { - TypedArray<RegExMatch> reg_match = reg.search_all(line); - if (reg_match.size() > 0) { - found_things.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader" + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + TypedArray<RegExMatch> reg_match = reg.search_all(line); + if (reg_match.size() > 0) { + found_renames.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader" + } } current_line++; } - return found_things; + return found_renames; } -void ProjectConverter3To4::rename_common(const char *array[][2], String &file_content) { - int current_index = 0; - while (array[current_index][0]) { - RegEx reg = RegEx(String("\\b") + array[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); - file_content = reg.sub(file_content, array[current_index][1], true); - current_index++; +void ProjectConverter3To4::rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines) { + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) { + if (line.contains(array[current_index][0])) { + line = cached_regexes[current_index]->sub(line, array[current_index][1], true); + } + } + } } } -// Common renaming, -Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[][2], Vector<String> &file_content) { - int current_index = 0; - - Vector<String> found_things; +Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines) { + Vector<String> found_renames; - while (array[current_index][0]) { - RegEx reg = RegEx(String("\\b") + array[current_index][0] + "\\b"); - CRASH_COND(!reg.is_valid()); + int current_line = 1; - int current_line = 1; - for (String &line : file_content) { - TypedArray<RegExMatch> reg_match = reg.search_all(line); - if (reg_match.size() > 0) { - found_things.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line)); + for (String &line : lines) { + if (uint64_t(line.length()) <= maximum_line_length) { + for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) { + if (line.contains(array[current_index][0])) { + TypedArray<RegExMatch> reg_match = cached_regexes[current_index]->search_all(line); + if (reg_match.size() > 0) { + found_renames.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line)); + } + } } - current_line++; } - current_index++; + current_line++; } - return found_things; + + return found_renames; } -// Formats data to print them into user console when trying to convert data +// Prints full info about renamed things e.g.: +// Line (67) remove -> remove_at - LINE """ doubler._blacklist.remove(0) """ String ProjectConverter3To4::line_formatter(int current_line, String from, String to, String line) { if (from.size() > 200) { from = from.substr(0, 197) + "..."; @@ -3727,6 +3880,8 @@ String ProjectConverter3To4::line_formatter(int current_line, String from, Strin return String("Line (") + itos(current_line) + ") " + from.replace("\r", "").replace("\n", "") + " -> " + to.replace("\r", "").replace("\n", "") + " - LINE \"\"\" " + line.replace("\r", "").replace("\n", "").strip_edges() + " \"\"\""; } +// Prints only full lines e.g.: +// Line (1) - FULL LINES - """yield(get_tree().create_timer(3), 'timeout')""" =====> """ await get_tree().create_timer(3).timeout """ String ProjectConverter3To4::simple_line_formatter(int current_line, String old_line, String line) { if (old_line.size() > 1000) { old_line = old_line.substr(0, 997) + "..."; @@ -3737,6 +3892,19 @@ String ProjectConverter3To4::simple_line_formatter(int current_line, String old_ return String("Line (") + itos(current_line) + ") - FULL LINES - \"\"\"" + old_line.replace("\r", "").replace("\n", "").strip_edges() + "\"\"\" =====> \"\"\" " + line.replace("\r", "").replace("\n", "").strip_edges() + " \"\"\""; } +// Collects string from vector strings +String ProjectConverter3To4::collect_string_from_vector(Vector<String> &vector) { + String string = ""; + for (int i = 0; i < vector.size(); i++) { + string += vector[i]; + + if (i != vector.size() - 1) { + string += "\n"; + } + } + return string; +} + #else // No regex. int ProjectConverter3To4::convert() { diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h index 8526e2ceb9..fc6d66c9a8 100644 --- a/editor/project_converter_3_to_4.h +++ b/editor/project_converter_3_to_4.h @@ -35,37 +35,43 @@ #include "core/io/file_access.h" #include "core/object/ref_counted.h" #include "core/string/ustring.h" +#include "core/templates/local_vector.h" + +class RegEx; class ProjectConverter3To4 { public: class RegExContainer; private: - void rename_enums(String &file_content); - Vector<String> check_for_rename_enums(Vector<String> &file_content); + uint64_t maximum_file_size; + uint64_t maximum_line_length; + + void rename_colors(Vector<String> &lines, const RegExContainer ®_container); + Vector<String> check_for_rename_colors(Vector<String> &lines, const RegExContainer ®_container); - void rename_classes(String &file_content); - Vector<String> check_for_rename_classes(Vector<String> &file_content); + void rename_classes(Vector<String> &lines, const RegExContainer ®_container); + Vector<String> check_for_rename_classes(Vector<String> &lines, const RegExContainer ®_container); - void rename_gdscript_functions(String &file_content, const RegExContainer ®_container, bool builtin); - Vector<String> check_for_rename_gdscript_functions(Vector<String> &file_content, const RegExContainer ®_container, bool builtin); + void rename_gdscript_functions(Vector<String> &lines, const RegExContainer ®_container, bool builtin); + Vector<String> check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer ®_container, bool builtin); void process_gdscript_line(String &line, const RegExContainer ®_container, bool builtin); - void rename_csharp_functions(String &file_content); - Vector<String> check_for_rename_csharp_functions(Vector<String> &file_content); - void process_csharp_line(String &line); + void rename_csharp_functions(Vector<String> &lines, const RegExContainer ®_container); + Vector<String> check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer ®_container); + void process_csharp_line(String &line, const RegExContainer ®_container); - void rename_csharp_attributes(String &file_content); - Vector<String> check_for_rename_csharp_attributes(Vector<String> &file_content); + void rename_csharp_attributes(Vector<String> &lines, const RegExContainer ®_container); + Vector<String> check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer ®_container); - void rename_gdscript_keywords(String &file_content); - Vector<String> check_for_rename_gdscript_keywords(Vector<String> &file_content); + void rename_gdscript_keywords(Vector<String> &lines, const RegExContainer ®_container); + Vector<String> check_for_rename_gdscript_keywords(Vector<String> &lines, const RegExContainer ®_container); - void custom_rename(String &file_content, String from, String to); - Vector<String> check_for_custom_rename(Vector<String> &file_content, String from, String to); + void custom_rename(Vector<String> &lines, String from, String to); + Vector<String> check_for_custom_rename(Vector<String> &lines, String from, String to); - void rename_common(const char *array[][2], String &file_content); - Vector<String> check_for_rename_common(const char *array[][2], Vector<String> &file_content); + void rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines); + Vector<String> check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines); Vector<String> check_for_files(); @@ -77,15 +83,17 @@ private: String line_formatter(int current_line, String from, String to, String line); String simple_line_formatter(int current_line, String old_line, String line); + String collect_string_from_vector(Vector<String> &vector); bool test_single_array(const char *array[][2], bool ignore_second_check = false); - bool test_conversion_single_additional(String name, String expected, void (ProjectConverter3To4::*func)(String &), String what); - bool test_conversion_single_additional_builtin(String name, String expected, void (ProjectConverter3To4::*func)(String &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin); - bool test_conversion_single_normal(String name, String expected, const char *array[][2], String what); + bool test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &, bool), String what, const RegExContainer ®_container, bool builtin); + bool test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &), String what, const RegExContainer ®_container); + bool test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> ®ex_cache, String what); bool test_array_names(); - bool test_conversion(const RegExContainer ®_container); + bool test_conversion(RegExContainer ®_container); public: + ProjectConverter3To4(int, int); int validate_conversion(); int convert(); }; diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 361406d963..9909ab378a 100644 --- a/editor/project_manager.cpp +++ b/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); } diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 7b4df696b7..300a3d0f05 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -500,7 +500,7 @@ String RenameDialog::_postprocess(const String &subject) { if (style_id == 1) { // PascalCase to snake_case - result = result.camelcase_to_underscore(true); + result = result.to_snake_case(); result = _regex("_+", result, "_"); } else if (style_id == 2) { @@ -521,7 +521,7 @@ String RenameDialog::_postprocess(const String &subject) { end = start + 1; } buffer += result.substr(end, result.size() - (end + 1)); - result = buffer.replace("_", "").capitalize(); + result = buffer.to_pascal_case(); } } diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp index 94a5c07709..9b8684b7b8 100644 --- a/editor/scene_create_dialog.cpp +++ b/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.")); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index d62b78e883..e2265f2f83 100644 --- a/editor/scene_tree_dock.cpp +++ b/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; } @@ -1068,24 +1068,61 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } break; case TOOL_TOGGLE_SCENE_UNIQUE_NAME: { - List<Node *> selection = editor_selection->get_selected_node_list(); - List<Node *>::Element *e = selection.front(); - if (e) { - Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo(); - Node *node = e->get(); - bool enabled = node->is_unique_name_in_owner(); - if (!enabled && get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(node->get_name())) != nullptr) { - accept->set_text(TTR("Another node already uses this unique name in the scene.")); + // Enabling/disabling based on the same node based on which the checkbox in the menu is checked/unchecked. + List<Node *>::Element *first_selected = editor_selection->get_selected_node_list().front(); + if (first_selected == nullptr) { + return; + } + bool enabling = !first_selected->get()->is_unique_name_in_owner(); + + List<Node *> full_selection = editor_selection->get_full_selected_node_list(); + Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo(); + + if (enabling) { + Vector<Node *> new_unique_nodes; + Vector<StringName> new_unique_names; + Vector<StringName> cant_be_set_unique_names; + + for (Node *node : full_selection) { + if (node->is_unique_name_in_owner()) { + continue; + } + StringName name = node->get_name(); + if (new_unique_names.find(name) != -1 || get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(name)) != nullptr) { + cant_be_set_unique_names.push_back(name); + } else { + new_unique_nodes.push_back(node); + new_unique_names.push_back(name); + } + } + + if (new_unique_nodes.size()) { + undo_redo->create_action(TTR("Enable Scene Unique Name(s)")); + for (Node *node : new_unique_nodes) { + undo_redo->add_do_method(node, "set_unique_name_in_owner", true); + undo_redo->add_undo_method(node, "set_unique_name_in_owner", false); + } + undo_redo->commit_action(); + } + + if (cant_be_set_unique_names.size()) { + String popup_text = TTR("Unique names already used by another node in the scene:"); + popup_text += "\n"; + for (StringName name : cant_be_set_unique_names) { + popup_text += "\n" + String(name); + } + accept->set_text(popup_text); accept->popup_centered(); - return; } - if (!enabled) { - undo_redo->create_action(TTR("Enable Scene Unique Name")); - } else { - undo_redo->create_action(TTR("Disable Scene Unique Name")); + } else { // Disabling. + undo_redo->create_action(TTR("Disable Scene Unique Name(s)")); + for (Node *node : full_selection) { + if (!node->is_unique_name_in_owner()) { + continue; + } + undo_redo->add_do_method(node, "set_unique_name_in_owner", false); + undo_redo->add_undo_method(node, "set_unique_name_in_owner", true); } - undo_redo->add_do_method(node, "set_unique_name_in_owner", !enabled); - undo_redo->add_undo_method(node, "set_unique_name_in_owner", enabled); undo_redo->commit_action(); } } break; @@ -1469,7 +1506,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 +1876,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 +2239,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); @@ -2821,14 +2858,26 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_separator(); menu->add_icon_shortcut(get_theme_icon(SNAME("CopyNodePath"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH); } + } - if (selection[0]->get_owner() == EditorNode::get_singleton()->get_edited_scene()) { - // Only for nodes owned by the edited scene root. + if (profile_allow_editing) { + // Allow multi-toggling scene unique names but only if all selected nodes are owned by the edited scene root. + bool all_owned = true; + for (Node *node : full_selection) { + if (node->get_owner() != EditorNode::get_singleton()->get_edited_scene()) { + all_owned = false; + break; + } + } + if (all_owned) { menu->add_separator(); menu->add_icon_check_item(get_theme_icon(SNAME("SceneUniqueName"), SNAME("EditorIcons")), TTR("Access as Scene Unique Name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME); + // Checked based on `selection[0]` because `full_selection` has undesired ordering. menu->set_item_checked(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), selection[0]->is_unique_name_in_owner()); } + } + if (selection.size() == 1) { bool is_external = (!selection[0]->get_scene_file_path().is_empty()); if (is_external) { bool is_inherited = selection[0]->get_scene_inherited_state() != nullptr; @@ -2938,9 +2987,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 +3046,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 +3248,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(); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 559a909b1c..88ca371fac 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -354,7 +354,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { tooltip += "\n\n" + p_node->get_editor_description(); } - item->set_tooltip(0, tooltip); + item->set_tooltip_text(0, tooltip); } else if (p_node != get_scene_node() && !p_node->get_scene_file_path().is_empty() && can_open_instance) { item->add_button(0, get_theme_icon(SNAME("InstanceOptions"), SNAME("EditorIcons")), BUTTON_SUBSCENE, false, TTR("Open in Editor")); @@ -363,7 +363,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { tooltip += "\n\n" + p_node->get_editor_description(); } - item->set_tooltip(0, tooltip); + item->set_tooltip_text(0, tooltip); } else { StringName type = EditorNode::get_singleton()->get_object_custom_type_name(p_node); if (type == StringName()) { @@ -375,7 +375,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { tooltip += "\n\n" + p_node->get_editor_description(); } - item->set_tooltip(0, tooltip); + item->set_tooltip_text(0, tooltip); } if (can_open_instance && undo_redo.is_valid()) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 15e992ce18..7d065b4920 100644 --- a/editor/script_create_dialog.cpp +++ b/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(); @@ -898,7 +898,7 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL // Get name from file name if no name in meta information if (script_template.name == String()) { - script_template.name = p_filename.get_basename().replace("_", " ").capitalize(); + script_template.name = p_filename.get_basename().capitalize(); } return script_template; diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp index 8c4a231e8a..522fd7c645 100644 --- a/editor/shader_create_dialog.cpp +++ b/editor/shader_create_dialog.cpp @@ -161,7 +161,7 @@ void ShaderCreateDialog::_create_new() { shader = text_shader; StringBuilder code; - code += vformat("shader_type %s;\n", mode_menu->get_text().replace(" ", "").camelcase_to_underscore()); + code += vformat("shader_type %s;\n", mode_menu->get_text().to_snake_case()); if (current_template == 0) { // Default template. code += "\n"; diff --git a/editor/translations/extract.py b/editor/translations/extract.py index 7f3da400e7..07026baee2 100755 --- a/editor/translations/extract.py +++ b/editor/translations/extract.py @@ -139,7 +139,7 @@ theme_property_patterns = { } -# See String::camelcase_to_underscore(). +# See String::_camelcase_to_underscore(). capitalize_re = re.compile(r"(?<=\D)(?=\d)|(?<=\d)(?=\D([a-z]|\d))") diff --git a/main/main.cpp b/main/main.cpp index 7964ba8e3e..d0170d8093 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -156,6 +156,8 @@ static OS::ProcessID editor_pid = 0; #ifdef TOOLS_ENABLED static bool auto_build_solutions = false; static String debug_server_uri; +static int converter_max_kb_file = 4 * 1024; // 4MB +static int converter_max_line_length = 100000; HashMap<Main::CLIScope, Vector<String>> forwardable_cli_arguments; #endif @@ -403,8 +405,8 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print(" <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe'). The target directory should exist.\n"); OS::get_singleton()->print(" --export-debug <preset> <path> Same as --export, but using the debug template.\n"); OS::get_singleton()->print(" --export-pack <preset> <path> Same as --export, but only export the game pack for the given preset. The <path> extension determines whether it will be in PCK or ZIP format.\n"); - OS::get_singleton()->print(" --convert-3to4 Converts project from Godot 3.x to Godot 4.x.\n"); - OS::get_singleton()->print(" --validate-conversion-3to4 Shows what elements will be renamed when converting project from Godot 3.x to Godot 4.x.\n"); + OS::get_singleton()->print(" --convert-3to4 [<max_file_kb>] [<max_line_size>] Converts project from Godot 3.x to Godot 4.x.\n"); + OS::get_singleton()->print(" --validate-conversion-3to4 [<max_file_kb>] [<max_line_size>] Shows what elements will be renamed when converting project from Godot 3.x to Godot 4.x.\n"); OS::get_singleton()->print(" --doctool [<path>] Dump the engine API reference to the given <path> (defaults to current dir) in XML format, merging if existing files are found.\n"); OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n"); OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n"); @@ -1086,10 +1088,32 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph // Actually handling is done in start(). cmdline_tool = true; main_args.push_back(I->get()); + + if (I->next() && !I->next()->get().begins_with("-")) { + if (itos(I->next()->get().to_int()) == I->next()->get()) { + converter_max_kb_file = I->next()->get().to_int(); + } + if (I->next()->next() && !I->next()->next()->get().begins_with("-")) { + if (itos(I->next()->next()->get().to_int()) == I->next()->next()->get()) { + converter_max_line_length = I->next()->next()->get().to_int(); + } + } + } } else if (I->get() == "--validate-conversion-3to4") { // Actually handling is done in start(). cmdline_tool = true; main_args.push_back(I->get()); + + if (I->next() && !I->next()->get().begins_with("-")) { + if (itos(I->next()->get().to_int()) == I->next()->get()) { + converter_max_kb_file = I->next()->get().to_int(); + } + if (I->next()->next() && !I->next()->next()->get().begins_with("-")) { + if (itos(I->next()->next()->get().to_int()) == I->next()->next()->get()) { + converter_max_line_length = I->next()->next()->get().to_int(); + } + } + } } else if (I->get() == "--doctool") { // Actually handling is done in start(). cmdline_tool = true; @@ -2342,7 +2366,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 +2384,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); @@ -2394,12 +2418,12 @@ bool Main::start() { } if (converting_project) { - int exit_code = ProjectConverter3To4().convert(); + int exit_code = ProjectConverter3To4(converter_max_kb_file, converter_max_line_length).convert(); OS::get_singleton()->set_exit_code(exit_code); return false; } if (validating_converting_project) { - int exit_code = ProjectConverter3To4().validate_conversion(); + int exit_code = ProjectConverter3To4(converter_max_kb_file, converter_max_line_length).validate_conversion(); OS::get_singleton()->set_exit_code(exit_code); return false; } @@ -2730,11 +2754,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())); } } diff --git a/misc/hooks/pre-commit-black b/misc/hooks/pre-commit-black index fd93bfe73c..b7335685ae 100755 --- a/misc/hooks/pre-commit-black +++ b/misc/hooks/pre-commit-black @@ -70,7 +70,7 @@ if [ ! -x "$BLACK" ] ; then $XMSG -center -title "Error" "Error: black executable not found." exit 1 elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then - winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")" + winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "Error: black executable not found." exit 1 fi @@ -160,7 +160,7 @@ while true; do yn="N" fi elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then - winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")" + winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?" choice=$? if [ "$choice" = "100" ] ; then diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format index e8e62e6470..44b6f59132 100755 --- a/misc/hooks/pre-commit-clang-format +++ b/misc/hooks/pre-commit-clang-format @@ -90,7 +90,7 @@ if [ ! -x "$CLANG_FORMAT" ] ; then $XMSG -center -title "Error" "$message" exit 1 elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then - winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")" + winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "$message" exit 1 fi @@ -200,7 +200,7 @@ while true; do yn="N" fi elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then - winmessage="$(canonicalize_filename "./.git/hooks/winmessage.ps1")" + winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")" $PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?" choice=$? if [ "$choice" = "100" ] ; then diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index 61df8cdf06..02922086f0 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -45,10 +45,11 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l int previous_column = 0; bool prev_is_char = false; - bool prev_is_number = false; + bool prev_is_digit = false; bool prev_is_binary_op = false; bool in_keyword = false; bool in_word = false; + bool in_number = false; bool in_function_name = false; bool in_lambda = false; bool in_variable_declaration = false; @@ -94,7 +95,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l color = font_color; bool is_char = !is_symbol(str[j]); bool is_a_symbol = is_symbol(str[j]); - bool is_number = is_digit(str[j]); + bool is_a_digit = is_digit(str[j]); bool is_binary_op = false; /* color regions */ @@ -233,58 +234,80 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_region = -1; prev_is_char = false; - prev_is_number = false; + prev_is_digit = false; + prev_is_binary_op = false; continue; } } } + // A bit of a hack, but couldn't come up with anything better. + if (j > 0 && (str[j] == '&' || str[j] == '^' || str[j] == '%' || str[j] == '+' || str[j] == '-' || str[j] == '~' || str[j] == '.')) { + if (!keywords.has(previous_text)) { + if (previous_text == "PI" || previous_text == "TAU" || previous_text == "INF" || previous_text == "NAN") { + is_binary_op = true; + } else { + int k = j - 1; + while (k > 0 && is_whitespace(str[k])) { + k--; + } + if (!is_symbol(str[k]) || str[k] == '"' || str[k] == '\'' || str[k] == ')' || str[k] == ']' || str[k] == '}') { + is_binary_op = true; + } + } + } + } + + if (!is_char) { + in_keyword = false; + } + // allow ABCDEF in hex notation - if (is_hex_notation && (is_hex_digit(str[j]) || is_number)) { - is_number = true; + if (is_hex_notation && (is_hex_digit(str[j]) || is_a_digit)) { + is_a_digit = true; } else { is_hex_notation = false; } // disallow anything not a 0 or 1 in binary notation - if (is_bin_notation && (is_binary_digit(str[j]))) { - is_number = true; - } else if (is_bin_notation) { - is_bin_notation = false; - is_number = false; - } else { + if (is_bin_notation && !is_binary_digit(str[j])) { + is_a_digit = false; is_bin_notation = false; } - // check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation - if ((str[j] == '.' || str[j] == 'x' || str[j] == 'b' || str[j] == '_' || str[j] == 'e') && !in_word && prev_is_number && !is_number) { - is_number = true; - is_a_symbol = false; - is_char = false; + if (!in_number && !in_word && is_a_digit) { + in_number = true; + } - if (str[j] == 'x' && str[j - 1] == '0') { - is_hex_notation = true; - } else if (str[j] == 'b' && str[j - 1] == '0') { + // Special cases for numbers + if (in_number && !is_a_digit) { + if (str[j] == 'b' && str[j - 1] == '0') { is_bin_notation = true; + } else if (str[j] == 'x' && str[j - 1] == '0') { + is_hex_notation = true; + } else if (!((str[j] == '-' || str[j] == '+') && str[j - 1] == 'e' && !prev_is_digit) && + !(str[j] == '_' && (prev_is_digit || str[j - 1] == 'b' || str[j - 1] == 'x' || str[j - 1] == '.')) && + !((str[j] == 'e' || str[j] == '.') && (prev_is_digit || str[j - 1] == '_')) && + !((str[j] == '-' || str[j] == '+' || str[j] == '~') && !prev_is_binary_op && str[j - 1] != 'e')) { + /* 1st row of condition: '+' or '-' after scientific notation; + 2nd row of condition: '_' as a numeric separator; + 3rd row of condition: Scientific notation 'e' and floating points; + 4th row of condition: Multiple unary operators. */ + in_number = false; } + } else if ((str[j] == '-' || str[j] == '+' || str[j] == '~' || (str[j] == '.' && str[j + 1] != '.' && (j == 0 || (j > 0 && str[j - 1] != '.')))) && !is_binary_op) { + // Start a number from unary mathematical operators and floating points, except for '..' + in_number = true; } - if (!in_word && (is_ascii_char(str[j]) || is_underscore(str[j])) && !is_number) { + if (!in_word && (is_ascii_char(str[j]) || is_underscore(str[j])) && !in_number) { in_word = true; } - if ((in_keyword || in_word) && !is_hex_notation) { - is_number = false; - } - if (is_a_symbol && str[j] != '.' && in_word) { in_word = false; } - if (!is_char) { - in_keyword = false; - } - if (!in_keyword && is_char && !prev_is_char) { int to = j; while (to < line_length && !is_symbol(str[to])) { @@ -355,7 +378,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } } - if (!in_function_name && !in_member_variable && !in_keyword && !is_number && in_word) { + if (!in_function_name && !in_member_variable && !in_keyword && !in_number && in_word) { int k = j; while (k > 0 && !is_symbol(str[k]) && !is_whitespace(str[k])) { k--; @@ -403,22 +426,6 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_member_variable = false; } - if (j > 0 && (str[j] == '&' || str[j] == '^' || str[j] == '%' || str[j] == '+' || str[j] == '-' || str[j] == '~')) { - int k = j - 1; - while (k > 0 && is_whitespace(str[k])) { - k--; - } - if (!is_symbol(str[k]) || str[k] == '"' || str[k] == '\'' || str[k] == ')' || str[k] == ']' || str[k] == '}') { - is_binary_op = true; - } - } - - // Highlight '+' and '-' like numbers when unary - if ((str[j] == '+' || str[j] == '-' || str[j] == '~') && !is_binary_op) { - is_number = true; - is_a_symbol = false; - } - // Keep symbol color for binary '&&'. In the case of '&&&' use StringName color for the last ampersand if (!in_string_name && in_region == -1 && str[j] == '&' && !is_binary_op) { if (j >= 2 && str[j - 1] == '&' && str[j - 2] != '&' && prev_is_binary_op) { @@ -479,12 +486,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } else { color = function_color; } + } else if (in_number) { + next_type = NUMBER; + color = number_color; } else if (is_a_symbol) { next_type = SYMBOL; color = symbol_color; - } else if (is_number) { - next_type = NUMBER; - color = number_color; } else if (expect_type) { next_type = TYPE; color = type_color; @@ -516,7 +523,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } prev_is_char = is_char; - prev_is_number = is_number; + prev_is_digit = is_a_digit; prev_is_binary_op = is_binary_op; if (color != prev_color) { diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index cf2d6ae9f8..10babad378 100644 --- a/modules/gdscript/gdscript.cpp +++ b/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)) { diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index a07d4855f3..c8c876369f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/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)) { diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 44b60369ab..fd213e7b37 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/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(); diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index e3b956369d..6c346acb7e 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/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); } } diff --git a/modules/gltf/doc_classes/GLTFCamera.xml b/modules/gltf/doc_classes/GLTFCamera.xml index b90abd105d..49efaa1564 100644 --- a/modules/gltf/doc_classes/GLTFCamera.xml +++ b/modules/gltf/doc_classes/GLTFCamera.xml @@ -10,6 +10,34 @@ <link title="GLTF camera detailed specification">https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-camera</link> <link title="GLTF camera spec and example file">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md</link> </tutorials> + <methods> + <method name="from_dictionary" qualifiers="static"> + <return type="GLTFCamera" /> + <param index="0" name="dictionary" type="Dictionary" /> + <description> + Creates a new GLTFCamera instance by parsing the given [Dictionary]. + </description> + </method> + <method name="from_node" qualifiers="static"> + <return type="GLTFCamera" /> + <param index="0" name="camera_node" type="Camera3D" /> + <description> + Create a new GLTFCamera instance from the given Godot [Camera3D] node. + </description> + </method> + <method name="to_dictionary" qualifiers="const"> + <return type="Dictionary" /> + <description> + Serializes this GLTFCamera instance into a [Dictionary]. + </description> + </method> + <method name="to_node" qualifiers="const"> + <return type="Camera3D" /> + <description> + Converts this GLTFCamera instance into a Godot [Camera3D] node. + </description> + </method> + </methods> <members> <member name="depth_far" type="float" setter="set_depth_far" getter="get_depth_far" default="4000.0"> The distance to the far culling boundary for this camera relative to its local Z axis, in meters. This maps to GLTF's [code]zfar[/code] property. diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml index db2dfb487a..7fd59e14bc 100644 --- a/modules/gltf/doc_classes/GLTFLight.xml +++ b/modules/gltf/doc_classes/GLTFLight.xml @@ -9,6 +9,34 @@ <tutorials> <link title="KHR_lights_punctual GLTF extension spec">https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual</link> </tutorials> + <methods> + <method name="from_dictionary" qualifiers="static"> + <return type="GLTFLight" /> + <param index="0" name="dictionary" type="Dictionary" /> + <description> + Creates a new GLTFLight instance by parsing the given [Dictionary]. + </description> + </method> + <method name="from_node" qualifiers="static"> + <return type="GLTFLight" /> + <param index="0" name="light_node" type="Light3D" /> + <description> + Create a new GLTFLight instance from the given Godot [Light3D] node. + </description> + </method> + <method name="to_dictionary" qualifiers="const"> + <return type="Dictionary" /> + <description> + Serializes this GLTFLight instance into a [Dictionary]. + </description> + </method> + <method name="to_node" qualifiers="const"> + <return type="Light3D" /> + <description> + Converts this GLTFLight instance into a Godot [Light3D] node. + </description> + </method> + </methods> <members> <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> The [Color] of the light. Defaults to white. A black color causes the light to have no effect. diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index 707769da35..ab52761e17 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/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; } diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp index faad2d315d..017a44cccf 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.cpp +++ b/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(); diff --git a/modules/gltf/extensions/gltf_light.cpp b/modules/gltf/extensions/gltf_light.cpp index af21a4e804..ab5a15c671 100644 --- a/modules/gltf/extensions/gltf_light.cpp +++ b/modules/gltf/extensions/gltf_light.cpp @@ -31,6 +31,12 @@ #include "gltf_light.h" void GLTFLight::_bind_methods() { + ClassDB::bind_static_method("GLTFLight", D_METHOD("from_node", "light_node"), &GLTFLight::from_node); + ClassDB::bind_method(D_METHOD("to_node"), &GLTFLight::to_node); + + ClassDB::bind_static_method("GLTFLight", D_METHOD("from_dictionary", "dictionary"), &GLTFLight::from_dictionary); + ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFLight::to_dictionary); + ClassDB::bind_method(D_METHOD("get_color"), &GLTFLight::get_color); ClassDB::bind_method(D_METHOD("set_color", "color"), &GLTFLight::set_color); ClassDB::bind_method(D_METHOD("get_intensity"), &GLTFLight::get_intensity); @@ -99,3 +105,116 @@ float GLTFLight::get_outer_cone_angle() { void GLTFLight::set_outer_cone_angle(float p_outer_cone_angle) { outer_cone_angle = p_outer_cone_angle; } + +Ref<GLTFLight> GLTFLight::from_node(const Light3D *p_light) { + Ref<GLTFLight> l; + l.instantiate(); + l->color = p_light->get_color(); + if (cast_to<DirectionalLight3D>(p_light)) { + l->light_type = "directional"; + const DirectionalLight3D *light = cast_to<const DirectionalLight3D>(p_light); + l->intensity = light->get_param(DirectionalLight3D::PARAM_ENERGY); + l->range = FLT_MAX; // Range for directional lights is infinite in Godot. + } else if (cast_to<const OmniLight3D>(p_light)) { + l->light_type = "point"; + const OmniLight3D *light = cast_to<const OmniLight3D>(p_light); + l->range = light->get_param(OmniLight3D::PARAM_RANGE); + l->intensity = light->get_param(OmniLight3D::PARAM_ENERGY); + } else if (cast_to<const SpotLight3D>(p_light)) { + l->light_type = "spot"; + const SpotLight3D *light = cast_to<const SpotLight3D>(p_light); + l->range = light->get_param(SpotLight3D::PARAM_RANGE); + l->intensity = light->get_param(SpotLight3D::PARAM_ENERGY); + l->outer_cone_angle = Math::deg_to_rad(light->get_param(SpotLight3D::PARAM_SPOT_ANGLE)); + // This equation is the inverse of the import equation (which has a desmos link). + float angle_ratio = 1 - (0.2 / (0.1 + light->get_param(SpotLight3D::PARAM_SPOT_ATTENUATION))); + angle_ratio = MAX(0, angle_ratio); + l->inner_cone_angle = l->outer_cone_angle * angle_ratio; + } + return l; +} + +Light3D *GLTFLight::to_node() const { + if (light_type == "directional") { + DirectionalLight3D *light = memnew(DirectionalLight3D); + light->set_param(Light3D::PARAM_ENERGY, intensity); + light->set_color(color); + return light; + } + const float range = CLAMP(this->range, 0, 4096); + if (light_type == "point") { + OmniLight3D *light = memnew(OmniLight3D); + light->set_param(OmniLight3D::PARAM_ENERGY, intensity); + light->set_param(OmniLight3D::PARAM_RANGE, range); + light->set_color(color); + return light; + } + if (light_type == "spot") { + SpotLight3D *light = memnew(SpotLight3D); + light->set_param(SpotLight3D::PARAM_ENERGY, intensity); + light->set_param(SpotLight3D::PARAM_RANGE, range); + light->set_param(SpotLight3D::PARAM_SPOT_ANGLE, Math::rad_to_deg(outer_cone_angle)); + light->set_color(color); + // Line of best fit derived from guessing, see https://www.desmos.com/calculator/biiflubp8b + // The points in desmos are not exact, except for (1, infinity). + float angle_ratio = inner_cone_angle / outer_cone_angle; + float angle_attenuation = 0.2 / (1 - angle_ratio) - 0.1; + light->set_param(SpotLight3D::PARAM_SPOT_ATTENUATION, angle_attenuation); + return light; + } + return memnew(Light3D); +} + +Ref<GLTFLight> GLTFLight::from_dictionary(const Dictionary p_dictionary) { + ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFLight>(), "Failed to parse GLTF light, missing required field 'type'."); + Ref<GLTFLight> light; + light.instantiate(); + const String &type = p_dictionary["type"]; + light->light_type = type; + + if (p_dictionary.has("color")) { + const Array &arr = p_dictionary["color"]; + if (arr.size() == 3) { + light->color = Color(arr[0], arr[1], arr[2]).linear_to_srgb(); + } else { + ERR_PRINT("Error parsing GLTF light: The color must have exactly 3 numbers."); + } + } + if (p_dictionary.has("intensity")) { + light->intensity = p_dictionary["intensity"]; + } + if (p_dictionary.has("range")) { + light->range = p_dictionary["range"]; + } + if (type == "spot") { + const Dictionary &spot = p_dictionary["spot"]; + light->inner_cone_angle = spot["innerConeAngle"]; + light->outer_cone_angle = spot["outerConeAngle"]; + if (light->inner_cone_angle >= light->outer_cone_angle) { + ERR_PRINT("Error parsing GLTF light: The inner angle must be smaller than the outer angle."); + } + } else if (type != "point" && type != "directional") { + ERR_PRINT("Error parsing GLTF light: Light type '" + type + "' is unknown."); + } + return light; +} + +Dictionary GLTFLight::to_dictionary() const { + Dictionary d; + Array color_array; + color_array.resize(3); + color_array[0] = color.r; + color_array[1] = color.g; + color_array[2] = color.b; + d["color"] = color_array; + d["type"] = light_type; + if (light_type == "spot") { + Dictionary spot_dict; + spot_dict["innerConeAngle"] = inner_cone_angle; + spot_dict["outerConeAngle"] = outer_cone_angle; + d["spot"] = spot_dict; + } + d["intensity"] = intensity; + d["range"] = range; + return d; +} diff --git a/modules/gltf/extensions/gltf_light.h b/modules/gltf/extensions/gltf_light.h index f0765a1bbc..04980e144c 100644 --- a/modules/gltf/extensions/gltf_light.h +++ b/modules/gltf/extensions/gltf_light.h @@ -70,6 +70,12 @@ public: float get_outer_cone_angle(); void set_outer_cone_angle(float p_outer_cone_angle); + + static Ref<GLTFLight> from_node(const Light3D *p_light); + Light3D *to_node() const; + + static Ref<GLTFLight> from_dictionary(const Dictionary p_dictionary); + Dictionary to_dictionary() const; }; #endif // GLTF_LIGHT_H diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 87ba1d9869..0ed212e21f 100644 --- a/modules/gltf/gltf_document.cpp +++ b/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 @@ -4534,28 +4534,7 @@ Error GLTFDocument::_serialize_lights(Ref<GLTFState> state) { } Array lights; for (GLTFLightIndex i = 0; i < state->lights.size(); i++) { - Dictionary d; - Ref<GLTFLight> light = state->lights[i]; - Array color; - color.resize(3); - color[0] = light->color.r; - color[1] = light->color.g; - color[2] = light->color.b; - d["color"] = color; - d["type"] = light->light_type; - if (light->light_type == "spot") { - Dictionary s; - float inner_cone_angle = light->inner_cone_angle; - s["innerConeAngle"] = inner_cone_angle; - float outer_cone_angle = light->outer_cone_angle; - s["outerConeAngle"] = outer_cone_angle; - d["spot"] = s; - } - float intensity = light->intensity; - d["intensity"] = intensity; - float range = light->range; - d["range"] = range; - lights.push_back(d); + lights.push_back(state->lights[i]->to_dictionary()); } Dictionary extensions; @@ -4577,27 +4556,7 @@ Error GLTFDocument::_serialize_cameras(Ref<GLTFState> state) { Array cameras; cameras.resize(state->cameras.size()); for (GLTFCameraIndex i = 0; i < state->cameras.size(); i++) { - Dictionary d; - - Ref<GLTFCamera> camera = state->cameras[i]; - - if (camera->get_perspective()) { - Dictionary persp; - persp["yfov"] = camera->get_fov(); - persp["zfar"] = camera->get_depth_far(); - persp["znear"] = camera->get_depth_near(); - d["perspective"] = persp; - d["type"] = "perspective"; - } else { - Dictionary ortho; - ortho["ymag"] = camera->get_size_mag(); - ortho["xmag"] = camera->get_size_mag(); - ortho["zfar"] = camera->get_depth_far(); - ortho["znear"] = camera->get_depth_near(); - d["orthographic"] = ortho; - d["type"] = "orthographic"; - } - cameras[i] = d; + cameras[i] = state->cameras[i]->to_dictionary(); } if (!state->cameras.size()) { @@ -4627,35 +4586,10 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) { const Array &lights = lights_punctual["lights"]; for (GLTFLightIndex light_i = 0; light_i < lights.size(); light_i++) { - const Dictionary &d = lights[light_i]; - - Ref<GLTFLight> light; - light.instantiate(); - ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); - const String &type = d["type"]; - light->light_type = type; - - if (d.has("color")) { - const Array &arr = d["color"]; - ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR); - const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb(); - light->color = c; - } - if (d.has("intensity")) { - light->intensity = d["intensity"]; + Ref<GLTFLight> light = GLTFLight::from_dictionary(lights[light_i]); + if (light.is_null()) { + return Error::ERR_PARSE_ERROR; } - if (d.has("range")) { - light->range = d["range"]; - } - if (type == "spot") { - const Dictionary &spot = d["spot"]; - light->inner_cone_angle = spot["innerConeAngle"]; - light->outer_cone_angle = spot["outerConeAngle"]; - ERR_CONTINUE_MSG(light->inner_cone_angle >= light->outer_cone_angle, "The inner angle must be smaller than the outer angle."); - } else if (type != "point" && type != "directional") { - ERR_CONTINUE_MSG(true, "Light type is unknown."); - } - state->lights.push_back(light); } @@ -4672,35 +4606,7 @@ Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) { const Array cameras = state->json["cameras"]; for (GLTFCameraIndex i = 0; i < cameras.size(); i++) { - const Dictionary &d = cameras[i]; - - Ref<GLTFCamera> camera; - camera.instantiate(); - ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); - const String &type = d["type"]; - if (type == "perspective") { - camera->set_perspective(true); - if (d.has("perspective")) { - const Dictionary &persp = d["perspective"]; - camera->set_fov(persp["yfov"]); - if (persp.has("zfar")) { - camera->set_depth_far(persp["zfar"]); - } - camera->set_depth_near(persp["znear"]); - } - } else if (type == "orthographic") { - camera->set_perspective(false); - if (d.has("orthographic")) { - const Dictionary &ortho = d["orthographic"]; - camera->set_size_mag(ortho["ymag"]); - camera->set_depth_far(ortho["zfar"]); - camera->set_depth_near(ortho["znear"]); - } - } else { - ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Camera3D should be in 'orthographic' or 'perspective'"); - } - - state->cameras.push_back(camera); + state->cameras.push_back(GLTFCamera::from_dictionary(cameras[i])); } print_verbose("glTF: Total cameras: " + itos(state->cameras.size())); @@ -5148,45 +5054,7 @@ Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex print_verbose("glTF: Creating light for: " + gltf_node->get_name()); Ref<GLTFLight> l = state->lights[gltf_node->light]; - - float intensity = l->intensity; - if (intensity > 10) { - // GLTF spec has the default around 1, but Blender defaults lights to 100. - // The only sane way to handle this is to check where it came from and - // handle it accordingly. If it's over 10, it probably came from Blender. - intensity /= 100; - } - - if (l->light_type == "directional") { - DirectionalLight3D *light = memnew(DirectionalLight3D); - light->set_param(Light3D::PARAM_ENERGY, intensity); - light->set_color(l->color); - return light; - } - - const float range = CLAMP(l->range, 0, 4096); - if (l->light_type == "point") { - OmniLight3D *light = memnew(OmniLight3D); - light->set_param(OmniLight3D::PARAM_ENERGY, intensity); - light->set_param(OmniLight3D::PARAM_RANGE, range); - light->set_color(l->color); - return light; - } - if (l->light_type == "spot") { - SpotLight3D *light = memnew(SpotLight3D); - light->set_param(SpotLight3D::PARAM_ENERGY, intensity); - light->set_param(SpotLight3D::PARAM_RANGE, range); - light->set_param(SpotLight3D::PARAM_SPOT_ANGLE, Math::rad_to_deg(l->outer_cone_angle)); - light->set_color(l->color); - - // Line of best fit derived from guessing, see https://www.desmos.com/calculator/biiflubp8b - // The points in desmos are not exact, except for (1, infinity). - float angle_ratio = l->inner_cone_angle / l->outer_cone_angle; - float angle_attenuation = 0.2 / (1 - angle_ratio) - 0.1; - light->set_param(SpotLight3D::PARAM_SPOT_ATTENUATION, angle_attenuation); - return light; - } - return memnew(Node3D); + return l->to_node(); } Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index) { @@ -5194,32 +5062,16 @@ Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeInd ERR_FAIL_INDEX_V(gltf_node->camera, state->cameras.size(), nullptr); - Camera3D *camera = memnew(Camera3D); print_verbose("glTF: Creating camera for: " + gltf_node->get_name()); Ref<GLTFCamera> c = state->cameras[gltf_node->camera]; - camera->set_projection(c->get_perspective() ? Camera3D::PROJECTION_PERSPECTIVE : Camera3D::PROJECTION_ORTHOGONAL); - // GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees. - camera->set_fov(Math::rad_to_deg(c->get_fov())); - // GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters. - camera->set_size(c->get_size_mag() * 2.0f); - camera->set_near(c->get_depth_near()); - camera->set_far(c->get_depth_far()); - return camera; + return c->to_node(); } GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_camera) { print_verbose("glTF: Converting camera: " + p_camera->get_name()); - Ref<GLTFCamera> c; - c.instantiate(); - c->set_perspective(p_camera->get_projection() == Camera3D::ProjectionType::PROJECTION_PERSPECTIVE); - // GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees. - c->set_fov(Math::deg_to_rad(p_camera->get_fov())); - // GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters. - c->set_size_mag(p_camera->get_size() * 0.5f); - c->set_depth_far(p_camera->get_far()); - c->set_depth_near(p_camera->get_near()); + Ref<GLTFCamera> c = GLTFCamera::from_node(p_camera); GLTFCameraIndex camera_index = state->cameras.size(); state->cameras.push_back(c); return camera_index; @@ -5228,31 +5080,7 @@ GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_light) { print_verbose("glTF: Converting light: " + p_light->get_name()); - Ref<GLTFLight> l; - l.instantiate(); - l->color = p_light->get_color(); - if (cast_to<DirectionalLight3D>(p_light)) { - l->light_type = "directional"; - DirectionalLight3D *light = cast_to<DirectionalLight3D>(p_light); - l->intensity = light->get_param(DirectionalLight3D::PARAM_ENERGY); - l->range = FLT_MAX; // Range for directional lights is infinite in Godot. - } else if (cast_to<OmniLight3D>(p_light)) { - l->light_type = "point"; - OmniLight3D *light = cast_to<OmniLight3D>(p_light); - l->range = light->get_param(OmniLight3D::PARAM_RANGE); - l->intensity = light->get_param(OmniLight3D::PARAM_ENERGY); - } else if (cast_to<SpotLight3D>(p_light)) { - l->light_type = "spot"; - SpotLight3D *light = cast_to<SpotLight3D>(p_light); - l->range = light->get_param(SpotLight3D::PARAM_RANGE); - l->intensity = light->get_param(SpotLight3D::PARAM_ENERGY); - l->outer_cone_angle = Math::deg_to_rad(light->get_param(SpotLight3D::PARAM_SPOT_ANGLE)); - - // This equation is the inverse of the import equation (which has a desmos link). - float angle_ratio = 1 - (0.2 / (0.1 + light->get_param(SpotLight3D::PARAM_SPOT_ATTENUATION))); - angle_ratio = MAX(0, angle_ratio); - l->inner_cone_angle = l->outer_cone_angle * angle_ratio; - } + Ref<GLTFLight> l = GLTFLight::from_node(p_light); GLTFLightIndex light_index = state->lights.size(); state->lights.push_back(l); diff --git a/modules/gltf/structures/gltf_camera.cpp b/modules/gltf/structures/gltf_camera.cpp index c492913ea7..5069f39c4b 100644 --- a/modules/gltf/structures/gltf_camera.cpp +++ b/modules/gltf/structures/gltf_camera.cpp @@ -31,6 +31,12 @@ #include "gltf_camera.h" void GLTFCamera::_bind_methods() { + ClassDB::bind_static_method("GLTFCamera", D_METHOD("from_node", "camera_node"), &GLTFCamera::from_node); + ClassDB::bind_method(D_METHOD("to_node"), &GLTFCamera::to_node); + + ClassDB::bind_static_method("GLTFCamera", D_METHOD("from_dictionary", "dictionary"), &GLTFCamera::from_dictionary); + ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFCamera::to_dictionary); + ClassDB::bind_method(D_METHOD("get_perspective"), &GLTFCamera::get_perspective); ClassDB::bind_method(D_METHOD("set_perspective", "perspective"), &GLTFCamera::set_perspective); ClassDB::bind_method(D_METHOD("get_fov"), &GLTFCamera::get_fov); @@ -48,3 +54,78 @@ void GLTFCamera::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_far"), "set_depth_far", "get_depth_far"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_near"), "set_depth_near", "get_depth_near"); } + +Ref<GLTFCamera> GLTFCamera::from_node(const Camera3D *p_camera) { + Ref<GLTFCamera> c; + c.instantiate(); + c->set_perspective(p_camera->get_projection() == Camera3D::ProjectionType::PROJECTION_PERSPECTIVE); + // GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees. + c->set_fov(Math::deg_to_rad(p_camera->get_fov())); + // GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters. + c->set_size_mag(p_camera->get_size() * 0.5f); + c->set_depth_far(p_camera->get_far()); + c->set_depth_near(p_camera->get_near()); + return c; +} + +Camera3D *GLTFCamera::to_node() const { + Camera3D *camera = memnew(Camera3D); + camera->set_projection(perspective ? Camera3D::PROJECTION_PERSPECTIVE : Camera3D::PROJECTION_ORTHOGONAL); + // GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees. + camera->set_fov(Math::rad_to_deg(fov)); + // GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters. + camera->set_size(size_mag * 2.0f); + camera->set_near(depth_near); + camera->set_far(depth_far); + return camera; +} + +Ref<GLTFCamera> GLTFCamera::from_dictionary(const Dictionary p_dictionary) { + ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFCamera>(), "Failed to parse GLTF camera, missing required field 'type'."); + Ref<GLTFCamera> camera; + camera.instantiate(); + const String &type = p_dictionary["type"]; + if (type == "perspective") { + camera->set_perspective(true); + if (p_dictionary.has("perspective")) { + const Dictionary &persp = p_dictionary["perspective"]; + camera->set_fov(persp["yfov"]); + if (persp.has("zfar")) { + camera->set_depth_far(persp["zfar"]); + } + camera->set_depth_near(persp["znear"]); + } + } else if (type == "orthographic") { + camera->set_perspective(false); + if (p_dictionary.has("orthographic")) { + const Dictionary &ortho = p_dictionary["orthographic"]; + camera->set_size_mag(ortho["ymag"]); + camera->set_depth_far(ortho["zfar"]); + camera->set_depth_near(ortho["znear"]); + } + } else { + ERR_PRINT("Error parsing GLTF camera: Camera type '" + type + "' is unknown, should be perspective or orthographic."); + } + return camera; +} + +Dictionary GLTFCamera::to_dictionary() const { + Dictionary d; + if (perspective) { + Dictionary persp; + persp["yfov"] = fov; + persp["zfar"] = depth_far; + persp["znear"] = depth_near; + d["perspective"] = persp; + d["type"] = "perspective"; + } else { + Dictionary ortho; + ortho["ymag"] = size_mag; + ortho["xmag"] = size_mag; + ortho["zfar"] = depth_far; + ortho["znear"] = depth_near; + d["orthographic"] = ortho; + d["type"] = "orthographic"; + } + return d; +} diff --git a/modules/gltf/structures/gltf_camera.h b/modules/gltf/structures/gltf_camera.h index 8e528c063f..50ae10e17a 100644 --- a/modules/gltf/structures/gltf_camera.h +++ b/modules/gltf/structures/gltf_camera.h @@ -63,6 +63,12 @@ public: void set_depth_far(real_t p_val) { depth_far = p_val; } real_t get_depth_near() const { return depth_near; } void set_depth_near(real_t p_val) { depth_near = p_val; } + + static Ref<GLTFCamera> from_node(const Camera3D *p_light); + Camera3D *to_node() const; + + static Ref<GLTFCamera> from_dictionary(const Dictionary p_dictionary); + Dictionary to_dictionary() const; }; #endif // GLTF_CAMERA_H diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 8b135051c5..2e59987fe6 100644 --- a/modules/mono/csharp_script.cpp +++ b/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); diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs index 54da6218f3..7ec3f88e5d 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs @@ -27,7 +27,8 @@ namespace GodotPlugins.Game internal static partial class Main { [UnmanagedCallersOnly(EntryPoint = ""godotsharp_game_main_init"")] - private static godot_bool InitializeFromGameProject(IntPtr godotDllHandle, IntPtr outManagedCallbacks) + private static godot_bool InitializeFromGameProject(IntPtr godotDllHandle, IntPtr outManagedCallbacks, + IntPtr unmanagedCallbacks, int unmanagedCallbacksSize) { try { @@ -37,6 +38,8 @@ namespace GodotPlugins.Game NativeLibrary.SetDllImportResolver(coreApiAssembly, dllImportResolver); + NativeFuncs.Initialize(unmanagedCallbacks, unmanagedCallbacksSize); + ManagedCallbacks.Create(outManagedCallbacks); ScriptManagerBridge.LookupScriptsInAssembly(typeof(GodotPlugins.Game.Main).Assembly); diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs index 655be0ab5e..d0cd529d1f 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs @@ -176,8 +176,9 @@ namespace GodotTools.Build arguments.Add("--no-restore"); // Incremental or rebuild - if (buildInfo.Rebuild) - arguments.Add("--no-incremental"); + // TODO: Not supported in `dotnet publish` (https://github.com/dotnet/sdk/issues/11099) + // if (buildInfo.Rebuild) + // arguments.Add("--no-incremental"); // Configuration arguments.Add("-c"); diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index 951bff7e7a..851a8b3689 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -112,7 +112,7 @@ namespace GodotTools.Export string buildConfig = isDebug ? "ExportDebug" : "ExportRelease"; // TODO: This works for now, as we only implemented support for x86 family desktop so far, but it needs to be fixed - string arch = features.Contains("64") ? "x86_64" : "x86"; + string arch = features.Contains("x86_64") ? "x86_64" : "x86"; string ridOS = DetermineRuntimeIdentifierOS(platform); string ridArch = DetermineRuntimeIdentifierArch(arch); diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs index 6290b2c56f..c16f803226 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs @@ -70,9 +70,7 @@ namespace GodotTools.Utils { ["Windows"] = Platforms.Windows, ["macOS"] = Platforms.MacOS, - ["LinuxBSD"] = Platforms.LinuxBSD, - // "X11" for compatibility, temporarily, while we are on an outdated branch - ["X11"] = Platforms.LinuxBSD, + ["Linux"] = Platforms.LinuxBSD, ["UWP"] = Platforms.UWP, ["Haiku"] = Platforms.Haiku, ["Android"] = Platforms.Android, diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index d70a1e6c88..0e496454a1 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/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."); } } diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp index 36c46627e2..40296eef10 100644 --- a/modules/mono/editor/code_completion.cpp +++ b/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(); diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index 1ef78c3ac2..6f42ad6916 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/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)); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs index 94dda5a74b..e84bba1179 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs @@ -436,6 +436,15 @@ namespace Godot.NativeInterop public static partial void godotsharp_string_simplify_path(in godot_string p_self, out godot_string r_simplified_path); + public static partial void godotsharp_string_to_camel_case(in godot_string p_self, + out godot_string r_camel_case); + + public static partial void godotsharp_string_to_pascal_case(in godot_string p_self, + out godot_string r_pascal_case); + + public static partial void godotsharp_string_to_snake_case(in godot_string p_self, + out godot_string r_snake_case); + // NodePath public static partial void godotsharp_node_path_get_as_property_path(in godot_node_path p_self, diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index f0bc5949df..44f951e314 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -287,6 +287,45 @@ namespace Godot return cap; } + /// <summary> + /// Returns the string converted to <c>camelCase</c>. + /// </summary> + /// <param name="instance">The string to convert.</param> + /// <returns>The converted string.</returns> + public static string ToCamelCase(this string instance) + { + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_to_camel_case(instanceStr, out godot_string camelCase); + using (camelCase) + return Marshaling.ConvertStringToManaged(camelCase); + } + + /// <summary> + /// Returns the string converted to <c>PascalCase</c>. + /// </summary> + /// <param name="instance">The string to convert.</param> + /// <returns>The converted string.</returns> + public static string ToPascalCase(this string instance) + { + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_to_pascal_case(instanceStr, out godot_string pascalCase); + using (pascalCase) + return Marshaling.ConvertStringToManaged(pascalCase); + } + + /// <summary> + /// Returns the string converted to <c>snake_case</c>. + /// </summary> + /// <param name="instance">The string to convert.</param> + /// <returns>The converted string.</returns> + public static string ToSnakeCase(this string instance) + { + using godot_string instanceStr = Marshaling.ConvertStringToNative(instance); + NativeFuncs.godotsharp_string_to_snake_case(instanceStr, out godot_string snakeCase); + using (snakeCase) + return Marshaling.ConvertStringToManaged(snakeCase); + } + private static string CamelcaseToUnderscore(this string instance, bool lowerCase) { string newString = string.Empty; diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp index 0d68cb54b9..529bda4c38 100644 --- a/modules/mono/glue/runtime_interop.cpp +++ b/modules/mono/glue/runtime_interop.cpp @@ -1096,6 +1096,18 @@ void godotsharp_string_simplify_path(const String *p_self, String *r_simplified_ memnew_placement(r_simplified_path, String(p_self->simplify_path())); } +void godotsharp_string_to_camel_case(const String *p_self, String *r_camel_case) { + memnew_placement(r_camel_case, String(p_self->to_camel_case())); +} + +void godotsharp_string_to_pascal_case(const String *p_self, String *r_pascal_case) { + memnew_placement(r_pascal_case, String(p_self->to_pascal_case())); +} + +void godotsharp_string_to_snake_case(const String *p_self, String *r_snake_case) { + memnew_placement(r_snake_case, String(p_self->to_snake_case())); +} + void godotsharp_node_path_get_as_property_path(const NodePath *p_ptr, NodePath *r_dest) { memnew_placement(r_dest, NodePath(p_ptr->get_as_property_path())); } @@ -1471,6 +1483,9 @@ static const void *unmanaged_callbacks[]{ (void *)godotsharp_string_sha256_buffer, (void *)godotsharp_string_sha256_text, (void *)godotsharp_string_simplify_path, + (void *)godotsharp_string_to_camel_case, + (void *)godotsharp_string_to_pascal_case, + (void *)godotsharp_string_to_snake_case, (void *)godotsharp_node_path_get_as_property_path, (void *)godotsharp_node_path_get_concatenated_names, (void *)godotsharp_node_path_get_concatenated_subnames, diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 12960fb938..c7e47d2718 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/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 diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 0532cc915b..e698e92d7a 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -103,12 +103,12 @@ const char_t *get_data(const HostFxrCharString &p_char_str) { } #ifdef TOOLS_ENABLED -String find_hostfxr(size_t p_known_buffet_size, get_hostfxr_parameters *p_get_hostfxr_params) { +String find_hostfxr(size_t p_known_buffer_size, get_hostfxr_parameters *p_get_hostfxr_params) { // Pre-allocate a large buffer for the path to hostfxr Vector<char_t> buffer; - buffer.resize(p_known_buffet_size); + buffer.resize(p_known_buffer_size); - int rc = get_hostfxr_path(buffer.ptrw(), &p_known_buffet_size, p_get_hostfxr_params); + int rc = get_hostfxr_path(buffer.ptrw(), &p_known_buffer_size, p_get_hostfxr_params); ERR_FAIL_COND_V_MSG(rc != 0, String(), "get_hostfxr_path failed with code: " + itos(rc)); @@ -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 @@ -270,7 +270,7 @@ load_assembly_and_get_function_pointer_fn initialize_hostfxr_self_contained( int i = 1; for (const String &E : cmdline_args) { HostFxrCharString &stored = argv_store.push_back(str_to_hostfxr(E))->get(); - argv.write[i] = stored.ptr(); + argv.write[i] = get_data(stored); i++; } @@ -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)); @@ -356,7 +356,7 @@ godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime print_verbose(".NET: hostfxr initialized"); int rc = load_assembly_and_get_function_pointer(get_data(assembly_path), - str_to_hostfxr("GodotPlugins.Game.Main, " + assembly_name), + get_data(str_to_hostfxr("GodotPlugins.Game.Main, " + assembly_name)), HOSTFXR_STR("InitializeFromGameProject"), UNMANAGEDCALLERSONLY_METHOD, nullptr, @@ -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)) { diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp index 19ad59a1bc..269e41e2f4 100644 --- a/modules/mono/utils/path_utils.cpp +++ b/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)); } } diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 428135de56..373c6e37f1 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/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); diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 685b1f01af..0f8ef3f7d6 100644 --- a/platform/android/export/export_plugin.cpp +++ b/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) \ { \ diff --git a/platform/android/export/godot_plugin_config.cpp b/platform/android/export/godot_plugin_config.cpp index 3daf6e44cd..21580ae907 100644 --- a/platform/android/export/godot_plugin_config.cpp +++ b/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); } } diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index f94614c741..142dc54c45 100644 --- a/platform/android/os_android.cpp +++ b/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) { diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp index f49cf7a88d..7aacb2de85 100644 --- a/platform/ios/export/export_plugin.cpp +++ b/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("splash@2x.png"); + String image_path = p_dest_dir.path_join("splash@2x.png"); 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("splash@3x.png"); + image_path = p_dest_dir.path_join("splash@3x.png"); 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("splash@2x.png"); - const String splash_png_path_3x = p_dest_dir.plus_file("splash@3x.png"); + const String splash_png_path_2x = p_dest_dir.path_join("splash@2x.png"); + const String splash_png_path_3x = p_dest_dir.path_join("splash@3x.png"); 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); } diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h index abda8e218a..639f2416a5 100644 --- a/platform/ios/export/export_plugin.h +++ b/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 { diff --git a/platform/ios/export/godot_plugin_config.cpp b/platform/ios/export/godot_plugin_config.cpp index 24a95a11a4..42797d449b 100644 --- a/platform/ios/export/godot_plugin_config.cpp +++ b/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)); diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index cacb9d2a27..017fc3e3a2 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -1869,6 +1869,14 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const { return retval; } +void DisplayServerX11::_validate_fullscreen_on_map(WindowID p_window) { + const WindowData &wd = windows[p_window]; + if (wd.fullscreen && !_window_fullscreen_check(p_window)) { + // Unmapped fullscreen attempt didn't take effect, redo... + _set_wm_fullscreen(p_window, true); + } +} + bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const { _THREAD_SAFE_METHOD_ return _window_maximize_check(p_window, "_NET_WM_ALLOWED_ACTIONS"); @@ -3650,6 +3658,9 @@ void DisplayServerX11::process_events() { const WindowData &wd = windows[window_id]; + // Have we failed to set fullscreen while the window was unmapped? + _validate_fullscreen_on_map(window_id); + XWindowAttributes xwa; XSync(x11_display, False); XGetWindowAttributes(x11_display, wd.x11_window, &xwa); @@ -4990,6 +5001,9 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode XNextEvent(x11_display, &xevent); if (xevent.type == ConfigureNotify) { _window_changed(&xevent); + } else if (xevent.type == MapNotify) { + // Have we failed to set fullscreen while the window was unmapped? + _validate_fullscreen_on_map(main_window); } } diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 0174cfb881..6b9f57d78f 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -268,6 +268,7 @@ class DisplayServerX11 : public DisplayServer { void _update_real_mouse_position(const WindowData &wd); bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const; bool _window_fullscreen_check(WindowID p_window) const; + void _validate_fullscreen_on_map(WindowID p_window); void _update_size_hints(WindowID p_window); void _set_wm_fullscreen(WindowID p_window, bool p_enabled); void _set_wm_maximized(WindowID p_window, bool p_enabled); diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index a74ca155a4..61faf3061c 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/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(); } diff --git a/platform/macos/dir_access_macos.mm b/platform/macos/dir_access_macos.mm index 94d937a7dc..3373cada1f 100644 --- a/platform/macos/dir_access_macos.mm +++ b/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]) { diff --git a/platform/macos/export/codesign.cpp b/platform/macos/export/codesign.cpp index fd044c00cc..c2bdf555d0 100644 --- a/platform/macos/export/codesign.cpp +++ b/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; diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp index 4b453add5a..50104aced5 100644 --- a/platform/macos/export/export_plugin.cpp +++ b/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; diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm index 47b53bba69..35c4e4b03d 100644 --- a/platform/macos/os_macos.mm +++ b/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(); } diff --git a/platform/uwp/export/app_packager.cpp b/platform/uwp/export/app_packager.cpp index 09717b9d69..87224d38b8 100644 --- a/platform/uwp/export/app_packager.cpp +++ b/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); { diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h index 71d0479543..b0427d1a65 100644 --- a/platform/uwp/export/export_plugin.h +++ b/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); diff --git a/platform/web/api/web_tools_editor_plugin.cpp b/platform/web/api/web_tools_editor_plugin.cpp index 6f684a73c2..46fcb2d452 100644 --- a/platform/web/api/web_tools_editor_plugin.cpp +++ b/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()) { diff --git a/platform/web/export/editor_http_server.h b/platform/web/export/editor_http_server.h index 1e50e60a28..38b9a66d7e 100644 --- a/platform/web/export/editor_http_server.h +++ b/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"; diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp index 996d1db2e7..2cd8ec88ef 100644 --- a/platform/web/export/export_plugin.cpp +++ b/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. diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 0e4d5f79b9..403d53ae53 100644 --- a/platform/windows/os_windows.cpp +++ b/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 { diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index 85de1fedee..a79c81e8bd 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -612,6 +612,10 @@ void CollisionObject2D::_bind_methods() { ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject2D::shape_find_owner); GDVIRTUAL_BIND(_input_event, "viewport", "event", "shape_idx"); + GDVIRTUAL_BIND(_mouse_enter); + GDVIRTUAL_BIND(_mouse_exit); + GDVIRTUAL_BIND(_mouse_shape_enter, "shape_idx"); + GDVIRTUAL_BIND(_mouse_shape_exit, "shape_idx"); ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx"))); ADD_SIGNAL(MethodInfo("mouse_entered")); diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index af216edc98..48ea59e040 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -103,6 +103,10 @@ protected: void set_body_mode(PhysicsServer2D::BodyMode p_mode); GDVIRTUAL3(_input_event, Viewport *, Ref<InputEvent>, int) + GDVIRTUAL0(_mouse_enter) + GDVIRTUAL0(_mouse_exit) + GDVIRTUAL1(_mouse_shape_enter, int) + GDVIRTUAL1(_mouse_shape_exit, int) public: void set_collision_layer(uint32_t p_layer); uint32_t get_collision_layer() const; diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index a1ed2de73a..cb0349fefd 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -30,6 +30,7 @@ #include "gpu_particles_2d.h" +#include "core/core_string_names.h" #include "scene/resources/particle_process_material.h" #ifdef TOOLS_ENABLED @@ -331,7 +332,15 @@ Rect2 GPUParticles2D::capture_rect() const { } void GPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) { + if (texture.is_valid()) { + texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GPUParticles2D::_texture_changed)); + } + texture = p_texture; + + if (texture.is_valid()) { + texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GPUParticles2D::_texture_changed)); + } _update_collision_size(); queue_redraw(); } @@ -363,6 +372,14 @@ void GPUParticles2D::_attach_sub_emitter() { } } +void GPUParticles2D::_texture_changed() { + // Changes to the texture need to trigger an update to make + // the editor redraw the sprite with the updated texture. + if (texture.is_valid()) { + update(); + } +} + void GPUParticles2D::set_sub_emitter(const NodePath &p_path) { if (is_inside_tree()) { RS::get_singleton()->particles_set_subemitter(particles, RID()); @@ -480,12 +497,21 @@ void GPUParticles2D::_notification(int p_what) { Vector2(-size.x / 2.0, size.y / 2.0) }; - Vector<Vector2> uvs = { - Vector2(0, 0), - Vector2(1, 0), - Vector2(1, 1), - Vector2(0, 1) - }; + Vector<Vector2> uvs; + AtlasTexture *atlas_texure = Object::cast_to<AtlasTexture>(*texture); + if (atlas_texure && atlas_texure->get_atlas().is_valid()) { + Rect2 region_rect = atlas_texure->get_region(); + Size2 atlas_size = atlas_texure->get_atlas()->get_size(); + uvs.push_back(Vector2(region_rect.position.x / atlas_size.x, region_rect.position.y / atlas_size.y)); + uvs.push_back(Vector2((region_rect.position.x + region_rect.size.x) / atlas_size.x, region_rect.position.y / atlas_size.y)); + uvs.push_back(Vector2((region_rect.position.x + region_rect.size.x) / atlas_size.x, (region_rect.position.y + region_rect.size.y) / atlas_size.y)); + uvs.push_back(Vector2(region_rect.position.x / atlas_size.x, (region_rect.position.y + region_rect.size.y) / atlas_size.y)); + } else { + uvs.push_back(Vector2(0, 0)); + uvs.push_back(Vector2(1, 0)); + uvs.push_back(Vector2(1, 1)); + uvs.push_back(Vector2(0, 1)); + } Vector<int> indices = { 0, 1, 2, 0, 2, 3 }; diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 7eece32898..10ae91775f 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -82,6 +82,8 @@ private: void _attach_sub_emitter(); + void _texture_changed(); + protected: static void _bind_methods(); void _validate_property(PropertyInfo &p_property) const; diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 48eb2a66b1..f5e3e8b015 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -469,6 +469,8 @@ void CollisionObject3D::_bind_methods() { ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject3D::shape_find_owner); GDVIRTUAL_BIND(_input_event, "camera", "event", "position", "normal", "shape_idx"); + GDVIRTUAL_BIND(_mouse_enter); + GDVIRTUAL_BIND(_mouse_exit); ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx"))); ADD_SIGNAL(MethodInfo("mouse_entered")); diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index 51c31da79f..c638be9d90 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -113,6 +113,8 @@ protected: bool is_only_update_transform_changes_enabled() const; GDVIRTUAL5(_input_event, Camera3D *, Ref<InputEvent>, Vector3, Vector3, int) + GDVIRTUAL0(_mouse_enter) + GDVIRTUAL0(_mouse_exit) public: void set_collision_layer(uint32_t p_layer); uint32_t get_collision_layer() const; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 57655afb4c..2a56d6d222 100644 --- a/scene/gui/file_dialog.cpp +++ b/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) { diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 466ad62373..3c6be008f2 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1013,7 +1013,7 @@ Ref<Texture2D> TreeItem::get_button(int p_column, int p_idx) const { return cells[p_column].buttons[p_idx].texture; } -String TreeItem::get_button_tooltip(int p_column, int p_idx) const { +String TreeItem::get_button_tooltip_text(int p_column, int p_idx) const { ERR_FAIL_INDEX_V(p_column, cells.size(), String()); ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), String()); return cells[p_column].buttons[p_idx].tooltip; @@ -1160,12 +1160,12 @@ int TreeItem::get_custom_font_size(int p_column) const { return cells[p_column].custom_font_size; } -void TreeItem::set_tooltip(int p_column, const String &p_tooltip) { +void TreeItem::set_tooltip_text(int p_column, const String &p_tooltip) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].tooltip = p_tooltip; } -String TreeItem::get_tooltip(int p_column) const { +String TreeItem::get_tooltip_text(int p_column) const { ERR_FAIL_INDEX_V(p_column, cells.size(), ""); return cells[p_column].tooltip; } @@ -1441,9 +1441,9 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_as_button", "column", "enable"), &TreeItem::set_custom_as_button); ClassDB::bind_method(D_METHOD("is_custom_set_as_button", "column"), &TreeItem::is_custom_set_as_button); - ClassDB::bind_method(D_METHOD("add_button", "column", "button", "id", "disabled", "tooltip"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL("")); + ClassDB::bind_method(D_METHOD("add_button", "column", "button", "id", "disabled", "tooltip_text"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL("")); ClassDB::bind_method(D_METHOD("get_button_count", "column"), &TreeItem::get_button_count); - ClassDB::bind_method(D_METHOD("get_button_tooltip", "column", "button_idx"), &TreeItem::get_button_tooltip); + ClassDB::bind_method(D_METHOD("get_button_tooltip_text", "column", "button_idx"), &TreeItem::get_button_tooltip_text); ClassDB::bind_method(D_METHOD("get_button_id", "column", "button_idx"), &TreeItem::get_button_id); ClassDB::bind_method(D_METHOD("get_button_by_id", "column", "id"), &TreeItem::get_button_by_id); ClassDB::bind_method(D_METHOD("get_button", "column", "button_idx"), &TreeItem::get_button); @@ -1452,8 +1452,8 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled); ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled); - ClassDB::bind_method(D_METHOD("set_tooltip", "column", "tooltip"), &TreeItem::set_tooltip); - ClassDB::bind_method(D_METHOD("get_tooltip", "column"), &TreeItem::get_tooltip); + ClassDB::bind_method(D_METHOD("set_tooltip_text", "column", "tooltip"), &TreeItem::set_tooltip_text); + ClassDB::bind_method(D_METHOD("get_tooltip_text", "column"), &TreeItem::get_tooltip_text); ClassDB::bind_method(D_METHOD("set_text_alignment", "column", "text_alignment"), &TreeItem::set_text_alignment); ClassDB::bind_method(D_METHOD("get_text_alignment", "column"), &TreeItem::get_text_alignment); @@ -5005,10 +5005,10 @@ String Tree::get_tooltip(const Point2 &p_pos) const { col_width -= size.width; } String ret; - if (it->get_tooltip(col) == "") { + if (it->get_tooltip_text(col) == "") { ret = it->get_text(col); } else { - ret = it->get_tooltip(col); + ret = it->get_tooltip_text(col); } return ret; } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 7f9c00b1b9..8eabdd60a1 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -245,7 +245,7 @@ public: void add_button(int p_column, const Ref<Texture2D> &p_button, int p_id = -1, bool p_disabled = false, const String &p_tooltip = ""); int get_button_count(int p_column) const; - String get_button_tooltip(int p_column, int p_idx) const; + String get_button_tooltip_text(int p_column, int p_idx) const; Ref<Texture2D> get_button(int p_column, int p_idx) const; int get_button_id(int p_column, int p_idx) const; void erase_button(int p_column, int p_idx); @@ -308,8 +308,8 @@ public: void set_custom_as_button(int p_column, bool p_button); bool is_custom_set_as_button(int p_column) const; - void set_tooltip(int p_column, const String &p_tooltip); - String get_tooltip(int p_column) const; + void set_tooltip_text(int p_column, const String &p_tooltip); + String get_tooltip_text(int p_column) const; void set_text_alignment(int p_column, HorizontalAlignment p_alignment); HorizontalAlignment get_text_alignment(int p_column) const; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index cc3d14e5be..289e963077 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -951,14 +951,11 @@ String Node::validate_child_name(Node *p_child) { String Node::adjust_name_casing(const String &p_name) { switch (GLOBAL_GET("editor/node_naming/name_casing").operator int()) { case NAME_CASING_PASCAL_CASE: - return p_name.capitalize().replace(" ", ""); - case NAME_CASING_CAMEL_CASE: { - String name = p_name.capitalize().replace(" ", ""); - name[0] = name.to_lower()[0]; - return name; - } + return p_name.to_pascal_case(); + case NAME_CASING_CAMEL_CASE: + return p_name.to_camel_case(); case NAME_CASING_SNAKE_CASE: - return p_name.capitalize().replace(" ", "_").to_lower(); + return p_name.to_snake_case(); } return p_name; } @@ -2926,7 +2923,7 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_PROCESS); BIND_CONSTANT(NOTIFICATION_PARENTED); BIND_CONSTANT(NOTIFICATION_UNPARENTED); - BIND_CONSTANT(NOTIFICATION_INSTANCED); + BIND_CONSTANT(NOTIFICATION_SCENE_INSTANTIATED); BIND_CONSTANT(NOTIFICATION_DRAG_BEGIN); BIND_CONSTANT(NOTIFICATION_DRAG_END); BIND_CONSTANT(NOTIFICATION_PATH_RENAMED); diff --git a/scene/main/node.h b/scene/main/node.h index 703c580d3f..ae6a997579 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -259,7 +259,7 @@ public: NOTIFICATION_PROCESS = 17, NOTIFICATION_PARENTED = 18, NOTIFICATION_UNPARENTED = 19, - NOTIFICATION_INSTANCED = 20, + NOTIFICATION_SCENE_INSTANTIATED = 20, NOTIFICATION_DRAG_BEGIN = 21, NOTIFICATION_DRAG_END = 22, NOTIFICATION_PATH_RENAMED = 23, diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 109799e23a..e91e2f5c92 100644 --- a/scene/main/scene_tree.cpp +++ b/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(); diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 8ec5678f0a..189d8d5502 100644 --- a/scene/resources/font.cpp +++ b/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(); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index bd0e470112..32ddef1693 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -2971,6 +2971,8 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_transparency(TRANSPARENCY_DISABLED); set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF); + // Alpha scissor threshold of 0.5 matches the glTF specification and Label3D default. + // <https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_material_alphacutoff> set_alpha_scissor_threshold(0.5); set_alpha_hash_scale(1.0); set_alpha_antialiasing_edge(0.3); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 33334801c3..e0bedad595 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -1755,7 +1755,7 @@ Node *PackedScene::instantiate(GenEditState p_edit_state) const { s->set_scene_file_path(get_path()); } - s->notification(Node::NOTIFICATION_INSTANCED); + s->notification(Node::NOTIFICATION_SCENE_INSTANTIATED); return s; } diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 2b1d91e4ef..0d798d2e27 100644 --- a/scene/resources/resource_format_text.cpp +++ b/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; } diff --git a/servers/movie_writer/movie_writer.cpp b/servers/movie_writer/movie_writer.cpp index 40b2b2539e..2164dca29e 100644 --- a/servers/movie_writer/movie_writer.cpp +++ b/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)); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 967b725b9e..e7abcf5674 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/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) { diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index c9b6d09d4c..0f2dea6fe9 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/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()); diff --git a/tests/core/io/test_config_file.h b/tests/core/io/test_config_file.h index 355aca479e..666719febb 100644 --- a/tests/core/io/test_config_file.h +++ b/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 diff --git a/tests/core/io/test_image.h b/tests/core/io/test_image.h index 36e6b83bfd..38b616cda0 100644 --- a/tests/core/io/test_image.h +++ b/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; diff --git a/tests/core/io/test_pck_packer.h b/tests/core/io/test_pck_packer.h index d21fbdaf50..8d0e5c402a 100644 --- a/tests/core/io/test_pck_packer.h +++ b/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, diff --git a/tests/core/io/test_resource.h b/tests/core/io/test_resource.h index c880ca7d2a..2457e06ade 100644 --- a/tests/core/io/test_resource.h +++ b/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); diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index 62d2051eee..d97da05c04 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -466,11 +466,6 @@ TEST_CASE("[String] String to float") { } } -TEST_CASE("[String] CamelCase to underscore") { - CHECK(String("TestTestStringGD").camelcase_to_underscore(false) == String("Test_Test_String_GD")); - CHECK(String("TestTestStringGD").camelcase_to_underscore(true) == String("test_test_string_gd")); -} - TEST_CASE("[String] Slicing") { String s = "Mars,Jupiter,Saturn,Uranus"; @@ -1096,8 +1091,36 @@ TEST_CASE("[String] IPVX address to string") { } TEST_CASE("[String] Capitalize against many strings") { - String input = "bytes2var"; - String output = "Bytes 2 Var"; + String input = "2D"; + String output = "2d"; + CHECK(input.capitalize() == output); + + input = "2d"; + output = "2d"; + CHECK(input.capitalize() == output); + + input = "2db"; + output = "2 Db"; + CHECK(input.capitalize() == output); + + input = "HTML5 Html5 html5 html_5"; + output = "Html 5 Html 5 Html 5 Html 5"; + CHECK(input.capitalize() == output); + + input = "Node2D Node2d NODE2D NODE_2D node_2d"; + output = "Node 2d Node 2d Node 2d Node 2d Node 2d"; + CHECK(input.capitalize() == output); + + input = "Node2DPosition"; + output = "Node 2d Position"; + CHECK(input.capitalize() == output); + + input = "Number2Digits"; + output = "Number 2 Digits"; + CHECK(input.capitalize() == output); + + input = "bytes2var"; + output = "Bytes 2 Var"; CHECK(input.capitalize() == output); input = "linear2db"; @@ -1112,10 +1135,6 @@ TEST_CASE("[String] Capitalize against many strings") { output = "Sha 256"; CHECK(input.capitalize() == output); - input = "2db"; - output = "2 Db"; - CHECK(input.capitalize() == output); - input = "PascalCase"; output = "Pascal Case"; CHECK(input.capitalize() == output); @@ -1153,6 +1172,50 @@ TEST_CASE("[String] Capitalize against many strings") { CHECK(input.capitalize() == output); } +struct StringCasesTestCase { + const char *input; + const char *camel_case; + const char *pascal_case; + const char *snake_case; +}; + +TEST_CASE("[String] Checking case conversion methods") { + StringCasesTestCase test_cases[] = { + /* clang-format off */ + { "2D", "2d", "2d", "2d" }, + { "2d", "2d", "2d", "2d" }, + { "2db", "2Db", "2Db", "2_db" }, + { "Vector3", "vector3", "Vector3", "vector_3" }, + { "sha256", "sha256", "Sha256", "sha_256" }, + { "Node2D", "node2d", "Node2d", "node_2d" }, + { "RichTextLabel", "richTextLabel", "RichTextLabel", "rich_text_label" }, + { "HTML5", "html5", "Html5", "html_5" }, + { "Node2DPosition", "node2dPosition", "Node2dPosition", "node_2d_position" }, + { "Number2Digits", "number2Digits", "Number2Digits", "number_2_digits" }, + { "get_property_list", "getPropertyList", "GetPropertyList", "get_property_list" }, + { "get_camera_2d", "getCamera2d", "GetCamera2d", "get_camera_2d" }, + { "_physics_process", "physicsProcess", "PhysicsProcess", "_physics_process" }, + { "bytes2var", "bytes2Var", "Bytes2Var", "bytes_2_var" }, + { "linear2db", "linear2Db", "Linear2Db", "linear_2_db" }, + { "sha256sum", "sha256Sum", "Sha256Sum", "sha_256_sum" }, + { "camelCase", "camelCase", "CamelCase", "camel_case" }, + { "PascalCase", "pascalCase", "PascalCase", "pascal_case" }, + { "snake_case", "snakeCase", "SnakeCase", "snake_case" }, + { "Test TEST test", "testTestTest", "TestTestTest", "test_test_test" }, + { nullptr, nullptr, nullptr, nullptr }, + /* clang-format on */ + }; + + int idx = 0; + while (test_cases[idx].input != nullptr) { + String input = test_cases[idx].input; + CHECK(input.to_camel_case() == test_cases[idx].camel_case); + CHECK(input.to_pascal_case() == test_cases[idx].pascal_case); + CHECK(input.to_snake_case() == test_cases[idx].snake_case); + idx++; + } +} + TEST_CASE("[String] Checking string is empty when it should be") { bool state = true; bool success; @@ -1359,7 +1422,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" }; @@ -1663,7 +1726,7 @@ TEST_CASE("[String] Variant ptr indexed set") { TEST_CASE("[Stress][String] Empty via ' == String()'") { for (int i = 0; i < 100000; ++i) { String str = "Hello World!"; - if (str.is_empty()) { + if (str == String()) { continue; } } diff --git a/tests/scene/test_audio_stream_wav.h b/tests/scene/test_audio_stream_wav.h index 92c524525c..cf369c115b 100644 --- a/tests/scene/test_audio_stream_wav.h +++ b/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; diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp index 11cb6398aa..ce12a30381 100644 --- a/tests/test_utils.cpp +++ b/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() { |