diff options
285 files changed, 3909 insertions, 5414 deletions
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index 1594f5b2d9..7ac364c45f 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -193,14 +193,6 @@ jobs: cp -f extension_api.json godot-cpp/godot-headers/ cp -f core/extension/gdnative_interface.h godot-cpp/godot-headers/godot/ - # Build godot-cpp library - - name: Build godot-cpp library - if: ${{ matrix.godot-cpp-test }} - run: | - cd godot-cpp - scons target=${{ matrix.target }} generate_bindings=yes -j2 - cd .. - # Build godot-cpp test extension - name: Build godot-cpp test extension if: ${{ matrix.godot-cpp-test }} diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 93c1abe7b5..06bfc0c562 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -145,7 +145,7 @@ String ProjectSettings::localize_path(const String &p_path) const { return p_path.simplify_path(); } - DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); String path = p_path.replace("\\", "/").simplify_path(); @@ -537,8 +537,8 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b // Nothing was found, try to find a project file in provided path (`p_path`) // or, if requested (`p_upwards`) in parent directories. - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V_MSG(!d, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_path + "'."); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V_MSG(d.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_path + "'."); d->change_dir(p_path); String current_dir = d->get_current_dir(); @@ -613,17 +613,14 @@ bool ProjectSettings::has_setting(String p_var) const { Error ProjectSettings::_load_settings_binary(const String &p_path) { Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err != OK) { return err; } uint8_t hdr[4]; f->get_buffer(hdr, 4); - if (hdr[0] != 'E' || hdr[1] != 'C' || hdr[2] != 'F' || hdr[3] != 'G') { - memdelete(f); - ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Corrupted header in binary project.binary (not ECFG)."); - } + ERR_FAIL_COND_V_MSG((hdr[0] != 'E' || hdr[1] != 'C' || hdr[2] != 'F' || hdr[3] != 'G'), ERR_FILE_CORRUPT, "Corrupted header in binary project.binary (not ECFG)."); uint32_t count = f->get_32(); @@ -646,16 +643,14 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) { set(key, value); } - f->close(); - memdelete(f); return OK; } Error ProjectSettings::_load_settings_text(const String &p_path) { Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { + if (f.is_null()) { // FIXME: Above 'err' error code is ERR_FILE_CANT_OPEN if the file is missing // This needs to be streamlined if we want decent error reporting return ERR_FILE_NOT_FOUND; @@ -680,25 +675,18 @@ Error ProjectSettings::_load_settings_text(const String &p_path) { err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true); if (err == ERR_FILE_EOF) { - memdelete(f); // 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")); return OK; - } else if (err != OK) { - ERR_PRINT("Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted."); - memdelete(f); - return err; } + ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted."); if (!assign.is_empty()) { if (section.is_empty() && assign == "config_version") { config_version = value; - if (config_version > CONFIG_VERSION) { - memdelete(f); - ERR_FAIL_V_MSG(ERR_FILE_CANT_OPEN, vformat("Can't open project at '%s', its `config_version` (%d) is from a more recent and incompatible version of the engine. Expected config version: %d.", p_path, config_version, CONFIG_VERSION)); - } + ERR_FAIL_COND_V_MSG(config_version > CONFIG_VERSION, ERR_FILE_CANT_OPEN, vformat("Can't open project at '%s', its `config_version` (%d) is from a more recent and incompatible version of the engine. Expected config version: %d.", p_path, config_version, CONFIG_VERSION)); } else { if (section.is_empty()) { set(assign, value); @@ -778,7 +766,7 @@ Error ProjectSettings::save() { Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) { Error err; - FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.binary at " + p_file + "."); uint8_t hdr[4] = { 'E', 'C', 'F', 'G' }; @@ -798,19 +786,13 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str int len; err = encode_variant(p_custom_features, nullptr, len, false); - if (err != OK) { - memdelete(file); - ERR_FAIL_V(err); - } + ERR_FAIL_COND_V(err != OK, err); Vector<uint8_t> buff; buff.resize(len); err = encode_variant(p_custom_features, buff.ptrw(), len, false); - if (err != OK) { - memdelete(file); - ERR_FAIL_V(err); - } + ERR_FAIL_COND_V(err != OK, err); file->store_32(len); file->store_buffer(buff.ptr(), buff.size()); @@ -834,33 +816,24 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str int len; err = encode_variant(value, nullptr, len, true); - if (err != OK) { - memdelete(file); - } ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Error when trying to encode Variant."); Vector<uint8_t> buff; buff.resize(len); err = encode_variant(value, buff.ptrw(), len, true); - if (err != OK) { - memdelete(file); - } ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Error when trying to encode Variant."); file->store_32(len); file->store_buffer(buff.ptr(), buff.size()); } } - file->close(); - memdelete(file); - return OK; } Error ProjectSettings::_save_settings_text(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) { Error err; - FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.godot - " + p_file + "."); @@ -905,9 +878,6 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const Map<Strin } } - file->close(); - memdelete(file); - return OK; } diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 706395afa9..7d8ec6064d 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -1027,10 +1027,10 @@ Error File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const V return err; } - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); + Ref<FileAccessEncrypted> fae; + fae.instantiate(); err = fae->open_and_parse(f, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ); if (err) { - memdelete(fae); close(); return err; } @@ -1044,10 +1044,10 @@ Error File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, co return err; } - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); + Ref<FileAccessEncrypted> fae; + fae.instantiate(); err = fae->open_and_parse_password(f, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ); if (err) { - memdelete(fae); close(); return err; } @@ -1057,14 +1057,13 @@ Error File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, co } Error File::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) { - FileAccessCompressed *fac = memnew(FileAccessCompressed); - + Ref<FileAccessCompressed> fac; + fac.instantiate(); fac->configure("GCPF", (Compression::Mode)p_compress_mode); Error err = fac->_open(p_path, p_mode_flags); if (err) { - memdelete(fac); return err; } @@ -1076,22 +1075,20 @@ Error File::open(const String &p_path, ModeFlags p_mode_flags) { close(); Error err; f = FileAccess::open(p_path, p_mode_flags, &err); - if (f) { + if (f.is_valid()) { f->set_big_endian(big_endian); } return err; } void File::flush() { - ERR_FAIL_COND_MSG(!f, "File must be opened before flushing."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before flushing."); f->flush(); } void File::close() { - if (f) { - memdelete(f); - } - f = nullptr; + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened."); + f = Ref<FileAccess>(); } bool File::is_open() const { @@ -1099,79 +1096,79 @@ bool File::is_open() const { } String File::get_path() const { - ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission."); return f->get_path(); } String File::get_path_absolute() const { - ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission."); return f->get_path_absolute(); } void File::seek(int64_t p_position) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); ERR_FAIL_COND_MSG(p_position < 0, "Seek position must be a positive integer."); f->seek(p_position); } void File::seek_end(int64_t p_position) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->seek_end(p_position); } uint64_t File::get_position() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); return f->get_position(); } uint64_t File::get_length() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); return f->get_length(); } bool File::eof_reached() const { - ERR_FAIL_COND_V_MSG(!f, false, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), false, "File must be opened before use, or is lacking read-write permission."); return f->eof_reached(); } uint8_t File::get_8() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); return f->get_8(); } uint16_t File::get_16() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); return f->get_16(); } uint32_t File::get_32() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); return f->get_32(); } uint64_t File::get_64() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); return f->get_64(); } float File::get_float() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); return f->get_float(); } double File::get_double() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); return f->get_double(); } real_t File::get_real() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission."); return f->get_real(); } Vector<uint8_t> File::get_buffer(int64_t p_length) const { Vector<uint8_t> data; - ERR_FAIL_COND_V_MSG(!f, data, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), data, "File must be opened before use, or is lacking read-write permission."); ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0."); if (p_length == 0) { @@ -1192,11 +1189,11 @@ Vector<uint8_t> File::get_buffer(int64_t p_length) const { } String File::get_as_text() const { - ERR_FAIL_COND_V_MSG(!f, String(), "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission."); String text; uint64_t original_pos = f->get_position(); - f->seek(0); + const_cast<FileAccess *>(*f)->seek(0); String l = get_line(); while (!eof_reached()) { @@ -1205,7 +1202,7 @@ String File::get_as_text() const { } text += l; - f->seek(original_pos); + const_cast<FileAccess *>(*f)->seek(original_pos); return text; } @@ -1219,12 +1216,12 @@ String File::get_sha256(const String &p_path) const { } String File::get_line() const { - ERR_FAIL_COND_V_MSG(!f, String(), "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission."); return f->get_line(); } Vector<String> File::get_csv_line(const String &p_delim) const { - ERR_FAIL_COND_V_MSG(!f, Vector<String>(), "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), Vector<String>(), "File must be opened before use, or is lacking read-write permission."); return f->get_csv_line(p_delim); } @@ -1235,7 +1232,7 @@ Vector<String> File::get_csv_line(const String &p_delim) const { void File::set_big_endian(bool p_big_endian) { big_endian = p_big_endian; - if (f) { + if (f.is_valid()) { f->set_big_endian(p_big_endian); } } @@ -1245,84 +1242,84 @@ bool File::is_big_endian() { } Error File::get_error() const { - if (!f) { + if (f.is_null()) { return ERR_UNCONFIGURED; } return f->get_error(); } void File::store_8(uint8_t p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_8(p_dest); } void File::store_16(uint16_t p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_16(p_dest); } void File::store_32(uint32_t p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_32(p_dest); } void File::store_64(uint64_t p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_64(p_dest); } void File::store_float(float p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_float(p_dest); } void File::store_double(double p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_double(p_dest); } void File::store_real(real_t p_real) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_real(p_real); } void File::store_string(const String &p_string) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_string(p_string); } void File::store_pascal_string(const String &p_string) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_pascal_string(p_string); } String File::get_pascal_string() { - ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission."); return f->get_pascal_string(); } void File::store_line(const String &p_string) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_line(p_string); } void File::store_csv_line(const Vector<String> &p_values, const String &p_delim) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); f->store_csv_line(p_values, p_delim); } void File::store_buffer(const Vector<uint8_t> &p_buffer) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); uint64_t len = p_buffer.size(); if (len == 0) { @@ -1339,7 +1336,7 @@ bool File::file_exists(const String &p_name) { } void File::store_var(const Variant &p_var, bool p_full_objects) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission."); int len; Error err = encode_variant(p_var, nullptr, len, p_full_objects); ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant."); @@ -1356,7 +1353,7 @@ void File::store_var(const Variant &p_var, bool p_full_objects) { } Variant File::get_var(bool p_allow_objects) const { - ERR_FAIL_COND_V_MSG(!f, Variant(), "File must be opened before use, or is lacking read-write permission."); + ERR_FAIL_COND_V_MSG(f.is_null(), Variant(), "File must be opened before use, or is lacking read-write permission."); uint32_t len = get_32(); Vector<uint8_t> buff = get_buffer(len); ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant()); @@ -1440,24 +1437,14 @@ void File::_bind_methods() { BIND_ENUM_CONSTANT(COMPRESSION_GZIP); } -File::~File() { - if (f) { - memdelete(f); - } -} - ////// Directory ////// Error Directory::open(const String &p_path) { Error err; - DirAccess *alt = DirAccess::open(p_path, &err); - - if (!alt) { + Ref<DirAccess> alt = DirAccess::open(p_path, &err); + if (alt.is_null()) { return err; } - if (d) { - memdelete(d); - } d = alt; dir_open = true; @@ -1465,7 +1452,7 @@ Error Directory::open(const String &p_path) { } bool Directory::is_open() const { - return d && dir_open; + return d.is_valid() && dir_open; } Error Directory::list_dir_begin() { @@ -1550,7 +1537,7 @@ int Directory::get_current_drive() { } Error Directory::change_dir(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly."); + ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly."); Error err = d->change_dir(p_dir); if (err != OK) { @@ -1567,25 +1554,25 @@ String Directory::get_current_dir() { } Error Directory::make_dir(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly."); + ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly."); if (!p_dir.is_relative_path()) { - DirAccessRef da = DirAccess::create_for_path(p_dir); + Ref<DirAccess> da = DirAccess::create_for_path(p_dir); return da->make_dir(p_dir); } return d->make_dir(p_dir); } Error Directory::make_dir_recursive(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly."); + ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly."); if (!p_dir.is_relative_path()) { - DirAccessRef da = DirAccess::create_for_path(p_dir); + Ref<DirAccess> da = DirAccess::create_for_path(p_dir); return da->make_dir_recursive(p_dir); } return d->make_dir_recursive(p_dir); } bool Directory::file_exists(String p_file) { - ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly."); + ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly."); if (!p_file.is_relative_path()) { return FileAccess::exists(p_file); } @@ -1593,7 +1580,7 @@ bool Directory::file_exists(String p_file) { } bool Directory::dir_exists(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly."); + ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly."); if (!p_dir.is_relative_path()) { return DirAccess::exists(p_dir); } @@ -1601,7 +1588,7 @@ bool Directory::dir_exists(String p_dir) { } uint64_t Directory::get_space_left() { - ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(d.is_null(), 0, "Directory must be opened before use."); return d->get_space_left() / 1024 * 1024; // Truncate to closest MiB. } @@ -1615,7 +1602,7 @@ Error Directory::rename(String p_from, String p_to) { ERR_FAIL_COND_V_MSG(p_from.is_empty() || p_from == "." || p_from == "..", ERR_INVALID_PARAMETER, "Invalid path to rename."); if (!p_from.is_relative_path()) { - DirAccessRef da = DirAccess::create_for_path(p_from); + Ref<DirAccess> da = DirAccess::create_for_path(p_from); ERR_FAIL_COND_V_MSG(!da->file_exists(p_from) && !da->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist."); return da->rename(p_from, p_to); } @@ -1627,7 +1614,7 @@ Error Directory::rename(String p_from, String p_to) { Error Directory::remove(String p_name) { ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); if (!p_name.is_relative_path()) { - DirAccessRef da = DirAccess::create_for_path(p_name); + Ref<DirAccess> da = DirAccess::create_for_path(p_name); return da->remove(p_name); } @@ -1669,12 +1656,6 @@ Directory::Directory() { d = DirAccess::create(DirAccess::ACCESS_RESOURCES); } -Directory::~Directory() { - if (d) { - memdelete(d); - } -} - ////// Marshalls ////// Marshalls *Marshalls::singleton = nullptr; diff --git a/core/core_bind.h b/core/core_bind.h index 4d26698f99..591cacdabb 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -349,7 +349,7 @@ public: class File : public RefCounted { GDCLASS(File, RefCounted); - FileAccess *f = nullptr; + Ref<FileAccess> f; bool big_endian = false; protected: @@ -442,12 +442,11 @@ public: uint64_t get_modified_time(const String &p_file) const; File() {} - virtual ~File(); }; class Directory : public RefCounted { GDCLASS(Directory, RefCounted); - DirAccess *d = nullptr; + Ref<DirAccess> d; bool dir_open = false; bool include_navigational = false; @@ -495,7 +494,6 @@ public: Error remove(String p_name); Directory(); - virtual ~Directory(); }; class Marshalls : public Object { diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index 9acc28f51e..f64c30dca5 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -869,9 +869,8 @@ void NativeExtensionAPIDump::generate_extension_json_file(const String &p_path) json.instantiate(); String text = json->stringify(api, "\t", false); - FileAccessRef fa = FileAccess::open(p_path, FileAccess::WRITE); + Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE); CharString cs = text.ascii(); fa->store_buffer((const uint8_t *)cs.ptr(), cs.length()); - fa->close(); } #endif diff --git a/core/extension/native_extension_manager.cpp b/core/extension/native_extension_manager.cpp index 509405494b..5436f7d51e 100644 --- a/core/extension/native_extension_manager.cpp +++ b/core/extension/native_extension_manager.cpp @@ -112,8 +112,8 @@ void NativeExtensionManager::deinitialize_extensions(NativeExtension::Initializa } void NativeExtensionManager::load_extensions() { - FileAccessRef f = FileAccess::open(NativeExtension::get_extension_list_config_file(), FileAccess::READ); - while (f && !f->eof_reached()) { + Ref<FileAccess> f = FileAccess::open(NativeExtension::get_extension_list_config_file(), FileAccess::READ); + while (f.is_valid() && !f->eof_reached()) { String s = f->get_line().strip_edges(); if (!s.is_empty()) { LoadStatus err = load_extension(s); diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp index c942b417e4..bc24cac955 100644 --- a/core/io/config_file.cpp +++ b/core/io/config_file.cpp @@ -129,12 +129,9 @@ void ConfigFile::erase_section_key(const String &p_section, const String &p_key) Error ConfigFile::save(const String &p_path) { Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); if (err) { - if (file) { - memdelete(file); - } return err; } @@ -143,17 +140,16 @@ Error ConfigFile::save(const String &p_path) { Error ConfigFile::save_encrypted(const String &p_path, const Vector<uint8_t> &p_key) { Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); if (err) { return err; } - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); + Ref<FileAccessEncrypted> fae; + fae.instantiate(); err = fae->open_and_parse(f, p_key, FileAccessEncrypted::MODE_WRITE_AES256); if (err) { - memdelete(fae); - memdelete(f); return err; } return _internal_save(fae); @@ -161,24 +157,23 @@ Error ConfigFile::save_encrypted(const String &p_path, const Vector<uint8_t> &p_ Error ConfigFile::save_encrypted_pass(const String &p_path, const String &p_pass) { Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); if (err) { return err; } - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); + Ref<FileAccessEncrypted> fae; + fae.instantiate(); err = fae->open_and_parse_password(f, p_pass, FileAccessEncrypted::MODE_WRITE_AES256); if (err) { - memdelete(fae); - memdelete(f); return err; } return _internal_save(fae); } -Error ConfigFile::_internal_save(FileAccess *file) { +Error ConfigFile::_internal_save(Ref<FileAccess> file) { for (OrderedHashMap<String, OrderedHashMap<String, Variant>>::Element E = values.front(); E; E = E.next()) { if (E != values.front()) { file->store_string("\n"); @@ -194,16 +189,14 @@ Error ConfigFile::_internal_save(FileAccess *file) { } } - memdelete(file); - return OK; } Error ConfigFile::load(const String &p_path) { Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { + if (f.is_null()) { return err; } @@ -212,17 +205,16 @@ Error ConfigFile::load(const String &p_path) { Error ConfigFile::load_encrypted(const String &p_path, const Vector<uint8_t> &p_key) { Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { return err; } - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); + Ref<FileAccessEncrypted> fae; + fae.instantiate(); err = fae->open_and_parse(f, p_key, FileAccessEncrypted::MODE_READ); if (err) { - memdelete(fae); - memdelete(f); return err; } return _internal_load(p_path, fae); @@ -230,31 +222,28 @@ Error ConfigFile::load_encrypted(const String &p_path, const Vector<uint8_t> &p_ Error ConfigFile::load_encrypted_pass(const String &p_path, const String &p_pass) { Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { return err; } - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); + Ref<FileAccessEncrypted> fae; + fae.instantiate(); err = fae->open_and_parse_password(f, p_pass, FileAccessEncrypted::MODE_READ); if (err) { - memdelete(fae); - memdelete(f); return err; } return _internal_load(p_path, fae); } -Error ConfigFile::_internal_load(const String &p_path, FileAccess *f) { +Error ConfigFile::_internal_load(const String &p_path, Ref<FileAccess> f) { VariantParser::StreamFile stream; stream.f = f; Error err = _parse(p_path, &stream); - memdelete(f); - return err; } diff --git a/core/io/config_file.h b/core/io/config_file.h index 71e9080fb7..7a52b0e16a 100644 --- a/core/io/config_file.h +++ b/core/io/config_file.h @@ -43,8 +43,8 @@ class ConfigFile : public RefCounted { PackedStringArray _get_sections() const; PackedStringArray _get_section_keys(const String &p_section) const; - Error _internal_load(const String &p_path, FileAccess *f); - Error _internal_save(FileAccess *file); + Error _internal_load(const String &p_path, Ref<FileAccess> f); + Error _internal_save(Ref<FileAccess> file); Error _parse(const String &p_path, VariantParser::Stream *p_stream); diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp index 73efdeb38e..dd994fe2fb 100644 --- a/core/io/dir_access.cpp +++ b/core/io/dir_access.cpp @@ -217,8 +217,8 @@ String DirAccess::fix_path(String p_path) const { DirAccess::CreateFunc DirAccess::create_func[ACCESS_MAX] = { nullptr, nullptr, nullptr }; -DirAccess *DirAccess::create_for_path(const String &p_path) { - DirAccess *da = nullptr; +Ref<DirAccess> DirAccess::create_for_path(const String &p_path) { + Ref<DirAccess> da; if (p_path.begins_with("res://")) { da = create(ACCESS_RESOURCES); } else if (p_path.begins_with("user://")) { @@ -230,25 +230,23 @@ DirAccess *DirAccess::create_for_path(const String &p_path) { return da; } -DirAccess *DirAccess::open(const String &p_path, Error *r_error) { - DirAccess *da = create_for_path(p_path); - - ERR_FAIL_COND_V_MSG(!da, nullptr, "Cannot create DirAccess for path '" + p_path + "'."); +Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) { + Ref<DirAccess> da = create_for_path(p_path); + ERR_FAIL_COND_V_MSG(da.is_null(), nullptr, "Cannot create DirAccess for path '" + p_path + "'."); Error err = da->change_dir(p_path); if (r_error) { *r_error = err; } if (err != OK) { - memdelete(da); return nullptr; } return da; } -DirAccess *DirAccess::create(AccessType p_access) { - DirAccess *da = create_func[p_access] ? create_func[p_access]() : nullptr; - if (da) { +Ref<DirAccess> DirAccess::create(AccessType p_access) { + Ref<DirAccess> da = create_func[p_access] ? create_func[p_access]() : nullptr; + if (da.is_valid()) { da->_access_type = p_access; // for ACCESS_RESOURCES and ACCESS_FILESYSTEM, current_dir already defaults to where game was started @@ -264,34 +262,24 @@ DirAccess *DirAccess::create(AccessType p_access) { } String DirAccess::get_full_path(const String &p_path, AccessType p_access) { - DirAccess *d = DirAccess::create(p_access); - if (!d) { + Ref<DirAccess> d = DirAccess::create(p_access); + if (d.is_null()) { return p_path; } d->change_dir(p_path); String full = d->get_current_dir(); - memdelete(d); return full; } Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { //printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data()); Error err; - FileAccess *fsrc = FileAccess::open(p_from, FileAccess::READ, &err); - - if (err) { - ERR_PRINT("Failed to open " + p_from); - return err; - } + Ref<FileAccess> fsrc = FileAccess::open(p_from, FileAccess::READ, &err); + ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_from); - FileAccess *fdst = FileAccess::open(p_to, FileAccess::WRITE, &err); - if (err) { - fsrc->close(); - memdelete(fsrc); - ERR_PRINT("Failed to open " + p_to); - return err; - } + Ref<FileAccess> fdst = FileAccess::open(p_to, FileAccess::WRITE, &err); + ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_to); fsrc->seek_end(0); int size = fsrc->get_position(); @@ -311,7 +299,6 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { } if (err == OK && p_chmod_flags != -1) { - fdst->close(); err = FileAccess::set_unix_permissions(p_to, p_chmod_flags); // If running on a platform with no chmod support (i.e., Windows), don't fail if (err == ERR_UNAVAILABLE) { @@ -319,9 +306,6 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { } } - memdelete(fsrc); - memdelete(fdst); - return err; } @@ -343,7 +327,7 @@ public: } }; -Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links) { +Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links) { List<String> dirs; String curdir = get_current_dir(); @@ -399,14 +383,11 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_copy_links) { ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist."); - DirAccess *target_da = DirAccess::create_for_path(p_to); - ERR_FAIL_COND_V_MSG(!target_da, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_to + "'."); + Ref<DirAccess> target_da = DirAccess::create_for_path(p_to); + ERR_FAIL_COND_V_MSG(target_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_to + "'."); if (!target_da->dir_exists(p_to)) { Error err = target_da->make_dir_recursive(p_to); - if (err) { - memdelete(target_da); - } ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + p_to + "'."); } @@ -416,12 +397,11 @@ Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_ DirChanger dir_changer(this, p_from); Error err = _copy_dir(target_da, p_to, p_chmod_flags, p_copy_links); - memdelete(target_da); return err; } bool DirAccess::exists(String p_dir) { - DirAccessRef da = DirAccess::create_for_path(p_dir); + Ref<DirAccess> da = DirAccess::create_for_path(p_dir); return da->change_dir(p_dir) == OK; } diff --git a/core/io/dir_access.h b/core/io/dir_access.h index b97d097842..0125f011b5 100644 --- a/core/io/dir_access.h +++ b/core/io/dir_access.h @@ -31,11 +31,12 @@ #ifndef DIR_ACCESS_H #define DIR_ACCESS_H +#include "core/object/ref_counted.h" #include "core/string/ustring.h" #include "core/typedefs.h" //@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies -class DirAccess { +class DirAccess : public RefCounted { public: enum AccessType { ACCESS_RESOURCES, @@ -44,13 +45,13 @@ public: ACCESS_MAX }; - typedef DirAccess *(*CreateFunc)(); + typedef Ref<DirAccess> (*CreateFunc)(); private: AccessType _access_type = ACCESS_FILESYSTEM; static CreateFunc create_func[ACCESS_MAX]; ///< set this to instance a filesystem object - Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links); + Error _copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links); protected: String _get_root_path() const; @@ -59,7 +60,7 @@ protected: String fix_path(String p_path) const; template <class T> - static DirAccess *_create_builtin() { + static Ref<DirAccess> _create_builtin() { return memnew(T); } @@ -77,7 +78,7 @@ public: virtual bool drives_are_shortcuts(); virtual Error change_dir(String p_dir) = 0; ///< can be relative or absolute, return false on success - virtual String get_current_dir(bool p_include_drive = true) = 0; ///< return current dir location + virtual String get_current_dir(bool p_include_drive = true) const = 0; ///< return current dir location virtual Error make_dir(String p_dir) = 0; virtual Error make_dir_recursive(String p_dir); virtual Error erase_contents_recursive(); //super dangerous, use with care! @@ -101,51 +102,29 @@ public: // Meant for editor code when we want to quickly remove a file without custom // handling (e.g. removing a cache file). static void remove_file_or_error(String p_path) { - DirAccess *da = create(ACCESS_FILESYSTEM); + Ref<DirAccess> da = create(ACCESS_FILESYSTEM); if (da->file_exists(p_path)) { if (da->remove(p_path) != OK) { ERR_FAIL_MSG("Cannot remove file or directory: " + p_path); } } - memdelete(da); } virtual String get_filesystem_type() const = 0; static String get_full_path(const String &p_path, AccessType p_access); - static DirAccess *create_for_path(const String &p_path); + static Ref<DirAccess> create_for_path(const String &p_path); - static DirAccess *create(AccessType p_access); + static Ref<DirAccess> create(AccessType p_access); template <class T> static void make_default(AccessType p_access) { create_func[p_access] = _create_builtin<T>; } - static DirAccess *open(const String &p_path, Error *r_error = nullptr); + static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr); DirAccess() {} virtual ~DirAccess() {} }; -struct DirAccessRef { - _FORCE_INLINE_ DirAccess *operator->() { - return f; - } - - operator bool() const { return f != nullptr; } - - DirAccess *f = nullptr; - - DirAccessRef(DirAccess *fa) { f = fa; } - DirAccessRef(DirAccessRef &&other) { - f = other.f; - other.f = nullptr; - } - ~DirAccessRef() { - if (f) { - memdelete(f); - } - } -}; - #endif // DIR_ACCESS_H diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 86836454c5..87c10074af 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -42,10 +42,10 @@ FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr; bool FileAccess::backup_save = false; -FileAccess *FileAccess::create(AccessType p_access) { +Ref<FileAccess> FileAccess::create(AccessType p_access) { ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr); - FileAccess *ret = create_func[p_access](); + Ref<FileAccess> ret = create_func[p_access](); ret->_set_access_type(p_access); return ret; } @@ -55,11 +55,10 @@ bool FileAccess::exists(const String &p_name) { return true; } - FileAccess *f = open(p_name, READ); - if (!f) { + Ref<FileAccess> f = open(p_name, READ); + if (f.is_null()) { return false; } - memdelete(f); return true; } @@ -67,8 +66,8 @@ void FileAccess::_set_access_type(AccessType p_access) { _access_type = p_access; } -FileAccess *FileAccess::create_for_path(const String &p_path) { - FileAccess *ret = nullptr; +Ref<FileAccess> FileAccess::create_for_path(const String &p_path) { + Ref<FileAccess> ret; if (p_path.begins_with("res://")) { ret = create(ACCESS_RESOURCES); } else if (p_path.begins_with("user://")) { @@ -85,13 +84,13 @@ Error FileAccess::reopen(const String &p_path, int p_mode_flags) { return _open(p_path, p_mode_flags); } -FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) { +Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) { //try packed data first - FileAccess *ret = nullptr; + Ref<FileAccess> ret; if (!(p_mode_flags & WRITE) && PackedData::get_singleton() && !PackedData::get_singleton()->is_disabled()) { ret = PackedData::get_singleton()->try_open_path(p_path); - if (ret) { + if (ret.is_valid()) { if (r_error) { *r_error = OK; } @@ -106,8 +105,7 @@ FileAccess *FileAccess::open(const String &p_path, int p_mode_flags, Error *r_er *r_error = err; } if (err != OK) { - memdelete(ret); - ret = nullptr; + ret = Ref<FileAccess>(); } return ret; @@ -463,11 +461,10 @@ uint64_t FileAccess::get_modified_time(const String &p_file) { return 0; } - FileAccess *fa = create_for_path(p_file); - ERR_FAIL_COND_V_MSG(!fa, 0, "Cannot create FileAccess for path '" + p_file + "'."); + Ref<FileAccess> fa = create_for_path(p_file); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'."); uint64_t mt = fa->_get_modified_time(p_file); - memdelete(fa); return mt; } @@ -476,11 +473,10 @@ uint32_t FileAccess::get_unix_permissions(const String &p_file) { return 0; } - FileAccess *fa = create_for_path(p_file); - ERR_FAIL_COND_V_MSG(!fa, 0, "Cannot create FileAccess for path '" + p_file + "'."); + Ref<FileAccess> fa = create_for_path(p_file); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'."); uint32_t mt = fa->_get_unix_permissions(p_file); - memdelete(fa); return mt; } @@ -489,11 +485,10 @@ Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissi return ERR_UNAVAILABLE; } - FileAccess *fa = create_for_path(p_file); - ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'."); + Ref<FileAccess> fa = create_for_path(p_file); + ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'."); Error err = fa->_set_unix_permissions(p_file, p_permissions); - memdelete(fa); return err; } @@ -559,8 +554,8 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) { } Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) { - FileAccess *f = FileAccess::open(p_path, READ, r_error); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, READ, r_error); + if (f.is_null()) { if (r_error) { // if error requested, do not throw error return Vector<uint8_t>(); } @@ -569,7 +564,6 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_err Vector<uint8_t> data; data.resize(f->get_length()); f->get_buffer(data.ptrw(), data.size()); - memdelete(f); return data; } @@ -592,8 +586,8 @@ String FileAccess::get_file_as_string(const String &p_path, Error *r_error) { } String FileAccess::get_md5(const String &p_file) { - FileAccess *f = FileAccess::open(p_file, READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_file, READ); + if (f.is_null()) { return String(); } @@ -615,8 +609,6 @@ String FileAccess::get_md5(const String &p_file) { unsigned char hash[16]; ctx.finish(hash); - memdelete(f); - return String::md5(hash); } @@ -625,8 +617,8 @@ String FileAccess::get_multiple_md5(const Vector<String> &p_file) { ctx.start(); for (int i = 0; i < p_file.size(); i++) { - FileAccess *f = FileAccess::open(p_file[i], READ); - ERR_CONTINUE(!f); + Ref<FileAccess> f = FileAccess::open(p_file[i], READ); + ERR_CONTINUE(f.is_null()); unsigned char step[32768]; @@ -639,7 +631,6 @@ String FileAccess::get_multiple_md5(const Vector<String> &p_file) { break; } } - memdelete(f); } unsigned char hash[16]; @@ -649,8 +640,8 @@ String FileAccess::get_multiple_md5(const Vector<String> &p_file) { } String FileAccess::get_sha256(const String &p_file) { - FileAccess *f = FileAccess::open(p_file, READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_file, READ); + if (f.is_null()) { return String(); } @@ -672,6 +663,5 @@ String FileAccess::get_sha256(const String &p_file) { unsigned char hash[32]; ctx.finish(hash); - memdelete(f); return String::hex_encode_buffer(hash, 32); } diff --git a/core/io/file_access.h b/core/io/file_access.h index a5150010da..60abfe3c5e 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -32,6 +32,7 @@ #define FILE_ACCESS_H #include "core/math/math_defs.h" +#include "core/object/ref_counted.h" #include "core/os/memory.h" #include "core/string/ustring.h" #include "core/typedefs.h" @@ -40,7 +41,7 @@ * Multi-Platform abstraction for accessing to files. */ -class FileAccess { +class FileAccess : public RefCounted { public: enum AccessType { ACCESS_RESOURCES, @@ -51,7 +52,7 @@ public: typedef void (*FileCloseFailNotify)(const String &); - typedef FileAccess *(*CreateFunc)(); + typedef Ref<FileAccess> (*CreateFunc)(); bool big_endian = false; bool real_is_double = false; @@ -71,7 +72,7 @@ private: AccessType _access_type = ACCESS_FILESYSTEM; static CreateFunc create_func[ACCESS_MAX]; /** default file access creation function for a platform */ template <class T> - static FileAccess *_create_builtin() { + static Ref<FileAccess> _create_builtin() { return memnew(T); } @@ -148,9 +149,9 @@ public: virtual Error reopen(const String &p_path, int p_mode_flags); ///< does not change the AccessType - static FileAccess *create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files. - static FileAccess *create_for_path(const String &p_path); - static FileAccess *open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files. + static Ref<FileAccess> create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files. + static Ref<FileAccess> create_for_path(const String &p_path); + static Ref<FileAccess> open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files. static CreateFunc get_create_func(AccessType p_access); static bool exists(const String &p_name); ///< return true if a file exists static uint64_t get_modified_time(const String &p_file); @@ -176,27 +177,4 @@ public: virtual ~FileAccess() {} }; -struct FileAccessRef { - _FORCE_INLINE_ FileAccess *operator->() { - return f; - } - - operator bool() const { return f != nullptr; } - - FileAccess *f = nullptr; - - operator FileAccess *() { return f; } - - FileAccessRef(FileAccess *fa) { f = fa; } - FileAccessRef(FileAccessRef &&other) { - f = other.f; - other.f = nullptr; - } - ~FileAccessRef() { - if (f) { - memdelete(f); - } - } -}; - #endif // FILE_ACCESS_H diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index 85faf04315..0c961ba8fb 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -58,12 +58,12 @@ void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_ } \ } -Error FileAccessCompressed::open_after_magic(FileAccess *p_base) { +Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) { f = p_base; cmode = (Compression::Mode)f->get_32(); block_size = f->get_32(); if (block_size == 0) { - f = nullptr; // Let the caller to handle the FileAccess object if failed to open as compressed file. + f = Ref<FileAccess>(); ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Can't open compressed file '" + p_base->get_path() + "' with block size 0, it is corrupted."); } read_total = f->get_32(); @@ -98,7 +98,7 @@ Error FileAccessCompressed::open_after_magic(FileAccess *p_base) { Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) { ERR_FAIL_COND_V(p_mode_flags == READ_WRITE, ERR_UNAVAILABLE); - if (f) { + if (f.is_valid()) { close(); } @@ -106,8 +106,7 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) { f = FileAccess::open(p_path, p_mode_flags, &err); if (err != OK) { //not openable - - f = nullptr; + f = Ref<FileAccess>(); return err; } @@ -127,8 +126,7 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) { rmagic[4] = 0; err = ERR_FILE_UNRECOGNIZED; if (magic != rmagic || (err = open_after_magic(f)) != OK) { - memdelete(f); - f = nullptr; + f = Ref<FileAccess>(); return err; } } @@ -137,7 +135,7 @@ Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) { } void FileAccessCompressed::close() { - if (!f) { + if (f.is_null()) { return; } @@ -182,17 +180,15 @@ void FileAccessCompressed::close() { buffer.clear(); read_blocks.clear(); } - - memdelete(f); - f = nullptr; + f = Ref<FileAccess>(); } bool FileAccessCompressed::is_open() const { - return f != nullptr; + return f.is_valid(); } void FileAccessCompressed::seek(uint64_t p_position) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use."); if (writing) { ERR_FAIL_COND(p_position > write_max); @@ -222,7 +218,7 @@ void FileAccessCompressed::seek(uint64_t p_position) { } void FileAccessCompressed::seek_end(int64_t p_position) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use."); if (writing) { seek(write_max + p_position); } else { @@ -231,7 +227,7 @@ void FileAccessCompressed::seek_end(int64_t p_position) { } uint64_t FileAccessCompressed::get_position() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use."); if (writing) { return write_pos; } else { @@ -240,7 +236,7 @@ uint64_t FileAccessCompressed::get_position() const { } uint64_t FileAccessCompressed::get_length() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use."); if (writing) { return write_max; } else { @@ -249,7 +245,7 @@ uint64_t FileAccessCompressed::get_length() const { } bool FileAccessCompressed::eof_reached() const { - ERR_FAIL_COND_V_MSG(!f, false, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(f.is_null(), false, "File must be opened before use."); if (writing) { return false; } else { @@ -258,7 +254,7 @@ bool FileAccessCompressed::eof_reached() const { } uint8_t FileAccessCompressed::get_8() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use."); ERR_FAIL_COND_V_MSG(writing, 0, "File has not been opened in read mode."); if (at_end) { @@ -291,7 +287,7 @@ uint8_t FileAccessCompressed::get_8() const { uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); - ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(f.is_null(), -1, "File must be opened before use."); ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode."); if (at_end) { @@ -332,14 +328,14 @@ Error FileAccessCompressed::get_error() const { } void FileAccessCompressed::flush() { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use."); ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode."); // compressed files keep data in memory till close() } void FileAccessCompressed::store_8(uint8_t p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use."); ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode."); WRITE_FIT(1); @@ -347,16 +343,15 @@ void FileAccessCompressed::store_8(uint8_t p_dest) { } bool FileAccessCompressed::file_exists(const String &p_name) { - FileAccess *fa = FileAccess::open(p_name, FileAccess::READ); - if (!fa) { + Ref<FileAccess> fa = FileAccess::open(p_name, FileAccess::READ); + if (fa.is_null()) { return false; } - memdelete(fa); return true; } uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) { - if (f) { + if (f.is_valid()) { return f->get_modified_time(p_file); } else { return 0; @@ -364,21 +359,21 @@ uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) { } uint32_t FileAccessCompressed::_get_unix_permissions(const String &p_file) { - if (f) { + if (f.is_valid()) { return f->_get_unix_permissions(p_file); } return 0; } Error FileAccessCompressed::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { - if (f) { + if (f.is_valid()) { return f->_set_unix_permissions(p_file, p_permissions); } return FAILED; } FileAccessCompressed::~FileAccessCompressed() { - if (f) { + if (f.is_valid()) { close(); } } diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index 97ef3fbdeb..cd28c576cf 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -61,12 +61,12 @@ class FileAccessCompressed : public FileAccess { String magic = "GCMP"; mutable Vector<uint8_t> buffer; - FileAccess *f = nullptr; + Ref<FileAccess> f; public: void configure(const String &p_magic, Compression::Mode p_mode = Compression::MODE_ZSTD, uint32_t p_block_size = 4096); - Error open_after_magic(FileAccess *p_base); + Error open_after_magic(Ref<FileAccess> p_base); virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file virtual void close(); ///< close a file diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index 8ee19d3d06..2443e2bea0 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -36,7 +36,7 @@ #include <stdio.h> -Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic) { +Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic) { ERR_FAIL_COND_V_MSG(file != nullptr, ERR_ALREADY_IN_USE, "Can't open file while another file from path '" + file->get_path_absolute() + "' is open."); ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER); @@ -99,7 +99,7 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8 return OK; } -Error FileAccessEncrypted::open_and_parse_password(FileAccess *p_base, const String &p_key, Mode p_mode) { +Error FileAccessEncrypted::open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode) { String cs = p_key.md5_text(); ERR_FAIL_COND_V(cs.length() != 32, ERR_INVALID_PARAMETER); Vector<uint8_t> key; @@ -116,26 +116,25 @@ Error FileAccessEncrypted::_open(const String &p_path, int p_mode_flags) { } void FileAccessEncrypted::close() { - if (!file) { + if (file.is_null()) { return; } _release(); file->close(); - memdelete(file); - file = nullptr; + file = Ref<FileAccess>(); } void FileAccessEncrypted::release() { - if (!file) { + if (file.is_null()) { return; } _release(); - file = nullptr; + file = Ref<FileAccess>(); } void FileAccessEncrypted::_release() { @@ -183,7 +182,7 @@ bool FileAccessEncrypted::is_open() const { } String FileAccessEncrypted::get_path() const { - if (file) { + if (file.is_valid()) { return file->get_path(); } else { return ""; @@ -191,7 +190,7 @@ String FileAccessEncrypted::get_path() const { } String FileAccessEncrypted::get_path_absolute() const { - if (file) { + if (file.is_valid()) { return file->get_path_absolute(); } else { return ""; @@ -291,11 +290,10 @@ void FileAccessEncrypted::store_8(uint8_t p_dest) { } bool FileAccessEncrypted::file_exists(const String &p_name) { - FileAccess *fa = FileAccess::open(p_name, FileAccess::READ); - if (!fa) { + Ref<FileAccess> fa = FileAccess::open(p_name, FileAccess::READ); + if (fa.is_null()) { return false; } - memdelete(fa); return true; } @@ -313,7 +311,7 @@ Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t } FileAccessEncrypted::~FileAccessEncrypted() { - if (file) { + if (file.is_valid()) { close(); } } diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index be5904c894..5d0b369fbf 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -46,7 +46,7 @@ public: private: Vector<uint8_t> key; bool writing = false; - FileAccess *file = nullptr; + Ref<FileAccess> file; uint64_t base = 0; uint64_t length = 0; Vector<uint8_t> data; @@ -57,8 +57,8 @@ private: void _release(); public: - Error open_and_parse(FileAccess *p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true); - Error open_and_parse_password(FileAccess *p_base, const String &p_key, Mode p_mode); + Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true); + Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode); virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file virtual void close(); ///< close a file diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 4aca26b007..62da51b09f 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -60,7 +60,7 @@ void FileAccessMemory::cleanup() { memdelete(files); } -FileAccess *FileAccessMemory::create() { +Ref<FileAccess> FileAccessMemory::create() { return memnew(FileAccessMemory); } diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index 50b23e1f32..baaad5f086 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -38,7 +38,7 @@ class FileAccessMemory : public FileAccess { uint64_t length = 0; mutable uint64_t pos = 0; - static FileAccess *create(); + static Ref<FileAccess> create(); public: static void register_file(String p_name, Vector<uint8_t> p_data); diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 7dbea96c3d..0b8deb8ec2 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -126,8 +126,8 @@ PackedData::~PackedData() { ////////////////////////////////////////////////////////////////// bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { return false; } @@ -137,19 +137,13 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, if (magic != PACK_HEADER_MAGIC) { // loading with offset feature not supported for self contained exe files - if (p_offset != 0) { - f->close(); - memdelete(f); - ERR_FAIL_V_MSG(false, "Loading self-contained executable with offset not supported."); - } + ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Loading self-contained executable with offset not supported."); //maybe at the end.... self contained exe f->seek_end(); f->seek(f->get_position() - 4); magic = f->get_32(); if (magic != PACK_HEADER_MAGIC) { - f->close(); - memdelete(f); return false; } f->seek(f->get_position() - 12); @@ -159,8 +153,6 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, magic = f->get_32(); if (magic != PACK_HEADER_MAGIC) { - f->close(); - memdelete(f); return false; } } @@ -170,16 +162,8 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint32_t ver_minor = f->get_32(); f->get_32(); // patch number, not used for validation. - if (version != PACK_FORMAT_VERSION) { - f->close(); - memdelete(f); - ERR_FAIL_V_MSG(false, "Pack version unsupported: " + itos(version) + "."); - } - if (ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR)) { - f->close(); - memdelete(f); - ERR_FAIL_V_MSG(false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + "."); - } + ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION, false, "Pack version unsupported: " + itos(version) + "."); + ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + "."); uint32_t pack_flags = f->get_32(); uint64_t file_base = f->get_64(); @@ -194,12 +178,9 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, int file_count = f->get_32(); if (enc_directory) { - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); - if (!fae) { - f->close(); - memdelete(f); - ERR_FAIL_V_MSG(false, "Can't open encrypted pack directory."); - } + Ref<FileAccessEncrypted> fae; + fae.instantiate(); + ERR_FAIL_COND_V_MSG(fae.is_null(), false, "Can't open encrypted pack directory."); Vector<uint8_t> key; key.resize(32); @@ -208,12 +189,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, } Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false); - if (err) { - f->close(); - memdelete(f); - memdelete(fae); - ERR_FAIL_V_MSG(false, "Can't open encrypted pack directory."); - } + ERR_FAIL_COND_V_MSG(err, false, "Can't open encrypted pack directory."); f = fae; } @@ -236,12 +212,10 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, PackedData::get_singleton()->add_path(p_path, path, ofs + p_offset, size, md5, this, p_replace_files, (flags & PACK_FILE_ENCRYPTED)); } - f->close(); - memdelete(f); return true; } -FileAccess *PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file) { +Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::PackedFile *p_file) { return memnew(FileAccessPack(p_path, *p_file)); } @@ -351,16 +325,15 @@ bool FileAccessPack::file_exists(const String &p_name) { FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file) : pf(p_file), f(FileAccess::open(pf.pack, FileAccess::READ)) { - ERR_FAIL_COND_MSG(!f, "Can't open pack-referenced file '" + String(pf.pack) + "'."); + ERR_FAIL_COND_MSG(f.is_null(), "Can't open pack-referenced file '" + String(pf.pack) + "'."); f->seek(pf.offset); off = pf.offset; if (pf.encrypted) { - FileAccessEncrypted *fae = memnew(FileAccessEncrypted); - if (!fae) { - ERR_FAIL_MSG("Can't open encrypted pack-referenced file '" + String(pf.pack) + "'."); - } + Ref<FileAccessEncrypted> fae; + fae.instantiate(); + ERR_FAIL_COND_MSG(fae.is_null(), "Can't open encrypted pack-referenced file '" + String(pf.pack) + "'."); Vector<uint8_t> key; key.resize(32); @@ -369,10 +342,7 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil } Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false); - if (err) { - memdelete(fae); - ERR_FAIL_MSG("Can't open encrypted pack-referenced file '" + String(pf.pack) + "'."); - } + ERR_FAIL_COND_MSG(err, "Can't open encrypted pack-referenced file '" + String(pf.pack) + "'."); f = fae; off = 0; } @@ -380,13 +350,6 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil eof = false; } -FileAccessPack::~FileAccessPack() { - if (f) { - f->close(); - memdelete(f); - } -} - ////////////////////////////////////////////////////////////////////////////////// // DIR ACCESS ////////////////////////////////////////////////////////////////////////////////// @@ -507,7 +470,7 @@ Error DirAccessPack::change_dir(String p_dir) { } } -String DirAccessPack::get_current_dir(bool p_include_drive) { +String DirAccessPack::get_current_dir(bool p_include_drive) const { PackedData::PackedDir *pd = current; String p = current->name; diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index d4b32df2c7..399b345b35 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -120,10 +120,10 @@ public: static PackedData *get_singleton() { return singleton; } Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset); - _FORCE_INLINE_ FileAccess *try_open_path(const String &p_path); + _FORCE_INLINE_ Ref<FileAccess> try_open_path(const String &p_path); _FORCE_INLINE_ bool has_path(const String &p_path); - _FORCE_INLINE_ DirAccess *try_open_directory(const String &p_path); + _FORCE_INLINE_ Ref<DirAccess> try_open_directory(const String &p_path); _FORCE_INLINE_ bool has_directory(const String &p_path); PackedData(); @@ -133,14 +133,14 @@ public: class PackSource { public: virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) = 0; - virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file) = 0; + virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) = 0; virtual ~PackSource() {} }; class PackedSourcePCK : public PackSource { public: virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override; - virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file) override; + virtual Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override; }; class FileAccessPack : public FileAccess { @@ -150,7 +150,7 @@ class FileAccessPack : public FileAccess { mutable bool eof; uint64_t off; - FileAccess *f = nullptr; + Ref<FileAccess> f; virtual Error _open(const String &p_path, int p_mode_flags); virtual uint64_t _get_modified_time(const String &p_file) { return 0; } virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } @@ -183,10 +183,9 @@ public: virtual bool file_exists(const String &p_name); FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file); - ~FileAccessPack(); }; -FileAccess *PackedData::try_open_path(const String &p_path) { +Ref<FileAccess> PackedData::try_open_path(const String &p_path) { PathMD5 pmd5(p_path.md5_buffer()); Map<PathMD5, PackedFile>::Element *E = files.find(pmd5); if (!E) { @@ -204,9 +203,8 @@ bool PackedData::has_path(const String &p_path) { } bool PackedData::has_directory(const String &p_path) { - DirAccess *da = try_open_directory(p_path); - if (da) { - memdelete(da); + Ref<DirAccess> da = try_open_directory(p_path); + if (da.is_valid()) { return true; } else { return false; @@ -233,7 +231,7 @@ public: virtual String get_drive(int p_drive); virtual Error change_dir(String p_dir); - virtual String get_current_dir(bool p_include_drive = true); + virtual String get_current_dir(bool p_include_drive = true) const; virtual bool file_exists(String p_file); virtual bool dir_exists(String p_dir); @@ -252,14 +250,12 @@ public: virtual String get_filesystem_type() const; DirAccessPack(); - ~DirAccessPack() {} }; -DirAccess *PackedData::try_open_directory(const String &p_path) { - DirAccess *da = memnew(DirAccessPack()); +Ref<DirAccess> PackedData::try_open_directory(const String &p_path) { + Ref<DirAccess> da = memnew(DirAccessPack()); if (da->change_dir(p_path) != OK) { - memdelete(da); - da = nullptr; + da = Ref<DirAccess>(); } return da; } diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index 6347862775..1caff2dc02 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -38,20 +38,26 @@ ZipArchive *ZipArchive::instance = nullptr; extern "C" { -static void *godot_open(void *data, const char *p_fname, int mode) { +struct ZipData { + Ref<FileAccess> f; +}; + +static void *godot_open(voidpf opaque, const char *p_fname, int mode) { if (mode & ZLIB_FILEFUNC_MODE_WRITE) { return nullptr; } - FileAccess *f = FileAccess::open(p_fname, FileAccess::READ); - ERR_FAIL_COND_V(!f, nullptr); + Ref<FileAccess> f = FileAccess::open(p_fname, FileAccess::READ); + ERR_FAIL_COND_V(f.is_null(), nullptr); - return f; + ZipData *zd = memnew(ZipData); + zd->f = f; + return zd; } -static uLong godot_read(void *data, void *fdata, void *buf, uLong size) { - FileAccess *f = (FileAccess *)fdata; - f->get_buffer((uint8_t *)buf, size); +static uLong godot_read(voidpf opaque, voidpf stream, void *buf, uLong size) { + ZipData *zd = (ZipData *)stream; + zd->f->get_buffer((uint8_t *)buf, size); return size; } @@ -60,42 +66,38 @@ static uLong godot_write(voidpf opaque, voidpf stream, const void *buf, uLong si } static long godot_tell(voidpf opaque, voidpf stream) { - FileAccess *f = (FileAccess *)stream; - return f->get_position(); + ZipData *zd = (ZipData *)stream; + return zd->f->get_position(); } static long godot_seek(voidpf opaque, voidpf stream, uLong offset, int origin) { - FileAccess *f = (FileAccess *)stream; + ZipData *zd = (ZipData *)stream; uint64_t pos = offset; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR: - pos = f->get_position() + offset; + pos = zd->f->get_position() + offset; break; case ZLIB_FILEFUNC_SEEK_END: - pos = f->get_length() + offset; + pos = zd->f->get_length() + offset; break; default: break; } - f->seek(pos); + zd->f->seek(pos); return 0; } static int godot_close(voidpf opaque, voidpf stream) { - FileAccess *f = (FileAccess *)stream; - if (f) { - f->close(); - memdelete(f); - f = nullptr; - } + ZipData *zd = (ZipData *)stream; + memdelete(zd); return 0; } static int godot_testerror(voidpf opaque, voidpf stream) { - FileAccess *f = (FileAccess *)stream; - return f->get_error() != OK ? 1 : 0; + ZipData *zd = (ZipData *)stream; + return zd->f->get_error() != OK ? 1 : 0; } static voidpf godot_alloc(voidpf opaque, uInt items, uInt size) { @@ -208,7 +210,7 @@ bool ZipArchive::file_exists(String p_name) const { return files.has(p_name); } -FileAccess *ZipArchive::get_file(const String &p_path, PackedData::PackedFile *p_file) { +Ref<FileAccess> ZipArchive::get_file(const String &p_path, PackedData::PackedFile *p_file) { return memnew(FileAccessZip(p_path, *p_file)); } diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index a238c66437..f6249add4b 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -68,7 +68,7 @@ public: bool file_exists(String p_name) const; virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) override; - FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file) override; + Ref<FileAccess> get_file(const String &p_path, PackedData::PackedFile *p_file) override; static ZipArchive *get_singleton(); diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index 5518ec8ceb..2ccc95f0de 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -44,17 +44,14 @@ bool ImageFormatLoader::recognize(const String &p_extension) const { return false; } -Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_custom, bool p_force_linear, float p_scale) { +Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, bool p_force_linear, float p_scale) { ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "It's not a reference to a valid Image object."); - FileAccess *f = p_custom; - if (!f) { + Ref<FileAccess> f = p_custom; + if (f.is_null()) { Error err; f = FileAccess::open(p_file, FileAccess::READ, &err); - if (!f) { - ERR_PRINT("Error opening file '" + p_file + "'."); - return err; - } + ERR_FAIL_COND_V_MSG(f.is_null(), err, "Error opening file '" + p_file + "'."); } String extension = p_file.get_extension(); @@ -69,18 +66,10 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_c } if (err != ERR_FILE_UNRECOGNIZED) { - if (!p_custom) { - memdelete(f); - } - return err; } } - if (!p_custom) { - memdelete(f); - } - return ERR_FILE_UNRECOGNIZED; } @@ -123,8 +112,8 @@ void ImageLoader::cleanup() { ///////////////// RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { if (r_error) { *r_error = ERR_CANT_OPEN; } @@ -136,7 +125,6 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin bool unrecognized = header[0] != 'G' || header[1] != 'D' || header[2] != 'I' || header[3] != 'M'; if (unrecognized) { - memdelete(f); if (r_error) { *r_error = ERR_FILE_UNRECOGNIZED; } @@ -155,7 +143,6 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin } if (idx == -1) { - memdelete(f); if (r_error) { *r_error = ERR_FILE_UNRECOGNIZED; } @@ -167,8 +154,6 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin Error err = ImageLoader::loader[idx]->load_image(image, f, false, 1.0); - memdelete(f); - if (err != OK) { if (r_error) { *r_error = err; diff --git a/core/io/image_loader.h b/core/io/image_loader.h index 37d7620f96..9409617268 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -44,7 +44,7 @@ class ImageFormatLoader { friend class ResourceFormatLoaderImage; protected: - virtual Error load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) = 0; + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) = 0; virtual void get_recognized_extensions(List<String> *p_extensions) const = 0; bool recognize(const String &p_extension) const; @@ -58,7 +58,7 @@ class ImageLoader { protected: public: - static Error load_image(String p_file, Ref<Image> p_image, FileAccess *p_custom = nullptr, bool p_force_linear = false, float p_scale = 1.0); + static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), bool p_force_linear = false, float p_scale = 1.0); static void get_recognized_extensions(List<String> *p_extensions); static ImageFormatLoader *recognize(const String &p_extension); diff --git a/core/io/logger.cpp b/core/io/logger.cpp index 2b6f230434..0caa2af5c4 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -115,21 +115,14 @@ void Logger::logf_error(const char *p_format, ...) { va_end(argp); } -void RotatedFileLogger::close_file() { - if (file) { - memdelete(file); - file = nullptr; - } -} - void RotatedFileLogger::clear_old_backups() { int max_backups = max_files - 1; // -1 for the current file String basename = base_path.get_file().get_basename(); String extension = base_path.get_extension(); - DirAccessRef da = DirAccess::open(base_path.get_base_dir()); - if (!da) { + Ref<DirAccess> da = DirAccess::open(base_path.get_base_dir()); + if (da.is_null()) { return; } @@ -155,7 +148,7 @@ void RotatedFileLogger::clear_old_backups() { } void RotatedFileLogger::rotate_file() { - close_file(); + file = Ref<FileAccess>(); if (FileAccess::exists(base_path)) { if (max_files > 1) { @@ -165,20 +158,21 @@ void RotatedFileLogger::rotate_file() { backup_name += "." + base_path.get_extension(); } - DirAccessRef da = DirAccess::open(base_path.get_base_dir()); - if (da) { + Ref<DirAccess> da = DirAccess::open(base_path.get_base_dir()); + if (da.is_valid()) { da->copy(base_path, backup_name); } clear_old_backups(); } } else { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_USERDATA); - if (da) { + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_USERDATA); + if (da.is_valid()) { da->make_dir_recursive(base_path.get_base_dir()); } } file = FileAccess::open(base_path, FileAccess::WRITE); + file->detach_from_objectdb(); // Note: This FileAccess instance will exist longer than ObjectDB, therefor can't be registered in ObjectDB. } RotatedFileLogger::RotatedFileLogger(const String &p_base_path, int p_max_files) : @@ -192,7 +186,7 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) { return; } - if (file) { + if (file.is_valid()) { const int static_buf_size = 512; char static_buf[static_buf_size]; char *buf = static_buf; @@ -218,10 +212,6 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) { } } -RotatedFileLogger::~RotatedFileLogger() { - close_file(); -} - void StdLogger::logv(const char *p_format, va_list p_list, bool p_err) { if (!should_log(p_err)) { return; diff --git a/core/io/logger.h b/core/io/logger.h index 047ee3d0f1..e3ac00f11c 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -81,9 +81,8 @@ class RotatedFileLogger : public Logger { String base_path; int max_files; - FileAccess *file = nullptr; + Ref<FileAccess> file; - void close_file(); void clear_old_backups(); void rotate_file(); @@ -91,8 +90,6 @@ public: RotatedFileLogger(const String &p_base_path, int p_max_files = 10); virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0; - - virtual ~RotatedFileLogger(); }; class CompositeLogger : public Logger { diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index b3bf0cff2d..d1a305e836 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -83,13 +83,8 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String & } enc_dir = p_encrypt_directory; - if (file != nullptr) { - memdelete(file); - } - file = FileAccess::open(p_file, FileAccess::WRITE); - - ERR_FAIL_COND_V_MSG(!file, ERR_CANT_CREATE, "Can't open file to write: " + String(p_file) + "."); + ERR_FAIL_COND_V_MSG(file.is_null(), ERR_CANT_CREATE, "Can't open file to write: " + String(p_file) + "."); alignment = p_alignment; @@ -112,8 +107,8 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String & } Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encrypt) { - FileAccess *f = FileAccess::open(p_src, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_src, FileAccess::READ); + if (f.is_null()) { return ERR_FILE_CANT_OPEN; } @@ -149,14 +144,11 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encr files.push_back(pf); - f->close(); - memdelete(f); - return OK; } Error PCKPacker::flush(bool p_verbose) { - ERR_FAIL_COND_V_MSG(!file, ERR_INVALID_PARAMETER, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(file.is_null(), ERR_INVALID_PARAMETER, "File must be opened before use."); int64_t file_base_ofs = file->get_position(); file->store_64(0); // files base @@ -168,12 +160,12 @@ Error PCKPacker::flush(bool p_verbose) { // write the index file->store_32(files.size()); - FileAccessEncrypted *fae = nullptr; - FileAccess *fhead = file; + Ref<FileAccessEncrypted> fae; + Ref<FileAccess> fhead = file; if (enc_dir) { - fae = memnew(FileAccessEncrypted); - ERR_FAIL_COND_V(!fae, ERR_CANT_CREATE); + fae.instantiate(); + ERR_FAIL_COND_V(fae.is_null(), ERR_CANT_CREATE); Error err = fae->open_and_parse(file, key, FileAccessEncrypted::MODE_WRITE_AES256, false); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); @@ -202,9 +194,8 @@ Error PCKPacker::flush(bool p_verbose) { fhead->store_32(flags); } - if (fae) { + if (fae.is_valid()) { fae->release(); - memdelete(fae); } int header_padding = _get_pad(alignment, file->get_position()); @@ -222,14 +213,14 @@ Error PCKPacker::flush(bool p_verbose) { int count = 0; for (int i = 0; i < files.size(); i++) { - FileAccess *src = FileAccess::open(files[i].src_path, FileAccess::READ); + Ref<FileAccess> src = FileAccess::open(files[i].src_path, FileAccess::READ); uint64_t to_write = files[i].size; - fae = nullptr; - FileAccess *ftmp = file; + fae = Ref<FileAccess>(); + Ref<FileAccess> ftmp = file; if (files[i].encrypted) { - fae = memnew(FileAccessEncrypted); - ERR_FAIL_COND_V(!fae, ERR_CANT_CREATE); + fae.instantiate(); + ERR_FAIL_COND_V(fae.is_null(), ERR_CANT_CREATE); Error err = fae->open_and_parse(file, key, FileAccessEncrypted::MODE_WRITE_AES256, false); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); @@ -242,9 +233,8 @@ Error PCKPacker::flush(bool p_verbose) { to_write -= read; } - if (fae) { + if (fae.is_valid()) { fae->release(); - memdelete(fae); } int pad = _get_pad(alignment, file->get_position()); @@ -252,8 +242,6 @@ Error PCKPacker::flush(bool p_verbose) { file->store_8(Math::rand() % 256); } - src->close(); - memdelete(src); count += 1; const int file_num = files.size(); if (p_verbose && (file_num > 0)) { @@ -265,15 +253,8 @@ Error PCKPacker::flush(bool p_verbose) { printf("\n"); } - file->close(); + file = Ref<FileAccess>(); memdelete_arr(buf); return OK; } - -PCKPacker::~PCKPacker() { - if (file != nullptr) { - memdelete(file); - } - file = nullptr; -} diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h index 583171a70b..77ec293fb2 100644 --- a/core/io/pck_packer.h +++ b/core/io/pck_packer.h @@ -38,7 +38,7 @@ class FileAccess; class PCKPacker : public RefCounted { GDCLASS(PCKPacker, RefCounted); - FileAccess *file = nullptr; + Ref<FileAccess> file; int alignment = 0; uint64_t ofs = 0; @@ -63,7 +63,6 @@ public: Error flush(bool p_verbose = false); PCKPacker() {} - ~PCKPacker(); }; #endif // PCK_PACKER_H diff --git a/core/io/resource.cpp b/core/io/resource.cpp index f90a6e9304..bf91438810 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -538,10 +538,10 @@ void ResourceCache::dump(const char *p_file, bool p_short) { Map<String, int> type_count; - FileAccess *f = nullptr; + Ref<FileAccess> f; if (p_file) { f = FileAccess::open(String::utf8(p_file), FileAccess::WRITE); - ERR_FAIL_COND_MSG(!f, "Cannot create file at path '" + String::utf8(p_file) + "'."); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file at path '" + String::utf8(p_file) + "'."); } const String *K = nullptr; @@ -555,21 +555,17 @@ void ResourceCache::dump(const char *p_file, bool p_short) { type_count[r->get_class()]++; if (!p_short) { - if (f) { + if (f.is_valid()) { f->store_line(r->get_class() + ": " + r->get_path()); } } } for (const KeyValue<String, int> &E : type_count) { - if (f) { + if (f.is_valid()) { f->store_line(E.key + " count: " + itos(E.value)); } } - if (f) { - f->close(); - memdelete(f); - } lock.read_unlock(); #else diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index b65993e3dd..87e4a01819 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -101,6 +101,50 @@ void ResourceLoaderBinary::_advance_padding(uint32_t p_len) { } } +static Error read_reals(real_t *dst, Ref<FileAccess> &f, size_t count) { + if (f->real_is_double) { + if (sizeof(real_t) == 8) { + // Ideal case with double-precision + f->get_buffer((uint8_t *)dst, count * sizeof(double)); +#ifdef BIG_ENDIAN_ENABLED + { + uint64_t *dst = (uint64_t *)dst; + for (size_t i = 0; i < count; i++) { + dst[i] = BSWAP64(dst[i]); + } + } +#endif + } else if (sizeof(real_t) == 4) { + // May be slower, but this is for compatibility. Eventually the data should be converted. + for (size_t i = 0; i < count; ++i) { + dst[i] = f->get_double(); + } + } else { + ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "real_t size is neither 4 nor 8!"); + } + } else { + if (sizeof(real_t) == 4) { + // Ideal case with float-precision + f->get_buffer((uint8_t *)dst, count * sizeof(float)); +#ifdef BIG_ENDIAN_ENABLED + { + uint32_t *dst = (uint32_t *)dst; + for (size_t i = 0; i < count; i++) { + dst[i] = BSWAP32(dst[i]); + } + } +#endif + } else if (sizeof(real_t) == 8) { + for (size_t i = 0; i < count; ++i) { + dst[i] = f->get_float(); + } + } else { + ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "real_t size is neither 4 nor 8!"); + } + } + return OK; +} + StringName ResourceLoaderBinary::_get_string() { uint32_t id = f->get_32(); if (id & 0x80000000) { @@ -528,21 +572,9 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { Vector<Vector2> array; array.resize(len); Vector2 *w = array.ptrw(); - if (sizeof(Vector2) == 8) { - f->get_buffer((uint8_t *)w, len * sizeof(real_t) * 2); -#ifdef BIG_ENDIAN_ENABLED - { - uint32_t *ptr = (uint32_t *)w.ptr(); - for (int i = 0; i < len * 2; i++) { - ptr[i] = BSWAP32(ptr[i]); - } - } - -#endif - - } else { - ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Vector2 size is NOT 8!"); - } + static_assert(sizeof(Vector2) == 2 * sizeof(real_t)); + const Error err = read_reals(reinterpret_cast<real_t *>(w), f, len * 2); + ERR_FAIL_COND_V(err != OK, err); r_v = array; @@ -553,21 +585,9 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { Vector<Vector3> array; array.resize(len); Vector3 *w = array.ptrw(); - if (sizeof(Vector3) == 12) { - f->get_buffer((uint8_t *)w, len * sizeof(real_t) * 3); -#ifdef BIG_ENDIAN_ENABLED - { - uint32_t *ptr = (uint32_t *)w.ptr(); - for (int i = 0; i < len * 3; i++) { - ptr[i] = BSWAP32(ptr[i]); - } - } - -#endif - - } else { - ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Vector3 size is NOT 12!"); - } + static_assert(sizeof(Vector3) == 3 * sizeof(real_t)); + const Error err = read_reals(reinterpret_cast<real_t *>(w), f, len * 3); + ERR_FAIL_COND_V(err != OK, err); r_v = array; @@ -578,22 +598,19 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { Vector<Color> array; array.resize(len); Color *w = array.ptrw(); - if (sizeof(Color) == 16) { - f->get_buffer((uint8_t *)w, len * sizeof(real_t) * 4); + // Colors always use `float` even with double-precision support enabled + static_assert(sizeof(Color) == 4 * sizeof(float)); + f->get_buffer((uint8_t *)w, len * sizeof(float) * 4); #ifdef BIG_ENDIAN_ENABLED - { - uint32_t *ptr = (uint32_t *)w.ptr(); - for (int i = 0; i < len * 4; i++) { - ptr[i] = BSWAP32(ptr[i]); - } + { + uint32_t *ptr = (uint32_t *)w.ptr(); + for (int i = 0; i < len * 4; i++) { + ptr[i] = BSWAP32(ptr[i]); } + } #endif - } else { - ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Color size is NOT 16!"); - } - r_v = array; } break; default: { @@ -772,7 +789,7 @@ Error ResourceLoaderBinary::load() { resource_cache.push_back(res); if (main) { - f->close(); + f = Ref<FileAccess>(); resource = res; resource->set_as_translation_remapped(translation_remapped); error = OK; @@ -787,13 +804,13 @@ void ResourceLoaderBinary::set_translation_remapped(bool p_remapped) { translation_remapped = p_remapped; } -static void save_ustring(FileAccess *f, const String &p_string) { +static void save_ustring(Ref<FileAccess> f, const String &p_string) { CharString utf8 = p_string.utf8(); f->store_32(utf8.length() + 1); f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); } -static String get_ustring(FileAccess *f) { +static String get_ustring(Ref<FileAccess> f) { int len = f->get_32(); Vector<char> str_buf; str_buf.resize(len); @@ -817,7 +834,7 @@ String ResourceLoaderBinary::get_unicode_string() { return s; } -void ResourceLoaderBinary::get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types) { +void ResourceLoaderBinary::get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types) { open(p_f, false, true); if (error) { return; @@ -839,7 +856,7 @@ void ResourceLoaderBinary::get_dependencies(FileAccess *p_f, List<String> *p_dep } } -void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_keep_uuid_paths) { +void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p_keep_uuid_paths) { error = OK; f = p_f; @@ -847,11 +864,11 @@ void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_kee f->get_buffer(header, 4); if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') { // Compressed. - FileAccessCompressed *fac = memnew(FileAccessCompressed); + Ref<FileAccessCompressed> fac; + fac.instantiate(); error = fac->open_after_magic(f); if (error != OK) { - memdelete(fac); - f->close(); + f = Ref<FileAccess>(); ERR_FAIL_MSG("Failed to open binary resource file: " + local_path + "."); } f = fac; @@ -859,7 +876,7 @@ void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_kee } else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') { // Not normal. error = ERR_FILE_UNRECOGNIZED; - f->close(); + f = Ref<FileAccess>(); ERR_FAIL_MSG("Unrecognized binary resource file: " + local_path + "."); } @@ -884,7 +901,7 @@ void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_kee print_bl("format: " + itos(ver_format)); if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) { - f->close(); + f = Ref<FileAccess>(); ERR_FAIL_MSG(vformat("File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s).", local_path, ver_format, ver_major, ver_minor, VERSION_BRANCH)); } @@ -961,12 +978,11 @@ void ResourceLoaderBinary::open(FileAccess *p_f, bool p_no_resources, bool p_kee if (f->eof_reached()) { error = ERR_FILE_CORRUPT; - f->close(); ERR_FAIL_MSG("Premature end of file (EOF): " + local_path + "."); } } -String ResourceLoaderBinary::recognize(FileAccess *p_f) { +String ResourceLoaderBinary::recognize(Ref<FileAccess> p_f) { error = OK; f = p_f; @@ -974,11 +990,11 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) { f->get_buffer(header, 4); if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') { // Compressed. - FileAccessCompressed *fac = memnew(FileAccessCompressed); + Ref<FileAccessCompressed> fac; + fac.instantiate(); error = fac->open_after_magic(f); if (error != OK) { - memdelete(fac); - f->close(); + f = Ref<FileAccess>(); return ""; } f = fac; @@ -986,7 +1002,7 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) { } else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') { // Not normal. error = ERR_FILE_UNRECOGNIZED; - f->close(); + f = Ref<FileAccess>(); return ""; } @@ -1000,7 +1016,7 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) { uint32_t ver_format = f->get_32(); if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) { - f->close(); + f = Ref<FileAccess>(); return ""; } @@ -1009,19 +1025,13 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) { return type; } -ResourceLoaderBinary::~ResourceLoaderBinary() { - if (f) { - memdelete(f); - } -} - RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_FILE_CANT_OPEN; } Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot open file '" + p_path + "'."); @@ -1079,8 +1089,8 @@ bool ResourceFormatLoaderBinary::handles_type(const String &p_type) const { } void ResourceFormatLoaderBinary::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file '" + p_path + "'."); ResourceLoaderBinary loader; loader.local_path = ProjectSettings::get_singleton()->localize_path(p_path); @@ -1089,10 +1099,10 @@ void ResourceFormatLoaderBinary::get_dependencies(const String &p_path, List<Str } Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, const Map<String, String> &p_map) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file '" + p_path + "'."); - FileAccess *fw = nullptr; + Ref<FileAccess> fw; String local_path = p_path.get_base_dir(); @@ -1100,36 +1110,26 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons f->get_buffer(header, 4); if (header[0] == 'R' && header[1] == 'S' && header[2] == 'C' && header[3] == 'C') { // Compressed. - FileAccessCompressed *fac = memnew(FileAccessCompressed); + Ref<FileAccessCompressed> fac; + fac.instantiate(); Error err = fac->open_after_magic(f); - if (err != OK) { - memdelete(fac); - memdelete(f); - ERR_FAIL_V_MSG(err, "Cannot open file '" + p_path + "'."); - } + ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'."); f = fac; - FileAccessCompressed *facw = memnew(FileAccessCompressed); + Ref<FileAccessCompressed> facw; + facw.instantiate(); facw->configure("RSCC"); err = facw->_open(p_path + ".depren", FileAccess::WRITE); - if (err) { - memdelete(fac); - memdelete(facw); - ERR_FAIL_COND_V_MSG(err, ERR_FILE_CORRUPT, "Cannot create file '" + p_path + ".depren'."); - } + ERR_FAIL_COND_V_MSG(err, ERR_FILE_CORRUPT, "Cannot create file '" + p_path + ".depren'."); fw = facw; } else if (header[0] != 'R' || header[1] != 'S' || header[2] != 'R' || header[3] != 'C') { // Not normal. - memdelete(f); ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unrecognized binary resource file '" + local_path + "'."); } else { fw = FileAccess::open(p_path + ".depren", FileAccess::WRITE); - if (!fw) { - memdelete(f); - } - ERR_FAIL_COND_V_MSG(!fw, ERR_CANT_CREATE, "Cannot create file '" + p_path + ".depren'."); + ERR_FAIL_COND_V_MSG(fw.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + ".depren'."); uint8_t magic[4] = { 'R', 'S', 'R', 'C' }; fw->store_buffer(magic, 4); @@ -1152,10 +1152,8 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons uint32_t ver_format = f->get_32(); if (ver_format < FORMAT_VERSION_CAN_RENAME_DEPS) { - memdelete(f); - memdelete(fw); { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); da->remove(p_path + ".depren"); } @@ -1184,8 +1182,6 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons } if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) { - memdelete(f); - memdelete(fw); ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, vformat("File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s).", local_path, ver_format, ver_major, ver_minor, VERSION_BRANCH)); @@ -1294,22 +1290,19 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons fw->seek(md_ofs); fw->store_64(importmd_ofs + size_diff); - memdelete(f); - memdelete(fw); - if (!all_ok) { return ERR_CANT_CREATE; } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); da->remove(p_path); da->rename(p_path + ".depren", p_path); return OK; } String ResourceFormatLoaderBinary::get_resource_type(const String &p_path) const { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { return ""; //could not read } @@ -1326,8 +1319,8 @@ ResourceUID::ID ResourceFormatLoaderBinary::get_resource_uid(const String &p_pat return ResourceUID::INVALID_ID; } - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { return ResourceUID::INVALID_ID; //could not read } @@ -1345,7 +1338,7 @@ ResourceUID::ID ResourceFormatLoaderBinary::get_resource_uid(const String &p_pat /////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// -void ResourceFormatSaverBinaryInstance::_pad_buffer(FileAccess *f, int p_bytes) { +void ResourceFormatSaverBinaryInstance::_pad_buffer(Ref<FileAccess> f, int p_bytes) { int extra = 4 - (p_bytes % 4); if (extra < 4) { for (int i = 0; i < extra; i++) { @@ -1354,7 +1347,7 @@ void ResourceFormatSaverBinaryInstance::_pad_buffer(FileAccess *f, int p_bytes) } } -void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Variant &p_property, Map<RES, int> &resource_map, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint) { +void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const Variant &p_property, Map<RES, int> &resource_map, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint) { switch (p_property.get_type()) { case Variant::NIL: { f->store_32(VARIANT_NIL); @@ -1813,14 +1806,14 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant } } -void ResourceFormatSaverBinaryInstance::save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len) { +void ResourceFormatSaverBinaryInstance::save_unicode_string(Ref<FileAccess> p_f, const String &p_string, bool p_bit_on_len) { CharString utf8 = p_string.utf8(); if (p_bit_on_len) { - f->store_32((utf8.length() + 1) | 0x80000000); + p_f->store_32((utf8.length() + 1) | 0x80000000); } else { - f->store_32(utf8.length() + 1); + p_f->store_32(utf8.length() + 1); } - f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); + p_f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); } int ResourceFormatSaverBinaryInstance::get_string_index(const String &p_string) { @@ -1836,15 +1829,13 @@ int ResourceFormatSaverBinaryInstance::get_string_index(const String &p_string) Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { Error err; + Ref<FileAccess> f; if (p_flags & ResourceSaver::FLAG_COMPRESS) { - FileAccessCompressed *fac = memnew(FileAccessCompressed); + Ref<FileAccessCompressed> fac; + fac.instantiate(); fac->configure("RSCC"); f = fac; err = fac->_open(p_path, FileAccess::WRITE); - if (err) { - memdelete(f); - } - } else { f = FileAccess::open(p_path, FileAccess::WRITE, &err); } @@ -1885,8 +1876,6 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p f->store_32(FORMAT_VERSION); if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) { - f->close(); - memdelete(f); return ERR_CANT_CREATE; } @@ -2044,14 +2033,9 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p f->store_buffer((const uint8_t *)"RSRC", 4); //magic at end if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) { - f->close(); - memdelete(f); return ERR_CANT_CREATE; } - f->close(); - memdelete(f); - return OK; } diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index 5403168a53..72a3c6751d 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -43,7 +43,7 @@ class ResourceLoaderBinary { Ref<Resource> resource; uint32_t ver_format = 0; - FileAccess *f = nullptr; + Ref<FileAccess> f; uint64_t importmd_ofs = 0; @@ -98,12 +98,11 @@ public: void set_translation_remapped(bool p_remapped); void set_remaps(const Map<String, String> &p_remaps) { remaps = p_remaps; } - void open(FileAccess *p_f, bool p_no_resources = false, bool p_keep_uuid_paths = false); - String recognize(FileAccess *p_f); - void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types); + void open(Ref<FileAccess> p_f, bool p_no_resources = false, bool p_keep_uuid_paths = false); + String recognize(Ref<FileAccess> p_f); + void get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types); ResourceLoaderBinary() {} - ~ResourceLoaderBinary(); }; class ResourceFormatLoaderBinary : public ResourceFormatLoader { @@ -127,7 +126,6 @@ class ResourceFormatSaverBinaryInstance { bool skip_editor; bool big_endian; bool takeover_paths; - FileAccess *f = nullptr; String magic; Set<RES> resource_set; @@ -155,9 +153,9 @@ class ResourceFormatSaverBinaryInstance { List<Property> properties; }; - static void _pad_buffer(FileAccess *f, int p_bytes); + static void _pad_buffer(Ref<FileAccess> f, int p_bytes); void _find_resources(const Variant &p_variant, bool p_main = false); - static void save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len = false); + static void save_unicode_string(Ref<FileAccess> f, const String &p_string, bool p_bit_on_len = false); int get_string_index(const String &p_string); public: @@ -170,7 +168,7 @@ public: RESERVED_FIELDS = 11 }; Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); - static void write_variant(FileAccess *f, const Variant &p_property, Map<RES, int> &resource_map, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint = PropertyInfo()); + static void write_variant(Ref<FileAccess> f, const Variant &p_property, Map<RES, int> &resource_map, Map<RES, int> &external_resources, Map<StringName, int> &string_map, const PropertyInfo &p_hint = PropertyInfo()); }; class ResourceFormatSaverBinary : public ResourceFormatSaver { diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index 9b6440e2a2..b4f73b3b25 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -40,9 +40,9 @@ bool ResourceFormatImporter::SortImporterByName::operator()(const Ref<ResourceIm Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid) const { Error err; - FileAccess *f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); - if (!f) { + if (f.is_null()) { if (r_valid) { *r_valid = false; } @@ -70,11 +70,9 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true); if (err == ERR_FILE_EOF) { - memdelete(f); return OK; } else if (err != OK) { ERR_PRINT("ResourceFormatImporter::load - " + p_path + ".import:" + itos(lines) + " error: " + error_text); - memdelete(f); return err; } @@ -110,8 +108,6 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy } } - memdelete(f); - if (r_path_and_type.path.is_empty() || r_path_and_type.type.is_empty()) { return ERR_FILE_CORRUPT; } @@ -270,9 +266,9 @@ String ResourceFormatImporter::get_internal_resource_path(const String &p_path) void ResourceFormatImporter::get_internal_resource_path_list(const String &p_path, List<String> *r_paths) { Error err; - FileAccess *f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); - if (!f) { + if (f.is_null()) { return; } @@ -292,11 +288,9 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, nullptr, true); if (err == ERR_FILE_EOF) { - memdelete(f); return; } else if (err != OK) { ERR_PRINT("ResourceFormatImporter::get_internal_resource_path_list - " + p_path + ".import:" + itos(lines) + " error: " + error_text); - memdelete(f); return; } @@ -310,7 +304,6 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat break; } } - memdelete(f); } String ResourceFormatImporter::get_import_group_file(const String &p_path) const { diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 2419c76dd3..fe9693aa20 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -206,7 +206,7 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c vformat("Failed loading resource: %s. Make sure resources have been imported by opening the project in the editor at least once.", p_path)); #ifdef TOOLS_ENABLED - FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES); + Ref<FileAccess> file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES); ERR_FAIL_COND_V_MSG(!file_check->file_exists(p_path), RES(), "Resource file not found: " + p_path + "."); #endif @@ -817,9 +817,8 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem if (new_path == p_path) { // Did not remap. // Try file remap. Error err; - FileAccess *f = FileAccess::open(p_path + ".remap", FileAccess::READ, &err); - - if (f) { + Ref<FileAccess> f = FileAccess::open(p_path + ".remap", FileAccess::READ, &err); + if (f.is_valid()) { VariantParser::StreamFile stream; stream.f = f; @@ -849,8 +848,6 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem break; } } - - memdelete(f); } } diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp index d0335bed3a..8f1f354e90 100644 --- a/core/io/resource_uid.cpp +++ b/core/io/resource_uid.cpp @@ -135,12 +135,12 @@ void ResourceUID::remove_id(ID p_id) { Error ResourceUID::save_to_cache() { String cache_file = get_cache_file(); if (!FileAccess::exists(cache_file)) { - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES); d->make_dir_recursive(String(cache_file).get_base_dir()); //ensure base dir exists } - FileAccessRef f = FileAccess::open(cache_file, FileAccess::WRITE); - if (!f) { + Ref<FileAccess> f = FileAccess::open(cache_file, FileAccess::WRITE); + if (f.is_null()) { return ERR_CANT_OPEN; } @@ -163,8 +163,8 @@ Error ResourceUID::save_to_cache() { } Error ResourceUID::load_from_cache() { - FileAccessRef f = FileAccess::open(get_cache_file(), FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(get_cache_file(), FileAccess::READ); + if (f.is_null()) { return ERR_CANT_OPEN; } @@ -201,12 +201,12 @@ Error ResourceUID::update_cache() { } MutexLock l(mutex); - FileAccess *f = nullptr; + Ref<FileAccess> f; for (OrderedHashMap<ID, Cache>::Element E = unique_ids.front(); E; E = E.next()) { if (!E.get().saved_to_cache) { - if (f == nullptr) { + if (f.is_null()) { f = FileAccess::open(get_cache_file(), FileAccess::READ_WRITE); //append - if (!f) { + if (f.is_null()) { return ERR_CANT_OPEN; } f->seek_end(); @@ -223,8 +223,6 @@ Error ResourceUID::update_cache() { if (f != nullptr) { f->seek(0); f->store_32(cache_entries); //update amount of entries - f->close(); - memdelete(f); } changed = false; diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 30df46a6b4..ae1ad304d7 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -34,7 +34,7 @@ #include "core/string/translation.h" #include "core/string/translation_po.h" -RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { +RES TranslationLoaderPO::load_translation(Ref<FileAccess> f, Error *r_error) { if (r_error) { *r_error = ERR_FILE_CORRUPT; } @@ -49,9 +49,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { uint16_t version_maj = f->get_16(); uint16_t version_min = f->get_16(); - if (version_maj > 1) { - ERR_FAIL_V_MSG(RES(), vformat("Unsupported MO file %s, version %d.%d.", path, version_maj, version_min)); - } + ERR_FAIL_COND_V_MSG(version_maj > 1, RES(), vformat("Unsupported MO file %s, version %d.%d.", path, version_maj, version_min)); uint32_t num_strings = f->get_32(); uint32_t id_table_offset = f->get_32(); @@ -134,7 +132,6 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { } } - memdelete(f); } else { // Try to load as text PO file. f->seek(0); @@ -173,7 +170,6 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { // If we reached last line and it's not a content line, break, otherwise let processing that last loop if (is_eof && l.is_empty()) { if (status == STATUS_READING_ID || status == STATUS_READING_CONTEXT || (status == STATUS_READING_PLURAL && plural_index != plural_forms - 1)) { - memdelete(f); ERR_FAIL_V_MSG(RES(), "Unexpected EOF while reading PO file at: " + path + ":" + itos(line)); } else { break; @@ -181,10 +177,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { } if (l.begins_with("msgctxt")) { - if (status != STATUS_READING_STRING && status != STATUS_READING_PLURAL) { - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Unexpected 'msgctxt', was expecting 'msgid_plural' or 'msgstr' before 'msgctxt' while parsing: " + path + ":" + itos(line)); - } + ERR_FAIL_COND_V_MSG(status != STATUS_READING_STRING && status != STATUS_READING_PLURAL, RES(), "Unexpected 'msgctxt', was expecting 'msgid_plural' or 'msgstr' before 'msgctxt' while parsing: " + path + ":" + itos(line)); // In PO file, "msgctxt" appears before "msgid". If we encounter a "msgctxt", we add what we have read // and set "entered_context" to true to prevent adding twice. @@ -192,10 +185,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { if (status == STATUS_READING_STRING) { translation->add_message(msg_id, msg_str, msg_context); } else if (status == STATUS_READING_PLURAL) { - if (plural_index != plural_forms - 1) { - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); - } + ERR_FAIL_COND_V_MSG(plural_index != plural_forms - 1, RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); translation->add_plural_message(msg_id, msgs_plural, msg_context); } } @@ -207,10 +197,8 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { if (l.begins_with("msgid_plural")) { if (plural_forms == 0) { - memdelete(f); ERR_FAIL_V_MSG(RES(), "PO file uses 'msgid_plural' but 'Plural-Forms' is invalid or missing in header: " + path + ":" + itos(line)); } else if (status != STATUS_READING_ID) { - memdelete(f); ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid_plural', was expecting 'msgid' before 'msgid_plural' while parsing: " + path + ":" + itos(line)); } // We don't record the message in "msgid_plural" itself as tr_n(), TTRN(), RTRN() interfaces provide the plural string already. @@ -221,20 +209,14 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { msgs_plural.resize(plural_forms); status = STATUS_READING_PLURAL; } else if (l.begins_with("msgid")) { - if (status == STATUS_READING_ID) { - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Unexpected 'msgid', was expecting 'msgstr' while parsing: " + path + ":" + itos(line)); - } + ERR_FAIL_COND_V_MSG(status == STATUS_READING_ID, RES(), "Unexpected 'msgid', was expecting 'msgstr' while parsing: " + path + ":" + itos(line)); if (!msg_id.is_empty()) { if (!skip_this && !entered_context) { if (status == STATUS_READING_STRING) { translation->add_message(msg_id, msg_str, msg_context); } else if (status == STATUS_READING_PLURAL) { - if (plural_index != plural_forms - 1) { - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); - } + ERR_FAIL_COND_V_MSG(plural_index != plural_forms - 1, RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); translation->add_plural_message(msg_id, msgs_plural, msg_context); } } @@ -263,18 +245,11 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { } if (l.begins_with("msgstr[")) { - if (status != STATUS_READING_PLURAL) { - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr[]', was expecting 'msgid_plural' before 'msgstr[]' while parsing: " + path + ":" + itos(line)); - } + ERR_FAIL_COND_V_MSG(status != STATUS_READING_PLURAL, RES(), "Unexpected 'msgstr[]', was expecting 'msgid_plural' before 'msgstr[]' while parsing: " + path + ":" + itos(line)); plural_index++; // Increment to add to the next slot in vector msgs_plural. l = l.substr(9, l.length()).strip_edges(); } else if (l.begins_with("msgstr")) { - if (status != STATUS_READING_ID) { - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Unexpected 'msgstr', was expecting 'msgid' before 'msgstr' while parsing: " + path + ":" + itos(line)); - } - + ERR_FAIL_COND_V_MSG(status != STATUS_READING_ID, RES(), "Unexpected 'msgstr', was expecting 'msgid' before 'msgstr' while parsing: " + path + ":" + itos(line)); l = l.substr(6, l.length()).strip_edges(); status = STATUS_READING_STRING; } @@ -287,10 +262,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { continue; // Nothing to read or comment. } - if (!l.begins_with("\"") || status == STATUS_NONE) { - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Invalid line '" + l + "' while parsing: " + path + ":" + itos(line)); - } + ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, RES(), "Invalid line '" + l + "' while parsing: " + path + ":" + itos(line)); l = l.substr(1, l.length()); // Find final quote, ignoring escaped ones (\"). @@ -312,10 +284,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { escape_next = false; } - if (end_pos == -1) { - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Expected '\"' at end of message while parsing: " + path + ":" + itos(line)); - } + ERR_FAIL_COND_V_MSG(end_pos == -1, RES(), "Expected '\"' at end of message while parsing: " + path + ":" + itos(line)); l = l.substr(0, end_pos); l = l.c_unescape(); @@ -327,18 +296,13 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { } else if (status == STATUS_READING_CONTEXT) { msg_context += l; } else if (status == STATUS_READING_PLURAL && plural_index >= 0) { - if (plural_index >= plural_forms) { - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Unexpected plural form while parsing: " + path + ":" + itos(line)); - } + ERR_FAIL_COND_V_MSG(plural_index >= plural_forms, RES(), "Unexpected plural form while parsing: " + path + ":" + itos(line)); msgs_plural.write[plural_index] = msgs_plural[plural_index] + l; } line++; } - memdelete(f); - // Add the last set of data from last iteration. if (status == STATUS_READING_STRING) { if (!msg_id.is_empty()) { @@ -350,10 +314,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) { } } else if (status == STATUS_READING_PLURAL) { if (!skip_this && !msg_id.is_empty()) { - if (plural_index != plural_forms - 1) { - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); - } + ERR_FAIL_COND_V_MSG(plural_index != plural_forms - 1, RES(), "Number of 'msgstr[]' doesn't match with number of plural forms: " + path + ":" + itos(line)); translation->add_plural_message(msg_id, msgs_plural, msg_context); } } @@ -388,8 +349,8 @@ RES TranslationLoaderPO::load(const String &p_path, const String &p_original_pat *r_error = ERR_CANT_OPEN; } - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, RES(), "Cannot open file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), RES(), "Cannot open file '" + p_path + "'."); return load_translation(f, r_error); } diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h index 1c58896a00..7da361cf24 100644 --- a/core/io/translation_loader_po.h +++ b/core/io/translation_loader_po.h @@ -37,7 +37,7 @@ class TranslationLoaderPO : public ResourceFormatLoader { public: - static RES load_translation(FileAccess *f, Error *r_error = nullptr); + static RES load_translation(Ref<FileAccess> f, Error *r_error = nullptr); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index 360da46f96..7b43193f47 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -472,7 +472,7 @@ Error XMLParser::open_buffer(const Vector<uint8_t> &p_buffer) { Error XMLParser::open(const String &p_path) { Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'."); @@ -488,8 +488,6 @@ Error XMLParser::open(const String &p_path) { data[length] = 0; P = data; - memdelete(file); - return OK; } diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp index 2c4f8346ab..2cc844b628 100644 --- a/core/io/zip_io.cpp +++ b/core/io/zip_io.cpp @@ -30,73 +30,69 @@ #include "zip_io.h" -void *zipio_open(void *data, const char *p_fname, int mode) { - FileAccess *&f = *(FileAccess **)data; +void *zipio_open(voidpf opaque, const char *p_fname, int mode) { + ZipIOData *zd = (ZipIOData *)opaque; String fname; fname.parse_utf8(p_fname); if (mode & ZLIB_FILEFUNC_MODE_WRITE) { - f = FileAccess::open(fname, FileAccess::WRITE); + zd->f = FileAccess::open(fname, FileAccess::WRITE); } else { - f = FileAccess::open(fname, FileAccess::READ); + zd->f = FileAccess::open(fname, FileAccess::READ); } - if (!f) { + if (zd->f.is_null()) { return nullptr; } - return data; + return opaque; } -uLong zipio_read(void *data, void *fdata, void *buf, uLong size) { - FileAccess *f = *(FileAccess **)data; - return f->get_buffer((uint8_t *)buf, size); +uLong zipio_read(voidpf opaque, voidpf stream, void *buf, uLong size) { + ZipIOData *zd = (ZipIOData *)opaque; + return zd->f->get_buffer((uint8_t *)buf, size); } uLong zipio_write(voidpf opaque, voidpf stream, const void *buf, uLong size) { - FileAccess *f = *(FileAccess **)opaque; - f->store_buffer((uint8_t *)buf, size); + ZipIOData *zd = (ZipIOData *)opaque; + zd->f->store_buffer((uint8_t *)buf, size); return size; } long zipio_tell(voidpf opaque, voidpf stream) { - FileAccess *f = *(FileAccess **)opaque; - return f->get_position(); + ZipIOData *zd = (ZipIOData *)opaque; + return zd->f->get_position(); } long zipio_seek(voidpf opaque, voidpf stream, uLong offset, int origin) { - FileAccess *f = *(FileAccess **)opaque; + ZipIOData *zd = (ZipIOData *)opaque; uint64_t pos = offset; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR: - pos = f->get_position() + offset; + pos = zd->f->get_position() + offset; break; case ZLIB_FILEFUNC_SEEK_END: - pos = f->get_length() + offset; + pos = zd->f->get_length() + offset; break; default: break; } - f->seek(pos); + zd->f->seek(pos); return 0; } int zipio_close(voidpf opaque, voidpf stream) { - FileAccess *&f = *(FileAccess **)opaque; - if (f) { - f->close(); - memdelete(f); - f = nullptr; - } + ZipIOData *zd = (ZipIOData *)opaque; + memdelete(zd); return 0; } int zipio_testerror(voidpf opaque, voidpf stream) { - FileAccess *f = *(FileAccess **)opaque; - return (f && f->get_error() != OK) ? 1 : 0; + ZipIOData *zd = (ZipIOData *)opaque; + return (zd->f.is_valid() && zd->f->get_error() != OK) ? 1 : 0; } voidpf zipio_alloc(voidpf opaque, uInt items, uInt size) { @@ -109,9 +105,9 @@ void zipio_free(voidpf opaque, voidpf address) { memfree(address); } -zlib_filefunc_def zipio_create_io_from_file(FileAccess **p_file) { +zlib_filefunc_def zipio_create_io() { zlib_filefunc_def io; - io.opaque = p_file; + io.opaque = (void *)memnew(ZipIOData); io.zopen_file = zipio_open; io.zread_file = zipio_read; io.zwrite_file = zipio_write; diff --git a/core/io/zip_io.h b/core/io/zip_io.h index 6a29703449..3bcd1f830d 100644 --- a/core/io/zip_io.h +++ b/core/io/zip_io.h @@ -39,8 +39,12 @@ #include "thirdparty/minizip/unzip.h" #include "thirdparty/minizip/zip.h" -void *zipio_open(void *data, const char *p_fname, int mode); -uLong zipio_read(void *data, void *fdata, void *buf, uLong size); +struct ZipIOData { + Ref<FileAccess> f; +}; + +void *zipio_open(voidpf opaque, const char *p_fname, int mode); +uLong zipio_read(voidpf opaque, voidpf stream, void *buf, uLong size); uLong zipio_write(voidpf opaque, voidpf stream, const void *buf, uLong size); long zipio_tell(voidpf opaque, voidpf stream); @@ -53,6 +57,6 @@ int zipio_testerror(voidpf opaque, voidpf stream); voidpf zipio_alloc(voidpf opaque, uInt items, uInt size); void zipio_free(voidpf opaque, voidpf address); -zlib_filefunc_def zipio_create_io_from_file(FileAccess **p_file); +zlib_filefunc_def zipio_create_io(); #endif // ZIP_IO_H diff --git a/core/object/object.cpp b/core/object/object.cpp index c2cd42ff91..897b5d18de 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1848,6 +1848,13 @@ Object::Object() { _construct_object(false); } +void Object::detach_from_objectdb() { + if (_instance_id != ObjectID()) { + ObjectDB::remove_instance(this); + _instance_id = ObjectID(); + } +} + Object::~Object() { if (script_instance) { memdelete(script_instance); @@ -1887,8 +1894,10 @@ Object::~Object() { c.signal.get_object()->_disconnect(c.signal.get_name(), c.callable, true); } - ObjectDB::remove_instance(this); - _instance_id = ObjectID(); + if (_instance_id != ObjectID()) { + ObjectDB::remove_instance(this); + _instance_id = ObjectID(); + } _predelete_ok = 2; if (_instance_bindings != nullptr) { diff --git a/core/object/object.h b/core/object/object.h index eeef03dcb9..c3e3c68b59 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -633,6 +633,7 @@ public: bool _is_gpl_reversed() const { return false; } + void detach_from_objectdb(); _FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; } template <class T> diff --git a/core/os/os.cpp b/core/os/os.cpp index 2e5db145a4..bf6cd4c9ab 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -80,7 +80,9 @@ void OS::print_error(const char *p_function, const char *p_file, int p_line, con return; } - _logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_editor_notify, p_type); + if (_logger) { + _logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_editor_notify, p_type); + } } void OS::print(const char *p_format, ...) { @@ -91,7 +93,9 @@ void OS::print(const char *p_format, ...) { va_list argp; va_start(argp, p_format); - _logger->logv(p_format, argp, false); + if (_logger) { + _logger->logv(p_format, argp, false); + } va_end(argp); } @@ -104,7 +108,9 @@ void OS::printerr(const char *p_format, ...) { va_list argp; va_start(argp, p_format); - _logger->logv(p_format, argp, true); + if (_logger) { + _logger->logv(p_format, argp, true); + } va_end(argp); } @@ -173,7 +179,7 @@ void OS::dump_memory_to_file(const char *p_file) { //Memory::dump_static_mem_to_file(p_file); } -static FileAccess *_OSPRF = nullptr; +static Ref<FileAccess> _OSPRF; static void _OS_printres(Object *p_obj) { Resource *res = Object::cast_to<Resource>(p_obj); @@ -182,7 +188,7 @@ static void _OS_printres(Object *p_obj) { } String str = vformat("%s - %s - %s", res->to_string(), res->get_name(), res->get_path()); - if (_OSPRF) { + if (_OSPRF.is_valid()) { _OSPRF->store_line(str); } else { print_line(str); @@ -190,24 +196,19 @@ static void _OS_printres(Object *p_obj) { } void OS::print_all_resources(String p_to_file) { - ERR_FAIL_COND(!p_to_file.is_empty() && _OSPRF); + 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 = nullptr; + _OSPRF = Ref<FileAccess>(); ERR_FAIL_MSG("Can't print all resources to file: " + String(p_to_file) + "."); } } ObjectDB::debug_objects(_OS_printres); - if (!p_to_file.is_empty()) { - if (_OSPRF) { - memdelete(_OSPRF); - } - _OSPRF = nullptr; - } + _OSPRF = Ref<FileAccess>(); } void OS::print_resources_in_use(bool p_short) { @@ -332,7 +333,7 @@ void OS::ensure_user_data_dir() { return; } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Error err = da->make_dir_recursive(dd); ERR_FAIL_COND_MSG(err != OK, "Error attempting to create data dir: " + dd + "."); } @@ -550,6 +551,8 @@ OS::OS() { } OS::~OS() { - memdelete(_logger); + if (_logger) { + memdelete(_logger); + } singleton = nullptr; } diff --git a/core/string/print_string.h b/core/string/print_string.h index f19573ad45..f7d0f25030 100644 --- a/core/string/print_string.h +++ b/core/string/print_string.h @@ -61,6 +61,14 @@ extern bool _print_error_enabled; extern void __print_line(String p_string); extern void print_error(String p_string); extern void print_verbose(String p_string); -#define print_line(...) __print_line(stringify_variants(__VA_ARGS__)) + +inline void print_line(Variant v) { + __print_line(stringify_variants(v)); +} + +template <typename... Args> +void print_line(Variant p_var, Args... p_args) { + __print_line(stringify_variants(p_var, p_args...)); +} #endif // PRINT_STRING_H diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp index 1c991ee12d..3f94e064ec 100644 --- a/core/string/translation_po.cpp +++ b/core/string/translation_po.cpp @@ -35,7 +35,7 @@ #ifdef DEBUG_TRANSLATION_PO void TranslationPO::print_translation_map() { Error err; - FileAccess *file = FileAccess::open("translation_map_print_test.txt", FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open("translation_map_print_test.txt", FileAccess::WRITE, &err); if (err != OK) { ERR_PRINT("Failed to open translation_map_print_test.txt"); return; @@ -62,7 +62,6 @@ void TranslationPO::print_translation_map() { file->store_line(""); } } - file->close(); } #endif diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h index b297babd6f..07d89d30cb 100644 --- a/core/variant/variant_parser.h +++ b/core/variant/variant_parser.h @@ -49,7 +49,7 @@ public: }; struct StreamFile : public Stream { - FileAccess *f = nullptr; + Ref<FileAccess> f; virtual char32_t get_char() override; virtual bool is_utf8() const override; diff --git a/doc/classes/AnimationLibrary.xml b/doc/classes/AnimationLibrary.xml new file mode 100644 index 0000000000..0a731edadd --- /dev/null +++ b/doc/classes/AnimationLibrary.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AnimationLibrary" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_animation"> + <return type="int" enum="Error" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="animation" type="Animation" /> + <description> + </description> + </method> + <method name="get_animation" qualifiers="const"> + <return type="Animation" /> + <argument index="0" name="name" type="StringName" /> + <description> + </description> + </method> + <method name="get_animation_list" qualifiers="const"> + <return type="StringName[]" /> + <description> + </description> + </method> + <method name="has_animation" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="name" type="StringName" /> + <description> + </description> + </method> + <method name="remove_animation"> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <description> + </description> + </method> + <method name="rename_animation"> + <return type="void" /> + <argument index="0" name="name" type="StringName" /> + <argument index="1" name="newname" type="StringName" /> + <description> + </description> + </method> + </methods> + <members> + <member name="_data" type="Dictionary" setter="_set_data" getter="_get_data" default="{}"> + </member> + </members> + <signals> + <signal name="animation_added"> + <argument index="0" name="name" type="Animation" /> + <description> + </description> + </signal> + <signal name="animation_removed"> + <argument index="0" name="name" type="Animation" /> + <description> + </description> + </signal> + <signal name="animation_renamed"> + <argument index="0" name="name" type="Animation" /> + <argument index="1" name="to_name" type="Animation" /> + <description> + </description> + </signal> + </signals> +</class> diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index b1d04ce1f2..625cf3c47c 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -14,12 +14,11 @@ <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link> </tutorials> <methods> - <method name="add_animation"> + <method name="add_animation_library"> <return type="int" enum="Error" /> <argument index="0" name="name" type="StringName" /> - <argument index="1" name="animation" type="Animation" /> + <argument index="1" name="library" type="AnimationLibrary" /> <description> - Adds [code]animation[/code] to the player accessible with the key [code]name[/code]. </description> </method> <method name="advance"> @@ -63,6 +62,12 @@ Returns the name of [code]animation[/code] or an empty string if not found. </description> </method> + <method name="find_animation_library" qualifiers="const"> + <return type="StringName" /> + <argument index="0" name="animation" type="Animation" /> + <description> + </description> + </method> <method name="get_animation" qualifiers="const"> <return type="Animation" /> <argument index="0" name="name" type="StringName" /> @@ -70,6 +75,17 @@ Returns the [Animation] with key [code]name[/code] or [code]null[/code] if not found. </description> </method> + <method name="get_animation_library" qualifiers="const"> + <return type="AnimationLibrary" /> + <argument index="0" name="name" type="StringName" /> + <description> + </description> + </method> + <method name="get_animation_library_list" qualifiers="const"> + <return type="StringName[]" /> + <description> + </description> + </method> <method name="get_animation_list" qualifiers="const"> <return type="PackedStringArray" /> <description> @@ -103,6 +119,12 @@ Returns [code]true[/code] if the [AnimationPlayer] stores an [Animation] with key [code]name[/code]. </description> </method> + <method name="has_animation_library" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="name" type="StringName" /> + <description> + </description> + </method> <method name="is_playing" qualifiers="const"> <return type="bool" /> <description> @@ -138,19 +160,17 @@ [b]Note:[/b] If a looped animation is currently playing, the queued animation will never play unless the looped animation is stopped somehow. </description> </method> - <method name="remove_animation"> + <method name="remove_animation_library"> <return type="void" /> <argument index="0" name="name" type="StringName" /> <description> - Removes the animation with key [code]name[/code]. </description> </method> - <method name="rename_animation"> + <method name="rename_animation_library"> <return type="void" /> <argument index="0" name="name" type="StringName" /> <argument index="1" name="newname" type="StringName" /> <description> - Renames an existing animation with key [code]name[/code] to [code]newname[/code]. </description> </method> <method name="seek"> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 5205a1db3b..baaf33956f 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -480,9 +480,6 @@ <member name="show_behind_parent" type="bool" setter="set_draw_behind_parent" getter="is_draw_behind_parent_enabled" default="false"> If [code]true[/code], the object draws behind its parent. </member> - <member name="show_on_top" type="bool" setter="_set_on_top" getter="_is_on_top"> - If [code]true[/code], the object draws on top of its parent. - </member> <member name="texture_filter" type="int" setter="set_texture_filter" getter="get_texture_filter" enum="CanvasItem.TextureFilter" default="0"> The texture filtering mode to use on this [CanvasItem]. </member> diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml index 28060f6579..63d493248f 100644 --- a/doc/classes/CharacterBody2D.xml +++ b/doc/classes/CharacterBody2D.xml @@ -183,7 +183,7 @@ If [code]true[/code], during a jump against the ceiling, the body will slide, if [code]false[/code] it will be stopped and will fall vertically. </member> <member name="up_direction" type="Vector2" setter="set_up_direction" getter="get_up_direction" default="Vector2(0, -1)"> - Direction vector used to determine what is a wall and what is a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. Defaults to [code]Vector2.UP[/code]. If set to [code]Vector2(0, 0)[/code], everything is considered a wall. This is useful for topdown games. + Vector pointing upwards, used to determine what is a wall and what is a floor (or a ceiling) when calling [method move_and_slide]. Defaults to [code]Vector2.UP[/code]. As the vector will be normalized it can't be equal to [constant Vector2.ZERO], if you want all collisions to be reported as walls, consider using [constant MOTION_MODE_FLOATING] as [member motion_mode]. </member> <member name="velocity" type="Vector2" setter="set_velocity" getter="get_velocity" default="Vector2(0, 0)"> Current velocity vector in pixels per second, used and modified during calls to [method move_and_slide]. diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml index 4895e2cff7..6c5cd62fe1 100644 --- a/doc/classes/CharacterBody3D.xml +++ b/doc/classes/CharacterBody3D.xml @@ -168,7 +168,7 @@ If [code]true[/code], during a jump against the ceiling, the body will slide, if [code]false[/code] it will be stopped and will fall vertically. </member> <member name="up_direction" type="Vector3" setter="set_up_direction" getter="get_up_direction" default="Vector3(0, 1, 0)"> - Direction vector used to determine what is a wall and what is a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. Defaults to [code]Vector3.UP[/code]. If set to [code]Vector3(0, 0, 0)[/code], everything is considered a wall. This is useful for topdown games. + Vector pointing upwards, used to determine what is a wall and what is a floor (or a ceiling) when calling [method move_and_slide]. Defaults to [code]Vector3.UP[/code]. As the vector will be normalized it can't be equal to [constant Vector3.ZERO], if you want all collisions to be reported as walls, consider using [constant MOTION_MODE_FLOATING] as [member motion_mode]. </member> <member name="velocity" type="Vector3" setter="set_velocity" getter="get_velocity" default="Vector3(0, 0, 0)"> Current velocity vector (typically meters per second), used and modified during calls to [method move_and_slide]. diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml index 25e41116a2..b7145ab923 100644 --- a/doc/classes/OptionButton.xml +++ b/doc/classes/OptionButton.xml @@ -30,8 +30,9 @@ </method> <method name="add_separator"> <return type="void" /> + <argument index="0" name="text" type="String" default="""" /> <description> - Adds a separator to the list of items. Separators help to group items. Separator also takes up an index and is appended at the end. + Adds a separator to the list of items. Separators help to group items, and can optionally be given a [code]text[/code] header. A separator also gets an index assigned, and is appended at the end of the item list. </description> </method> <method name="clear"> @@ -89,6 +90,12 @@ [b]Warning:[/b] This is a required internal node, removing and freeing it may cause a crash. If you wish to hide it or any of its children, use their [member Window.visible] property. </description> </method> + <method name="get_selectable_item" qualifiers="const"> + <return type="int" /> + <argument index="0" name="from_last" type="bool" default="false" /> + <description> + </description> + </method> <method name="get_selected_id" qualifiers="const"> <return type="int" /> <description> @@ -101,6 +108,11 @@ Gets the metadata of the selected item. Metadata for items can be set using [method set_item_metadata]. </description> </method> + <method name="has_selectable_items" qualifiers="const"> + <return type="bool" /> + <description> + </description> + </method> <method name="is_item_disabled" qualifiers="const"> <return type="bool" /> <argument index="0" name="idx" type="int" /> @@ -108,6 +120,12 @@ Returns [code]true[/code] if the item at index [code]idx[/code] is disabled. </description> </method> + <method name="is_item_separator" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="idx" type="int" /> + <description> + </description> + </method> <method name="remove_item"> <return type="void" /> <argument index="0" name="idx" type="int" /> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index a882a6c66f..b572ad2ed8 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -376,6 +376,13 @@ Scrolls the window's top line to match first line of the [code]paragraph[/code]. </description> </method> + <method name="select_all"> + <return type="void" /> + <description> + Select all the text. + If [member selection_enabled] is [code]false[/code], no selection will occur. + </description> + </method> <method name="set_cell_border_color"> <return type="void" /> <argument index="0" name="color" type="Color" /> diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index b4339bef11..9ef800d7e1 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -1249,9 +1249,9 @@ <method name="shaped_text_get_word_breaks" qualifiers="const"> <return type="PackedInt32Array" /> <argument index="0" name="shaped" type="RID" /> - <argument index="1" name="grapheme_flags" type="int" /> + <argument index="1" name="grapheme_flags" type="int" default="264" /> <description> - Breaks text into words and returns array of character ranges. + Breaks text into words and returns array of character ranges. Use [code]grapheme_flags[/code] to set what characters are used for breaking (see [enum GraphemeFlag]). </description> </method> <method name="shaped_text_hit_test_grapheme" qualifiers="const"> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index b8c39bee49..5abec4b437 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -179,8 +179,9 @@ <return type="Rect2" /> <argument index="0" name="item" type="TreeItem" /> <argument index="1" name="column" type="int" default="-1" /> + <argument index="2" name="button_index" type="int" default="-1" /> <description> - Returns the rectangle area for the specified [TreeItem]. If [code]column[/code] is specified, only get the position and size of that column, otherwise get the rectangle containing all columns. + Returns the rectangle area for the specified [TreeItem]. If [code]column[/code] is specified, only get the position and size of that column, otherwise get the rectangle containing all columns. If a button index is specified, the rectangle of that button will be returned. </description> </method> <method name="get_item_at_position" qualifiers="const"> diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 9853f906bc..87a65db192 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -349,6 +349,15 @@ <argument index="0" name="files" type="PackedStringArray" /> <description> Emitted when files are dragged from the OS file manager and dropped in the game window. The argument is a list of file paths. + Note that this method only works with non-embedded windows, i.e. the main window and [Window]-derived nodes when [member Viewport.gui_embed_subwindows] is disabled in the main viewport. + Example usage: + [codeblock] + func _ready(): + get_viewport().files_dropped.connect(on_files_dropped) + + func on_files_dropped(files): + print(files) + [/codeblock] </description> </signal> <signal name="focus_entered"> diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py index 365beb434b..eba4cee33a 100755 --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -58,7 +58,7 @@ strings_l10n = {} def print_error(error, state): # type: (str, State) -> None print("ERROR: {}".format(error)) - state.errored = True + state.num_errors += 1 class TypeName: @@ -163,8 +163,7 @@ class ClassDef: class State: def __init__(self): # type: () -> None - # Has any error been reported? - self.errored = False + self.num_errors = 0 self.classes = OrderedDict() # type: OrderedDict[str, ClassDef] self.current_class = "" # type: str @@ -194,7 +193,7 @@ class State: property_name = property.attrib["name"] if property_name in class_def.properties: - print_error("Duplicate property '{}', file: {}".format(property_name, class_name), self) + print_error('{}.xml: Duplicate property "{}".'.format(class_name, property_name), self) continue type_name = TypeName.from_element(property) @@ -305,7 +304,7 @@ class State: constant_def = ConstantDef(constant_name, value, constant.text) if enum is None: if constant_name in class_def.constants: - print_error("Duplicate constant '{}', file: {}".format(constant_name, class_name), self) + print_error('{}.xml: Duplicate constant "{}".'.format(class_name, constant_name), self) continue class_def.constants[constant_name] = constant_def @@ -328,7 +327,7 @@ class State: signal_name = signal.attrib["name"] if signal_name in class_def.signals: - print_error("Duplicate signal '{}', file: {}".format(signal_name, class_name), self) + print_error('{}.xml: Duplicate signal "{}".'.format(class_name, signal_name), self) continue params = parse_arguments(signal) @@ -351,8 +350,8 @@ class State: theme_item_id = "{}_{}".format(theme_item_data_name, theme_item_name) if theme_item_id in class_def.theme_items: print_error( - "Duplicate theme property '{}' of type '{}', file: {}".format( - theme_item_name, theme_item_data_name, class_name + '{}.xml: Duplicate theme item "{}" of type "{}".'.format( + class_name, theme_item_name, theme_item_data_name ), self, ) @@ -430,7 +429,7 @@ def main(): # type: () -> None if entry.msgid in BASE_STRINGS: strings_l10n[entry.msgid] = entry.msgstr else: - print("No PO file at '{}' for language '{}'.".format(lang_file, args.lang)) + print('No PO file at "{}" for language "{}".'.format(lang_file, args.lang)) print("Checking for errors in the XML class reference...") @@ -453,7 +452,7 @@ def main(): # type: () -> None elif os.path.isfile(path): if not path.endswith(".xml"): - print("Got non-.xml file '{}' in input, skipping.".format(path)) + print('Got non-.xml file "{}" in input, skipping.'.format(path)) continue file_list.append(path) @@ -465,17 +464,17 @@ def main(): # type: () -> None try: tree = ET.parse(cur_file) except ET.ParseError as e: - print_error("Parse error reading file '{}': {}".format(cur_file, e), state) + print_error("{}.xml: Parse error while reading the file: {}".format(cur_file, e), state) continue doc = tree.getroot() if "version" not in doc.attrib: - print_error("Version missing from 'doc', file: {}".format(cur_file), state) + print_error('{}.xml: "version" attribute missing from "doc".'.format(cur_file), state) continue name = doc.attrib["name"] if name in classes: - print_error("Duplicate class '{}'".format(name), state) + print_error('{}.xml: Duplicate class "{}".'.format(cur_file, name), state) continue classes[name] = (doc, cur_file) @@ -484,7 +483,7 @@ def main(): # type: () -> None try: state.parse_class(data[0], data[1]) except Exception as e: - print_error("Exception while parsing class '{}': {}".format(name, e), state) + print_error("{}.xml: Exception while parsing class: {}".format(name, e), state) state.sort_classes() @@ -499,12 +498,17 @@ def main(): # type: () -> None state.current_class = class_name make_rst_class(class_def, state, args.dry_run, args.output) - if not state.errored: - print("No errors found.") + if state.num_errors == 0: + print("No errors found in the class reference XML.") if not args.dry_run: print("Wrote reStructuredText files for each class to: %s" % args.output) else: - print("Errors were found in the class reference XML. Please check the messages above.") + if state.num_errors >= 2: + print( + "%d errors were found in the class reference XML. Please check the messages above." % state.num_errors + ) + else: + print("1 error was found in the class reference XML. Please check the messages above.") exit(1) @@ -856,7 +860,7 @@ def escape_rst(text, until_pos=-1): # type: (str) -> str def format_codeblock(code_type, post_text, indent_level, state): # types: str, str, int, state end_pos = post_text.find("[/" + code_type + "]") if end_pos == -1: - print_error("[" + code_type + "] without a closing tag, file: {}".format(state.current_class), state) + print_error("{}.xml: [" + code_type + "] without a closing tag.".format(state.current_class), state) return None code_text = post_text[len("[" + code_type + "]") : end_pos] @@ -875,9 +879,9 @@ def format_codeblock(code_type, post_text, indent_level, state): # types: str, if to_skip > indent_level: print_error( - "Four spaces should be used for indentation within [" + "{}.xml: Four spaces should be used for indentation within [" + code_type - + "], file: {}".format(state.current_class), + + "].".format(state.current_class), state, ) @@ -987,7 +991,7 @@ def rstize_text(text, state): # type: (str, State) -> str if param.find(".") != -1: ss = param.split(".") if len(ss) > 2: - print_error("Bad reference: '{}', file: {}".format(param, state.current_class), state) + print_error('{}.xml: Bad reference: "{}".'.format(state.current_class, param), state) class_param, method_param = ss else: @@ -1000,33 +1004,31 @@ def rstize_text(text, state): # type: (str, State) -> str if cmd.startswith("constructor"): if method_param not in class_def.constructors: print_error( - "Unresolved constructor '{}', file: {}".format(param, state.current_class), state + '{}.xml: Unresolved constructor "{}".'.format(state.current_class, param), state ) ref_type = "_constructor" if cmd.startswith("method"): if method_param not in class_def.methods: - print_error("Unresolved method '{}', file: {}".format(param, state.current_class), state) + print_error('{}.xml: Unresolved method "{}".'.format(state.current_class, param), state) ref_type = "_method" if cmd.startswith("operator"): if method_param not in class_def.operators: - print_error("Unresolved operator '{}', file: {}".format(param, state.current_class), state) + print_error('{}.xml: Unresolved operator "{}".'.format(state.current_class, param), state) ref_type = "_operator" elif cmd.startswith("member"): if method_param not in class_def.properties: - print_error("Unresolved member '{}', file: {}".format(param, state.current_class), state) + print_error('{}.xml: Unresolved member "{}".'.format(state.current_class, param), state) ref_type = "_property" elif cmd.startswith("theme_item"): if method_param not in class_def.theme_items: - print_error( - "Unresolved theme item '{}', file: {}".format(param, state.current_class), state - ) + print_error('{}.xml: Unresolved theme item "{}".'.format(state.current_class, param), state) ref_type = "_theme_{}".format(class_def.theme_items[method_param].data_name) elif cmd.startswith("signal"): if method_param not in class_def.signals: - print_error("Unresolved signal '{}', file: {}".format(param, state.current_class), state) + print_error('{}.xml: Unresolved signal "{}".'.format(state.current_class, param), state) ref_type = "_signal" elif cmd.startswith("constant"): @@ -1052,13 +1054,13 @@ def rstize_text(text, state): # type: (str, State) -> str break if not found: - print_error("Unresolved constant '{}', file: {}".format(param, state.current_class), state) + print_error('{}.xml: Unresolved constant "{}".'.format(state.current_class, param), state) ref_type = "_constant" else: print_error( - "Unresolved type reference '{}' in method reference '{}', file: {}".format( - class_param, param, state.current_class + '{}.xml: Unresolved type reference "{}" in method reference "{}".'.format( + state.current_class, class_param, param ), state, ) @@ -1078,7 +1080,7 @@ def rstize_text(text, state): # type: (str, State) -> str endurl_pos = text.find("[/url]", endq_pos + 1) if endurl_pos == -1: print_error( - "Tag depth mismatch for [url]: no closing [/url], file: {}".format(state.current_class), state + "{}.xml: Tag depth mismatch for [url]: no closing [/url]".format(state.current_class), state ) break link_title = text[endq_pos + 1 : endurl_pos] @@ -1203,7 +1205,9 @@ def rstize_text(text, state): # type: (str, State) -> str previous_pos = pos if tag_depth > 0: - print_error("Tag depth mismatch: too many/little open/close tags, file: {}".format(state.current_class), state) + print_error( + "{}.xml: Tag depth mismatch: too many (or too little) open/close tags.".format(state.current_class), state + ) return text @@ -1247,7 +1251,7 @@ def make_type(klass, state): # type: (str, State) -> str link_type = link_type[:-2] if link_type in state.classes: return ":ref:`{}<class_{}>`".format(klass, link_type) - print_error("Unresolved type '{}', file: {}".format(klass, state.current_class), state) + print_error('{}.xml: Unresolved type "{}".'.format(state.current_class, klass), state) return klass @@ -1271,7 +1275,7 @@ def make_enum(t, state): # type: (str, State) -> str # Don't fail for `Vector3.Axis`, as this enum is a special case which is expected not to be resolved. if "{}.{}".format(c, e) != "Vector3.Axis": - print_error("Unresolved enum '{}', file: {}".format(t, state.current_class), state) + print_error('{}.xml: Unresolved enum "{}".'.format(state.current_class, t), state) return t @@ -1429,7 +1433,7 @@ def sanitize_operator_name(dirty_name, state): # type: (str, State) -> str else: clear_name = "xxx" - print_error("Unsupported operator type '{}', please add the missing rule.".format(dirty_name), state) + print_error('Unsupported operator type "{}", please add the missing rule.'.format(dirty_name), state) return clear_name diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 4b0986cca1..1c946895a5 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -464,8 +464,8 @@ bool ShaderGLES3::_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"; - FileAccessRef f = FileAccess::open(path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ); + if (f.is_null()) { return false; } @@ -530,8 +530,8 @@ void ShaderGLES3::_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"; - FileAccessRef f = FileAccess::open(path, FileAccess::WRITE); - ERR_FAIL_COND(!f); + Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE); + ERR_FAIL_COND(f.is_null()); f->store_buffer((const uint8_t *)shader_file_header, 4); f->store_32(cache_file_version); //file version uint32_t variant_count = variant_count; @@ -541,8 +541,6 @@ void ShaderGLES3::_save_to_cache(Version *p_version) { f->store_32(p_version->variant_data[i].size()); //stage count f->store_buffer(p_version->variant_data[i].ptr(), p_version->variant_data[i].size()); } - - f->close(); #endif } @@ -642,8 +640,8 @@ void ShaderGLES3::initialize(const String &p_general_defines, int p_base_texture base_sha256 = hash_build.as_string().sha256_text(); - DirAccessRef d = DirAccess::open(shader_cache_dir); - ERR_FAIL_COND(!d); + Ref<DirAccess> d = DirAccess::open(shader_cache_dir); + ERR_FAIL_COND(d.is_null()); if (d->change_dir(name) != OK) { Error err = d->make_dir(name); ERR_FAIL_COND(err != OK); diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index 46e271f9c9..917bfec574 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -36,18 +36,16 @@ #include <string.h> -Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { const uint64_t buffer_size = f->get_length(); Vector<uint8_t> file_buffer; Error err = file_buffer.resize(buffer_size); if (err) { - f->close(); return err; } { uint8_t *writer = file_buffer.ptrw(); f->get_buffer(writer, buffer_size); - f->close(); } const uint8_t *reader = file_buffer.ptr(); return PNGDriverCommon::png_to_image(reader, buffer_size, p_force_linear, p_image); diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h index af3bcd5b66..522cc901d4 100644 --- a/drivers/png/image_loader_png.h +++ b/drivers/png/image_loader_png.h @@ -40,7 +40,7 @@ private: static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size); public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderPNG(); }; diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp index ca84fb6be9..8633d2dc4e 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.cpp @@ -52,20 +52,16 @@ Error ResourceSaverPNG::save_image(const String &p_path, const Ref<Image> &p_img Vector<uint8_t> buffer; Error err = PNGDriverCommon::image_to_png(p_img, buffer); ERR_FAIL_COND_V_MSG(err, err, "Can't convert image to PNG."); - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err, err, vformat("Can't save PNG at path: '%s'.", p_path)); const uint8_t *reader = buffer.ptr(); file->store_buffer(reader, buffer.size()); if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); return ERR_CANT_CREATE; } - file->close(); - memdelete(file); - return OK; } diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index af47173b41..7e6105f033 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -49,7 +49,7 @@ #include <mntent.h> #endif -DirAccess *DirAccessUnix::create_fs() { +Ref<DirAccess> DirAccessUnix::create_fs() { return memnew(DirAccessUnix); } @@ -374,7 +374,7 @@ Error DirAccessUnix::change_dir(String p_dir) { return OK; } -String DirAccessUnix::get_current_dir(bool p_include_drive) { +String DirAccessUnix::get_current_dir(bool p_include_drive) const { String base = _get_root_path(); if (!base.is_empty()) { String bd = current_dir.replace_first(base, ""); diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index b4dc012db2..4fea7cd154 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -43,7 +43,7 @@ class DirAccessUnix : public DirAccess { DIR *dir_stream = nullptr; - static DirAccess *create_fs(); + static Ref<DirAccess> create_fs(); String current_dir; bool _cisdir; @@ -67,7 +67,7 @@ public: virtual bool drives_are_shortcuts(); virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success - virtual String get_current_dir(bool p_include_drive = true); ///< return current dir location + virtual String get_current_dir(bool p_include_drive = true) const; ///< return current dir location virtual Error make_dir(String p_dir); virtual bool file_exists(String p_file); diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index ea442ad8bf..99da292e12 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -336,7 +336,7 @@ Error FileAccessUnix::_set_unix_permissions(const String &p_file, uint32_t p_per return FAILED; } -FileAccess *FileAccessUnix::create_libc() { +Ref<FileAccess> FileAccessUnix::create_libc() { return memnew(FileAccessUnix); } diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 8ebdcd2a2d..692776915c 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -49,7 +49,7 @@ class FileAccessUnix : public FileAccess { String path; String path_src; - static FileAccess *create_libc(); + static Ref<FileAccess> create_libc(); public: static CloseNotificationFunc close_notification_func; diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 260f7dd08b..400802686e 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -4875,9 +4875,8 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining push constants."); #if 0 if (pconstants[0] == nullptr) { - FileAccess *f = FileAccess::open("res://popo.spv", FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open("res://popo.spv", FileAccess::WRITE); f->store_buffer((const uint8_t *)&SpirV[0], SpirV.size() * sizeof(uint32_t)); - memdelete(f); } #endif diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 6f3bad12c1..881575d245 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -185,7 +185,7 @@ Error DirAccessWindows::make_dir(String p_dir) { return ERR_CANT_CREATE; } -String DirAccessWindows::get_current_dir(bool p_include_drive) { +String DirAccessWindows::get_current_dir(bool p_include_drive) const { String base = _get_root_path(); if (!base.is_empty()) { String bd = current_dir.replace("\\", "/").replace_first(base, ""); diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h index 78d37074e5..fbb07ddef8 100644 --- a/drivers/windows/dir_access_windows.h +++ b/drivers/windows/dir_access_windows.h @@ -64,7 +64,7 @@ public: virtual String get_drive(int p_drive); virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success - virtual String get_current_dir(bool p_include_drive = true); ///< return current dir location + virtual String get_current_dir(bool p_include_drive = true) const; ///< return current dir location virtual bool file_exists(String p_file); virtual bool dir_exists(String p_dir); diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index 96931efd3b..86b40a311e 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -61,29 +61,37 @@ static const char *_joy_axis_descriptions[(size_t)JoyAxis::MAX * 2] = { TTRC("Joystick 4 Down"), }; -String InputEventConfigurationDialog::get_event_text(const Ref<InputEvent> &p_event) { +String InputEventConfigurationDialog::get_event_text(const Ref<InputEvent> &p_event, bool p_include_device) const { ERR_FAIL_COND_V_MSG(p_event.is_null(), String(), "Provided event is not a valid instance of InputEvent"); - // Joypad motion events will display slightly differently than what the event->as_text() provides. See #43660. - Ref<InputEventJoypadMotion> jpmotion = p_event; - if (jpmotion.is_valid()) { + String text = p_event->as_text(); + + Ref<InputEventMouse> mouse = p_event; + Ref<InputEventJoypadMotion> jp_motion = p_event; + Ref<InputEventJoypadButton> jp_button = p_event; + if (jp_motion.is_valid()) { + // Joypad motion events will display slightly differently than what the event->as_text() provides. See #43660. String desc = TTR("Unknown Joypad Axis"); - if (jpmotion->get_axis() < JoyAxis::MAX) { - desc = RTR(_joy_axis_descriptions[2 * (size_t)jpmotion->get_axis() + (jpmotion->get_axis_value() < 0 ? 0 : 1)]); + if (jp_motion->get_axis() < JoyAxis::MAX) { + desc = RTR(_joy_axis_descriptions[2 * (size_t)jp_motion->get_axis() + (jp_motion->get_axis_value() < 0 ? 0 : 1)]); } - return vformat("Joypad Axis %s %s (%s)", itos((int64_t)jpmotion->get_axis()), jpmotion->get_axis_value() < 0 ? "-" : "+", desc); - } else { - return p_event->as_text(); + text = vformat("Joypad Axis %s %s (%s)", itos((int64_t)jp_motion->get_axis()), jp_motion->get_axis_value() < 0 ? "-" : "+", desc); + } + if (p_include_device && (mouse.is_valid() || jp_button.is_valid() || jp_motion.is_valid())) { + String device_string = _get_device_string(p_event->get_device()); + text += vformat(" - %s", device_string); } + + return text; } -void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event) { +void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event, bool p_update_input_list_selection) { if (p_event.is_valid()) { event = p_event; // Update Label - event_as_text->set_text(get_event_text(event)); + event_as_text->set_text(get_event_text(event, true)); Ref<InputEventKey> k = p_event; Ref<InputEventMouseButton> mb = p_event; @@ -122,7 +130,7 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event) { additional_options_container->show(); // Update selected item in input list. - if (k.is_valid() || joyb.is_valid() || joym.is_valid() || mb.is_valid()) { + if (p_update_input_list_selection && (k.is_valid() || joyb.is_valid() || joym.is_valid() || mb.is_valid())) { TreeItem *category = input_list_tree->get_root()->get_first_child(); while (category) { TreeItem *input_item = category->get_first_child(); @@ -234,10 +242,13 @@ void InputEventConfigurationDialog::_listen_window_input(const Ref<InputEvent> & } } + // Create an editable reference + Ref<InputEvent> received_event = p_event; + // Check what the type is and if it is allowed. - Ref<InputEventKey> k = p_event; - Ref<InputEventJoypadButton> joyb = p_event; - Ref<InputEventJoypadMotion> joym = p_event; + Ref<InputEventKey> k = received_event; + Ref<InputEventJoypadButton> joyb = received_event; + Ref<InputEventJoypadMotion> joym = received_event; int type = 0; if (k.is_valid()) { @@ -266,7 +277,7 @@ void InputEventConfigurationDialog::_listen_window_input(const Ref<InputEvent> & } if (k.is_valid()) { - k->set_pressed(false); // to avoid serialisation of 'pressed' property - doesn't matter for actions anyway. + k->set_pressed(false); // To avoid serialisation of 'pressed' property - doesn't matter for actions anyway. // Maintain physical keycode option state if (physical_key_checkbox->is_pressed()) { k->set_keycode(Key::NONE); @@ -275,15 +286,17 @@ void InputEventConfigurationDialog::_listen_window_input(const Ref<InputEvent> & } } - Ref<InputEventWithModifiers> mod = p_event; + Ref<InputEventWithModifiers> mod = received_event; if (mod.is_valid()) { // Maintain store command option state mod->set_store_command(store_command_checkbox->is_pressed()); - mod->set_window_id(0); } - _set_event(p_event); + // Maintain device selection. + received_event->set_device(_get_current_device()); + + _set_event(received_event); set_input_as_handled(); } @@ -331,7 +344,7 @@ void InputEventConfigurationDialog::_update_input_list() { Ref<InputEventMouseButton> mb; mb.instantiate(); mb->set_button_index(mouse_buttons[i]); - String desc = get_event_text(mb); + String desc = get_event_text(mb, false); if (!search_term.is_empty() && desc.findn(search_term) == -1) { continue; @@ -354,7 +367,7 @@ void InputEventConfigurationDialog::_update_input_list() { Ref<InputEventJoypadButton> joyb; joyb.instantiate(); joyb->set_button_index((JoyButton)i); - String desc = get_event_text(joyb); + String desc = get_event_text(joyb, false); if (!search_term.is_empty() && desc.findn(search_term) == -1) { continue; @@ -380,7 +393,7 @@ void InputEventConfigurationDialog::_update_input_list() { joym.instantiate(); joym->set_axis((JoyAxis)axis); joym->set_axis_value(direction); - String desc = get_event_text(joym); + String desc = get_event_text(joym, false); if (!search_term.is_empty() && desc.findn(search_term) == -1) { continue; @@ -495,7 +508,7 @@ void InputEventConfigurationDialog::_input_list_item_selected() { k->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed()); k->set_store_command(store_command_checkbox->is_pressed()); - _set_event(k); + _set_event(k, false); } break; case InputEventConfigurationDialog::INPUT_MOUSE_BUTTON: { MouseButton idx = (MouseButton)(int)selected->get_meta("__index"); @@ -510,12 +523,19 @@ void InputEventConfigurationDialog::_input_list_item_selected() { mb->set_meta_pressed(mod_checkboxes[MOD_META]->is_pressed()); mb->set_store_command(store_command_checkbox->is_pressed()); - _set_event(mb); + // Maintain selected device + mb->set_device(_get_current_device()); + + _set_event(mb, false); } break; case InputEventConfigurationDialog::INPUT_JOY_BUTTON: { JoyButton idx = (JoyButton)(int)selected->get_meta("__index"); Ref<InputEventJoypadButton> jb = InputEventJoypadButton::create_reference(idx); - _set_event(jb); + + // Maintain selected device + jb->set_device(_get_current_device()); + + _set_event(jb, false); } break; case InputEventConfigurationDialog::INPUT_JOY_MOTION: { JoyAxis axis = (JoyAxis)(int)selected->get_meta("__axis"); @@ -525,24 +545,35 @@ void InputEventConfigurationDialog::_input_list_item_selected() { jm.instantiate(); jm->set_axis(axis); jm->set_axis_value(value); - _set_event(jm); + + // Maintain selected device + jm->set_device(_get_current_device()); + + _set_event(jm, false); } break; } } -void InputEventConfigurationDialog::_set_current_device(int i_device) { - device_id_option->select(i_device + 1); +void InputEventConfigurationDialog::_device_selection_changed(int p_option_button_index) { + // Subtract 1 as option index 0 corresponds to "All Devices" (value of -1) + // and option index 1 corresponds to device 0, etc... + event->set_device(p_option_button_index - 1); + event_as_text->set_text(get_event_text(event, true)); +} + +void InputEventConfigurationDialog::_set_current_device(int p_device) { + device_id_option->select(p_device + 1); } int InputEventConfigurationDialog::_get_current_device() const { return device_id_option->get_selected() - 1; } -String InputEventConfigurationDialog::_get_device_string(int i_device) const { - if (i_device == InputMap::ALL_DEVICES) { +String InputEventConfigurationDialog::_get_device_string(int p_device) const { + if (p_device == InputMap::ALL_DEVICES) { return TTR("All Devices"); } - return TTR("Device") + " " + itos(i_device); + return TTR("Device") + " " + itos(p_device); } void InputEventConfigurationDialog::_notification(int p_what) { @@ -588,6 +619,9 @@ void InputEventConfigurationDialog::popup_and_configure(const Ref<InputEvent> &p // Switch to "Listen" tab tab_container->set_current_tab(0); + + // Select "All Devices" by default. + device_id_option->select(0); } popup_centered(); @@ -673,12 +707,13 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() { device_id_option = memnew(OptionButton); device_id_option->set_h_size_flags(Control::SIZE_EXPAND_FILL); - device_container->add_child(device_id_option); - for (int i = -1; i < 8; i++) { device_id_option->add_item(_get_device_string(i)); } - _set_current_device(0); + device_id_option->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_device_selection_changed)); + _set_current_device(InputMap::ALL_DEVICES); + device_container->add_child(device_id_option); + device_container->hide(); additional_options_container->add_child(device_container); @@ -1096,7 +1131,7 @@ void ActionMapEditor::update_action_list(const Vector<ActionInfo> &p_action_info TreeItem *event_item = action_tree->create_item(action_item); // First Column - Text - event_item->set_text(0, event_config_dialog->get_event_text(event)); // Need to us the special description for JoypadMotion here, so don't use as_text() directly. + event_item->set_text(0, event_config_dialog->get_event_text(event, true)); event_item->set_meta("__event", event); event_item->set_meta("__index", evnt_idx); diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h index e96139e070..0da7708422 100644 --- a/editor/action_map_editor.h +++ b/editor/action_map_editor.h @@ -97,7 +97,7 @@ private: CheckBox *physical_key_checkbox = nullptr; - void _set_event(const Ref<InputEvent> &p_event); + void _set_event(const Ref<InputEvent> &p_event, bool p_update_input_list_selection = true); void _tab_selected(int p_tab); void _listen_window_input(const Ref<InputEvent> &p_event); @@ -110,9 +110,10 @@ private: void _store_command_toggled(bool p_checked); void _physical_keycode_toggled(bool p_checked); - void _set_current_device(int i_device); + void _device_selection_changed(int p_option_button_index); + void _set_current_device(int p_device); int _get_current_device() const; - String _get_device_string(int i_device) const; + String _get_device_string(int p_device) const; protected: void _notification(int p_what); @@ -121,7 +122,7 @@ public: // Pass an existing event to configure it. Alternatively, pass no event to start with a blank configuration. void popup_and_configure(const Ref<InputEvent> &p_event = Ref<InputEvent>()); Ref<InputEvent> get_event() const; - String get_event_text(const Ref<InputEvent> &p_event); + String get_event_text(const Ref<InputEvent> &p_event, bool p_include_device) const; void set_allowed_input_types(int p_type_masks); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index dc69a8cb08..53631c1e3b 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1961,11 +1961,21 @@ void AnimationTrackEdit::_notification(int p_what) { int limit = timeline->get_name_limit(); + if (track % 2 == 1) { + // Draw a background over odd lines to make long lists of tracks easier to read. + draw_rect(Rect2(Point2(1 * EDSCALE, 0), get_size() - Size2(1 * EDSCALE, 0)), Color(0.5, 0.5, 0.5, 0.05)); + } + + if (hovered) { + // Draw hover feedback. + draw_rect(Rect2(Point2(1 * EDSCALE, 0), get_size() - Size2(1 * EDSCALE, 0)), Color(0.5, 0.5, 0.5, 0.1)); + } + if (has_focus()) { Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor")); accent.a *= 0.7; // Offside so the horizontal sides aren't cutoff. - draw_rect(Rect2(Point2(1 * EDSCALE, 0), get_size() - Size2(1 * EDSCALE, 0)), accent, false); + draw_style_box(get_theme_stylebox(SNAME("Focus"), SNAME("EditorStyles")), Rect2(Point2(1 * EDSCALE, 0), get_size() - Size2(1 * EDSCALE, 0))); } Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label")); @@ -2236,7 +2246,14 @@ void AnimationTrackEdit::_notification(int p_what) { } } break; + case NOTIFICATION_MOUSE_ENTER: + hovered = true; + update(); + break; case NOTIFICATION_MOUSE_EXIT: + hovered = false; + update(); + [[fallthrough]]; case NOTIFICATION_DRAG_END: { cancel_drop(); } break; diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index d025dd3d26..a8a5d11c12 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -171,6 +171,7 @@ class AnimationTrackEdit : public Control { PopupMenu *menu = nullptr; + bool hovered = false; bool clicking_on_name = false; void _zoom_changed(); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index f9858aa514..50e1d03663 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -377,8 +377,8 @@ void CreateDialog::_confirmed() { return; } - FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE); + if (f.is_valid()) { f->store_line(selected_item); for (int i = 0; i < MIN(32, recent->get_item_count()); i++) { @@ -386,8 +386,6 @@ void CreateDialog::_confirmed() { f->store_line(recent->get_item_text(i)); } } - - memdelete(f); } // To prevent, emitting an error from the transient window (shader dialog for example) hide this dialog before emitting the "create" signal. @@ -647,8 +645,8 @@ void CreateDialog::_save_and_update_favorite_list() { favorites->clear(); TreeItem *root = favorites->create_item(); - FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE); + if (f.is_valid()) { for (int i = 0; i < favorite_list.size(); i++) { String l = favorite_list[i]; String name = l.get_slicec(' ', 0); @@ -665,7 +663,6 @@ void CreateDialog::_save_and_update_favorite_list() { ti->set_text(0, l); ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(name, icon_fallback)); } - memdelete(f); } emit_signal(SNAME("favorites_updated")); @@ -673,8 +670,8 @@ void CreateDialog::_save_and_update_favorite_list() { void CreateDialog::_load_favorites_and_history() { String dir = EditorSettings::get_singleton()->get_project_settings_dir(); - FileAccess *f = FileAccess::open(dir.plus_file("create_recent." + base_type), FileAccess::READ); - if (f) { + Ref<FileAccess> f = FileAccess::open(dir.plus_file("create_recent." + base_type), FileAccess::READ); + if (f.is_valid()) { while (!f->eof_reached()) { String l = f->get_line().strip_edges(); String name = l.get_slicec(' ', 0); @@ -683,12 +680,10 @@ void CreateDialog::_load_favorites_and_history() { recent->add_item(l, EditorNode::get_singleton()->get_class_icon(name, icon_fallback)); } } - - memdelete(f); } f = FileAccess::open(dir.plus_file("favorites." + base_type), FileAccess::READ); - if (f) { + if (f.is_valid()) { while (!f->eof_reached()) { String l = f->get_line().strip_edges(); @@ -696,8 +691,6 @@ void CreateDialog::_load_favorites_and_history() { favorite_list.push_back(l); } } - - memdelete(f); } } diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 1e8753acc0..3a3b35f8a5 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -164,7 +164,7 @@ void ScriptEditorDebugger::_file_selected(const String &p_file) { switch (file_dialog_purpose) { case SAVE_MONITORS_CSV: { Error err; - FileAccessRef file = FileAccess::open(p_file, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err); if (err != OK) { ERR_PRINT("Failed to open " + p_file); @@ -209,7 +209,7 @@ void ScriptEditorDebugger::_file_selected(const String &p_file) { } break; case SAVE_VRAM_CSV: { Error err; - FileAccessRef file = FileAccess::open(p_file, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err); if (err != OK) { ERR_PRINT("Failed to open " + p_file); diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index 95b3a02631..35f40a159a 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -749,7 +749,7 @@ void OrphanResourcesDialog::_find_to_delete(TreeItem *p_item, List<String> &path } void OrphanResourcesDialog::_delete_confirm() { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); for (const String &E : paths) { da->remove(E); EditorFileSystem::get_singleton()->update_file(E); diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index adad8fdba8..16cbc0f34d 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -1035,8 +1035,8 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> & Error DocTools::load_classes(const String &p_dir) { Error err; - DirAccessRef da = DirAccess::open(p_dir, &err); - if (!da) { + Ref<DirAccess> da = DirAccess::open(p_dir, &err); + if (da.is_null()) { return err; } @@ -1063,8 +1063,8 @@ Error DocTools::load_classes(const String &p_dir) { Error DocTools::erase_classes(const String &p_dir) { Error err; - DirAccessRef da = DirAccess::open(p_dir, &err); - if (!da) { + Ref<DirAccess> da = DirAccess::open(p_dir, &err); + if (da.is_null()) { return err; } @@ -1273,7 +1273,7 @@ Error DocTools::_load(Ref<XMLParser> parser) { return OK; } -static void _write_string(FileAccess *f, int p_tablevel, const String &p_string) { +static void _write_string(Ref<FileAccess> f, int p_tablevel, const String &p_string) { if (p_string.is_empty()) { return; } @@ -1284,7 +1284,7 @@ static void _write_string(FileAccess *f, int p_tablevel, const String &p_string) f->store_string(tab + p_string + "\n"); } -static void _write_method_doc(FileAccess *f, const String &p_name, Vector<DocData::MethodDoc> &p_method_docs) { +static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<DocData::MethodDoc> &p_method_docs) { if (!p_method_docs.is_empty()) { p_method_docs.sort(); _write_string(f, 1, "<" + p_name + "s>"); @@ -1350,7 +1350,7 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str Error err; String save_file = save_path.plus_file(c.name + ".xml"); - FileAccessRef f = FileAccess::open(save_file, FileAccess::WRITE, &err); + 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 2537c4d4a8..7dcb9a4088 100644 --- a/editor/editor_asset_installer.cpp +++ b/editor/editor_asset_installer.cpp @@ -64,8 +64,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) { package_path = p_path; Set<String> files_sorted; - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); unzFile pkg = unzOpen2(p_path.utf8().get_data(), &io); if (!pkg) { @@ -238,8 +237,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) { } void EditorAssetInstaller::ok_pressed() { - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); unzFile pkg = unzOpen2(package_path.utf8().get_data(), &io); if (!pkg) { @@ -280,7 +278,7 @@ void EditorAssetInstaller::ok_pressed() { dirpath = dirpath.substr(0, dirpath.length() - 1); } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); da->make_dir(dirpath); } else { Vector<uint8_t> data; @@ -291,10 +289,9 @@ void EditorAssetInstaller::ok_pressed() { unzReadCurrentFile(pkg, data.ptrw(), data.size()); unzCloseCurrentFile(pkg); - FileAccess *f = FileAccess::open(path, FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE); + if (f.is_valid()) { f->store_buffer(data.ptr(), data.size()); - memdelete(f); } else { failed_files.push_back(path); } diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp index 9fabde93ef..8494991892 100644 --- a/editor/editor_dir_dialog.cpp +++ b/editor/editor_dir_dialog.cpp @@ -156,8 +156,8 @@ void EditorDirDialog::_make_dir_confirm() { String dir = ti->get_metadata(0); - DirAccessRef d = DirAccess::open(dir); - ERR_FAIL_COND_MSG(!d, "Cannot open directory '" + dir + "'."); + Ref<DirAccess> d = DirAccess::open(dir); + ERR_FAIL_COND_MSG(d.is_null(), "Cannot open directory '" + dir + "'."); const String stripped_dirname = makedirname->get_text().strip_edges(); diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index a1081fcbfb..40b850cace 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -327,12 +327,12 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa } } - FileAccessEncrypted *fae = nullptr; - FileAccess *ftmp = pd->f; + Ref<FileAccessEncrypted> fae; + Ref<FileAccess> ftmp = pd->f; if (sd.encrypted) { - fae = memnew(FileAccessEncrypted); - ERR_FAIL_COND_V(!fae, ERR_SKIP); + fae.instantiate(); + ERR_FAIL_COND_V(fae.is_null(), ERR_SKIP); Error err = fae->open_and_parse(ftmp, p_key, FileAccessEncrypted::MODE_WRITE_AES256, false); ERR_FAIL_COND_V(err != OK, ERR_SKIP); @@ -342,9 +342,8 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa // Store file content. ftmp->store_buffer(p_data.ptr(), p_data.size()); - if (fae) { + if (fae.is_valid()) { fae->release(); - memdelete(fae); } int pad = _get_pad(PCK_PADDING, pd->f->get_position()); @@ -480,7 +479,7 @@ void EditorExportPlatform::_export_find_dependencies(const String &p_path, Set<S } } -void EditorExportPlatform::_edit_files_with_filter(DirAccess *da, const Vector<String> &p_filters, Set<String> &r_list, bool exclude) { +void EditorExportPlatform::_edit_files_with_filter(Ref<DirAccess> &da, const Vector<String> &p_filters, Set<String> &r_list, bool exclude) { da->list_dir_begin(); String cur_dir = da->get_current_dir().replace("\\", "/"); if (!cur_dir.ends_with("/")) { @@ -542,10 +541,9 @@ void EditorExportPlatform::_edit_filter_list(Set<String> &r_list, const String & filters.push_back(f); } - DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - ERR_FAIL_NULL(da); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + ERR_FAIL_COND(da.is_null()); _edit_files_with_filter(da, filters, r_list, exclude); - memdelete(da); } void EditorExportPlugin::set_export_preset(const Ref<EditorExportPreset> &p_preset) { @@ -1130,12 +1128,12 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b EditorProgress ep("savepack", TTR("Packing"), 102, true); // Create the temporary export directory if it doesn't exist. - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + 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"); - FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!ftmp, ERR_CANT_CREATE, "Cannot create file '" + tmppath + "'."); + Ref<FileAccess> ftmp = FileAccess::open(tmppath, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(ftmp.is_null(), ERR_CANT_CREATE, "Cannot create file '" + tmppath + "'."); PackData pd; pd.ep = &ep; @@ -1144,8 +1142,6 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b Error err = export_project_files(p_preset, p_debug, _save_pack_file, &pd, _add_shared_object); - memdelete(ftmp); //close tmp file - if (err != OK) { DirAccess::remove_file_or_error(tmppath); ERR_PRINT("Failed to export project files"); @@ -1154,19 +1150,19 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b pd.file_ofs.sort(); //do sort, so we can do binary search later - FileAccess *f; + Ref<FileAccess> f; int64_t embed_pos = 0; if (!p_embed) { // Regular output to separate PCK file f = FileAccess::open(p_path, FileAccess::WRITE); - if (!f) { + if (f.is_null()) { DirAccess::remove_file_or_error(tmppath); ERR_FAIL_V(ERR_CANT_CREATE); } } else { // Append to executable f = FileAccess::open(p_path, FileAccess::READ_WRITE); - if (!f) { + if (f.is_null()) { DirAccess::remove_file_or_error(tmppath); ERR_FAIL_V(ERR_FILE_CANT_OPEN); } @@ -1211,8 +1207,8 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b f->store_32(pd.file_ofs.size()); //amount of files - FileAccessEncrypted *fae = nullptr; - FileAccess *fhead = f; + Ref<FileAccessEncrypted> fae; + Ref<FileAccess> fhead = f; if (enc_pck && enc_directory) { String script_key = p_preset->get_script_encryption_key().to_lower(); @@ -1243,8 +1239,8 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b key.write[i] = v; } } - fae = memnew(FileAccessEncrypted); - ERR_FAIL_COND_V(!fae, ERR_SKIP); + fae.instantiate(); + ERR_FAIL_COND_V(fae.is_null(), ERR_SKIP); err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_WRITE_AES256, false); ERR_FAIL_COND_V(err != OK, ERR_SKIP); @@ -1272,9 +1268,8 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b fhead->store_32(flags); } - if (fae) { + if (fae.is_valid()) { fae->release(); - memdelete(fae); } int header_padding = _get_pad(PCK_PADDING, f->get_position()); @@ -1290,8 +1285,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b // Save the rest of the data. ftmp = FileAccess::open(tmppath, FileAccess::READ); - if (!ftmp) { - memdelete(f); + if (ftmp.is_null()) { DirAccess::remove_file_or_error(tmppath); ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't open file to read from path '" + String(tmppath) + "'."); } @@ -1307,8 +1301,6 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b f->store_buffer(buf, got); } - memdelete(ftmp); - if (p_embed) { // Ensure embedded data ends at a 64-bit multiple uint64_t embed_end = f->get_position() - embed_pos + 12; @@ -1326,7 +1318,6 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b } } - memdelete(f); DirAccess::remove_file_or_error(tmppath); return OK; @@ -1335,8 +1326,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) { EditorProgress ep("savezip", TTR("Packing"), 102, true); - FileAccess *src_f; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io); ZipData zd; @@ -1839,7 +1829,7 @@ Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_pr return ERR_FILE_NOT_FOUND; } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); da->make_dir_recursive(p_path.get_base_dir()); Error err = da->copy(template_path, p_path, get_chmod_flags()); diff --git a/editor/editor_export.h b/editor/editor_export.h index 4d5aebc770..236f4d129c 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -184,7 +184,7 @@ private: }; struct PackData { - FileAccess *f = nullptr; + Ref<FileAccess> f; Vector<SavedData> file_ofs; EditorProgress *ep = nullptr; Vector<SharedObject> *so_files = nullptr; @@ -207,7 +207,7 @@ private: static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key); static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key); - void _edit_files_with_filter(DirAccess *da, const Vector<String> &p_filters, Set<String> &r_list, bool exclude); + void _edit_files_with_filter(Ref<DirAccess> &da, const Vector<String> &p_filters, Set<String> &r_list, bool exclude); void _edit_filter_list(Set<String> &r_list, const String &p_filter, bool exclude); static Error _add_shared_object(void *p_userdata, const SharedObject &p_so); diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index cf45848ed3..a20f112b2a 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -198,13 +198,12 @@ Error EditorFeatureProfile::save_to_file(const String &p_path) { data["disabled_features"] = dis_features; - FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); JSON json; String text = json.stringify(data, "\t"); f->store_string(text); - f->close(); return OK; } @@ -350,8 +349,8 @@ void EditorFeatureProfileManager::_update_profile_list(const String &p_select_pr } Vector<String> profiles; - DirAccessRef d = DirAccess::open(EditorSettings::get_singleton()->get_feature_profiles_dir()); - ERR_FAIL_COND_MSG(!d, "Cannot open directory '" + EditorSettings::get_singleton()->get_feature_profiles_dir() + "'."); + Ref<DirAccess> d = DirAccess::open(EditorSettings::get_singleton()->get_feature_profiles_dir()); + ERR_FAIL_COND_MSG(d.is_null(), "Cannot open directory '" + EditorSettings::get_singleton()->get_feature_profiles_dir() + "'."); d->list_dir_begin(); while (true) { @@ -453,8 +452,8 @@ void EditorFeatureProfileManager::_profile_action(int p_action) { void EditorFeatureProfileManager::_erase_selected_profile() { String selected = _get_selected_profile(); ERR_FAIL_COND(selected.is_empty()); - DirAccessRef da = DirAccess::open(EditorSettings::get_singleton()->get_feature_profiles_dir()); - ERR_FAIL_COND_MSG(!da, "Cannot open directory '" + EditorSettings::get_singleton()->get_feature_profiles_dir() + "'."); + Ref<DirAccess> da = DirAccess::open(EditorSettings::get_singleton()->get_feature_profiles_dir()); + ERR_FAIL_COND_MSG(da.is_null(), "Cannot open directory '" + EditorSettings::get_singleton()->get_feature_profiles_dir() + "'."); da->remove(selected + ".profile"); if (selected == current_profile) { diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index d5105b5ac8..dca69ffd5f 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -789,7 +789,7 @@ void EditorFileDialog::update_file_list() { } } else if (!dir_access->current_is_hidden()) { String full_path = cdir == "res://" ? item : dir_access->get_current_dir() + "/" + item; - if (dir_access->current_is_dir() && !EditorFileSystem::_should_skip_directory(full_path)) { + if (dir_access->current_is_dir() && (!EditorFileSystem::_should_skip_directory(full_path) || Engine::get_singleton()->is_project_manager_hint())) { dirs.push_back(item); } else { files.push_back(item); @@ -1065,7 +1065,6 @@ void EditorFileDialog::set_access(Access p_access) { if (access == p_access) { return; } - memdelete(dir_access); switch (p_access) { case ACCESS_FILESYSTEM: { dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); @@ -1853,5 +1852,4 @@ EditorFileDialog::~EditorFileDialog() { if (unregister_func) { unregister_func(this); } - memdelete(dir_access); } diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index fffe7ffcc5..db2a2ab09f 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -111,7 +111,7 @@ private: LineEdit *file = nullptr; OptionButton *filter = nullptr; AcceptDialog *error_dialog = nullptr; - DirAccess *dir_access = nullptr; + Ref<DirAccess> dir_access; ConfirmationDialog *confirm_save = nullptr; DependencyRemoveDialog *dep_remove_dialog = nullptr; ConfirmationDialog *global_remove_dialog = nullptr; diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 2b98a4b02a..98bf5d3234 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -218,10 +218,10 @@ void EditorFileSystem::_scan_filesystem() { String project = ProjectSettings::get_singleton()->get_resource_path(); String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME); - FileAccess *f = FileAccess::open(fscache, FileAccess::READ); + Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::READ); bool first = true; - if (f) { + if (f.is_valid()) { //read the disk cache while (!f->eof_reached()) { String l = f->get_line().strip_edges(); @@ -283,16 +283,13 @@ void EditorFileSystem::_scan_filesystem() { file_cache[name] = fc; } } - - f->close(); - memdelete(f); } String update_cache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4"); if (FileAccess::exists(update_cache)) { { - FileAccessRef f2 = FileAccess::open(update_cache, FileAccess::READ); + Ref<FileAccess> f2 = FileAccess::open(update_cache, FileAccess::READ); String l = f2->get_line().strip_edges(); while (!l.is_empty()) { file_cache.erase(l); //erase cache for this, so it gets updated @@ -300,7 +297,7 @@ void EditorFileSystem::_scan_filesystem() { } } - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); d->remove(update_cache); //bye bye update cache } @@ -314,14 +311,12 @@ void EditorFileSystem::_scan_filesystem() { new_filesystem = memnew(EditorFileSystemDirectory); new_filesystem->parent = nullptr; - DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES); d->change_dir("res://"); _scan_new_dir(new_filesystem, d, sp); file_cache.clear(); //clear caches, no longer needed - memdelete(d); - if (!first_scan) { //on the first scan this is done from the main thread after re-importing _save_filesystem_cache(); @@ -335,13 +330,11 @@ void EditorFileSystem::_save_filesystem_cache() { String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME); - FileAccess *f = FileAccess::open(fscache, FileAccess::WRITE); - ERR_FAIL_COND_MSG(!f, "Cannot create file '" + fscache + "'. Check user write permissions."); + Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::WRITE); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + fscache + "'. Check user write permissions."); f->store_line(filesystem_settings_version_for_import); _save_filesystem_cache(filesystem, f); - f->close(); - memdelete(f); } void EditorFileSystem::_thread_func(void *_userdata) { @@ -364,9 +357,9 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo } Error err; - FileAccess *f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path + ".import", FileAccess::READ, &err); - if (!f) { //no import file, do reimport + if (f.is_null()) { //no import file, do reimport return true; } @@ -400,7 +393,6 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo break; } else if (err != OK) { ERR_PRINT("ResourceFormatImporter::load - '" + p_path + ".import:" + itos(lines) + "' error '" + error_text + "'."); - memdelete(f); return false; //parse error, try reimport manually (Avoid reimport loop on broken file) } @@ -431,8 +423,6 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo } } - memdelete(f); - if (importer_name == "keep") { return false; //keep mode, do not reimport } @@ -453,8 +443,8 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo // Read the md5's from a separate file (so the import parameters aren't dependent on the file version String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(p_path); - FileAccess *md5s = FileAccess::open(base_path + ".md5", FileAccess::READ, &err); - if (!md5s) { // No md5's stored for this resource + Ref<FileAccess> md5s = FileAccess::open(base_path + ".md5", FileAccess::READ, &err); + if (md5s.is_null()) { // No md5's stored for this resource return true; } @@ -472,7 +462,6 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo break; } else if (err != OK) { ERR_PRINT("ResourceFormatImporter::load - '" + p_path + ".import.md5:" + itos(lines) + "' error '" + error_text + "'."); - memdelete(md5s); return false; // parse error } if (!assign.is_empty()) { @@ -485,7 +474,6 @@ bool EditorFileSystem::_test_for_reimport(const String &p_path, bool p_only_impo } } } - memdelete(md5s); //imported files are gone, reimport for (const String &E : to_check) { @@ -742,7 +730,7 @@ EditorFileSystem::ScanProgress EditorFileSystem::ScanProgress::get_sub(int p_cur return sp; } -void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess *da, const ScanProgress &p_progress) { +void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAccess> &da, const ScanProgress &p_progress) { List<String> dirs; List<String> files; @@ -967,7 +955,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const //then scan files and directories and check what's different - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); Error ret = da->change_dir(cd); ERR_FAIL_COND_MSG(ret != OK, "Cannot change to '" + cd + "' folder."); @@ -998,10 +986,9 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const efd->parent = p_dir; efd->name = f; - DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES); d->change_dir(cd.plus_file(f)); _scan_new_dir(efd, d, p_progress.get_sub(1, 1)); - memdelete(d); ItemAction ia; ia.action = ItemAction::ACTION_DIR_ADD; @@ -1137,7 +1124,7 @@ void EditorFileSystem::_delete_internal_files(String p_file) { if (FileAccess::exists(p_file + ".import")) { List<String> paths; ResourceFormatImporter::get_singleton()->get_internal_resource_path_list(p_file, &paths); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); for (const String &E : paths) { da->remove(E); } @@ -1282,7 +1269,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem() { return filesystem; } -void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory *p_dir, FileAccess *p_file) { +void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory *p_dir, Ref<FileAccess> p_file) { if (!p_dir) { return; //none } @@ -1467,8 +1454,8 @@ 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 = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4"); - FileAccessRef f = FileAccess::open(fscache, FileAccess::WRITE); - ERR_FAIL_COND_MSG(!f, "Cannot create file '" + fscache + "'. Check user write permissions."); + Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::WRITE); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + fscache + "'. Check user write permissions."); for (Set<String>::Element *E = late_update_files.front(); E; E = E->next()) { f->store_line(E->get()); } @@ -1713,8 +1700,8 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector for (const KeyValue<String, Map<StringName, Variant>> &E : source_file_options) { const String &file = E.key; String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(file); - FileAccessRef f = FileAccess::open(file + ".import", FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!f, ERR_FILE_CANT_OPEN, "Cannot open import file '" + file + ".import'."); + Ref<FileAccess> f = FileAccess::open(file + ".import", FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_FILE_CANT_OPEN, "Cannot open import file '" + file + ".import'."); //write manually, as order matters ([remap] has to go first for performance). f->store_line("[remap]"); @@ -1774,17 +1761,14 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector f->store_line(base + "=" + value); } - f->close(); - // Store the md5's of the various files. These are stored separately so that the .import files can be version controlled. - FileAccessRef md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!md5s, ERR_FILE_CANT_OPEN, "Cannot open MD5 file '" + base_path + ".md5'."); + Ref<FileAccess> md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(md5s.is_null(), ERR_FILE_CANT_OPEN, "Cannot open MD5 file '" + base_path + ".md5'."); md5s->store_line("source_md5=\"" + FileAccess::get_md5(file) + "\""); if (dest_paths.size()) { md5s->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n"); } - md5s->close(); EditorFileSystemDirectory *fs = nullptr; int cpos = -1; @@ -1930,8 +1914,8 @@ void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName //as import is complete, save the .import file - FileAccess *f = FileAccess::open(p_file + ".import", FileAccess::WRITE); - ERR_FAIL_COND_MSG(!f, "Cannot open file from path '" + p_file + ".import'."); + Ref<FileAccess> f = FileAccess::open(p_file + ".import", FileAccess::WRITE); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file from path '" + p_file + ".import'."); //write manually, as order matters ([remap] has to go first for performance). f->store_line("[remap]"); @@ -2017,19 +2001,14 @@ void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName f->store_line(base + "=" + value); } - f->close(); - memdelete(f); - // Store the md5's of the various files. These are stored separately so that the .import files can be version controlled. - FileAccess *md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE); - ERR_FAIL_COND_MSG(!md5s, "Cannot open MD5 file '" + base_path + ".md5'."); + Ref<FileAccess> md5s = FileAccess::open(base_path + ".md5", FileAccess::WRITE); + ERR_FAIL_COND_MSG(md5s.is_null(), "Cannot open MD5 file '" + base_path + ".md5'."); md5s->store_line("source_md5=\"" + FileAccess::get_md5(p_file) + "\""); if (dest_paths.size()) { md5s->store_line("dest_md5=\"" + FileAccess::get_multiple_md5(dest_paths) + "\"\n"); } - md5s->close(); - memdelete(md5s); //update modified times, to avoid reimport fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file); @@ -2342,14 +2321,14 @@ bool EditorFileSystem::_scan_extensions() { String extension_list_config_file = NativeExtension::get_extension_list_config_file(); if (extensions.size()) { if (extensions_added.size() || extensions_removed.size()) { //extensions were added or removed - FileAccessRef f = FileAccess::open(extension_list_config_file, FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(extension_list_config_file, FileAccess::WRITE); for (const String &E : extensions) { f->store_line(E); } } } else { if (loaded_extensions.size() || FileAccess::exists(extension_list_config_file)) { //extensions were removed - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); da->remove(extension_list_config_file); } } @@ -2438,7 +2417,7 @@ EditorFileSystem::EditorFileSystem() { new_filesystem = nullptr; // This should probably also work on Unix and use the string it returns for FAT32 or exFAT - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT"); scan_total = 0; diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 05b55d4e1b..81811d2eb0 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -213,7 +213,7 @@ class EditorFileSystem : public Node { }; void _save_filesystem_cache(); - void _save_filesystem_cache(EditorFileSystemDirectory *p_dir, FileAccess *p_file); + void _save_filesystem_cache(EditorFileSystemDirectory *p_dir, Ref<FileAccess> p_file); bool _find_file(const String &p_file, EditorFileSystemDirectory **r_d, int &r_file_pos) const; @@ -225,7 +225,7 @@ class EditorFileSystem : public Node { Set<String> valid_extensions; Set<String> import_extensions; - void _scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess *da, const ScanProgress &p_progress); + void _scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAccess> &da, const ScanProgress &p_progress); Thread thread_sources; bool scanning_changes = false; diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp index 8d6ebd1154..548f05217e 100644 --- a/editor/editor_folding.cpp +++ b/editor/editor_folding.cpp @@ -131,7 +131,7 @@ void EditorFolding::_fill_folds(const Node *p_root, const Node *p_node, Array &p void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path) { ERR_FAIL_NULL(p_scene); - FileAccessRef file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES); + Ref<FileAccess> file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES); if (!file_check->file_exists(p_path)) { //This can happen when creating scene from FilesystemDock. It has path, but no file. return; } diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index 66fe3c4838..3e18499b97 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -218,7 +218,7 @@ Ref<FontData> load_cached_internal_font(const uint8_t *p_data, size_t p_size, Te } void editor_register_fonts(Ref<Theme> p_theme) { - DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); /* Custom font */ diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index a80c7853f5..99e30593a9 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -416,7 +416,7 @@ void EditorNode::_version_control_menu_option(int p_idx) { void EditorNode::_update_title() { const String appname = ProjectSettings::get_singleton()->get("application/config/name"); - String title = (appname.is_empty() ? "Unnamed Project" : appname) + String(" - ") + VERSION_NAME; + String title = (appname.is_empty() ? TTR("Unnamed Project") : appname) + String(" - ") + VERSION_NAME; const String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_scene_file_path() : String(); if (!edited.is_empty()) { // Display the edited scene name before the program name so that it can be seen in the OS task bar. @@ -935,7 +935,7 @@ void EditorNode::_fs_changed() { } if (export_preset.is_null()) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (da->file_exists("res://export_presets.cfg")) { export_error = vformat( "Invalid export preset name: %s.\nThe following presets were detected in this project's `export_presets.cfg`:\n\n", @@ -1058,7 +1058,7 @@ void EditorNode::_scan_external_changes() { // Check if any edited scene has changed. for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (editor_data.get_scene_path(i) == "" || !da->file_exists(editor_data.get_scene_path(i))) { continue; } @@ -5478,7 +5478,7 @@ void EditorNode::_global_menu_new_window(const Variant &p_tag) { } } -void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) { +void EditorNode::_dropped_files(const Vector<String> &p_files) { String to_path = ProjectSettings::get_singleton()->globalize_path(FileSystemDock::get_singleton()->get_selected_path()); _add_dropped_files_recursive(p_files, to_path); @@ -5487,7 +5487,7 @@ void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) { } void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, String to_path) { - DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < p_files.size(); i++) { String from = p_files[i]; @@ -5496,7 +5496,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str if (dir->dir_exists(from)) { Vector<String> sub_files; - DirAccessRef sub_dir = DirAccess::open(from); + Ref<DirAccess> sub_dir = DirAccess::open(from); sub_dir->list_dir_begin(); String next_file = sub_dir->get_next(); diff --git a/editor/editor_node.h b/editor/editor_node.h index 685714cb47..c6c1f09938 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -575,7 +575,7 @@ private: void _open_recent_scene(int p_idx); void _global_menu_scene(const Variant &p_tag); void _global_menu_new_window(const Variant &p_tag); - void _dropped_files(const Vector<String> &p_files, int p_screen); + void _dropped_files(const Vector<String> &p_files); void _add_dropped_files_recursive(const Vector<String> &p_files, String to_path); void _update_from_settings(); diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp index 7b454055e0..a5c2fe093c 100644 --- a/editor/editor_paths.cpp +++ b/editor/editor_paths.cpp @@ -97,7 +97,7 @@ EditorPaths::EditorPaths() { exe_path = exe_path.plus_file("../../..").simplify_path(); } { - DirAccessRef d = DirAccess::create_for_path(exe_path); + Ref<DirAccess> d = DirAccess::create_for_path(exe_path); if (d->file_exists(exe_path + "/._sc_")) { self_contained = true; @@ -141,7 +141,7 @@ EditorPaths::EditorPaths() { // Validate or create each dir and its relevant subdirectories. - DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); // Data dir. { @@ -197,7 +197,7 @@ EditorPaths::EditorPaths() { // Nothing to create, use shared editor data dir for shader cache. Engine::get_singleton()->set_shader_cache_path(data_dir); } else { - DirAccessRef dir_res = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> dir_res = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (dir_res->change_dir(project_data_dir) != OK) { dir_res->make_dir_recursive(project_data_dir); if (dir_res->change_dir(project_data_dir) != OK) { @@ -210,10 +210,9 @@ EditorPaths::EditorPaths() { String project_data_gdignore_file_path = project_data_dir.plus_file(".gdignore"); if (!FileAccess::exists(project_data_gdignore_file_path)) { // Add an empty .gdignore file to avoid scan. - FileAccessRef f = FileAccess::open(project_data_gdignore_file_path, FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(project_data_gdignore_file_path, FileAccess::WRITE); + if (f.is_valid()) { f->store_line(""); - f->close(); } else { ERR_PRINT("Failed to create file " + project_data_gdignore_file_path); } diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index b6f48c7536..b728ce64c9 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -161,7 +161,7 @@ void EditorPluginSettings::_cell_button_pressed(Object *p_item, int p_column, in } Vector<String> EditorPluginSettings::_get_plugins(const String &p_dir) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); Error err = da->change_dir(p_dir); if (err != OK) { return Vector<String>(); diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 2bc92427e5..aa10d7e68e 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -199,14 +199,12 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref< if (has_small_texture) { ResourceSaver::save(cache_base + "_small.png", r_small_texture); } - FileAccess *f = FileAccess::open(cache_base + ".txt", FileAccess::WRITE); - ERR_FAIL_COND_MSG(!f, "Cannot create file '" + cache_base + ".txt'. Check user write permissions."); + Ref<FileAccess> f = FileAccess::open(cache_base + ".txt", FileAccess::WRITE); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + cache_base + ".txt'. Check user write permissions."); f->store_line(itos(thumbnail_size)); f->store_line(itos(has_small_texture)); f->store_line(itos(FileAccess::get_modified_time(p_item.path))); f->store_line(FileAccess::get_md5(p_item.path)); - f->close(); - memdelete(f); } } } @@ -251,8 +249,8 @@ void EditorResourcePreview::_iterate() { //does not have it, try to load a cached thumbnail String file = cache_base + ".txt"; - FileAccess *f = FileAccess::open(file, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(file, FileAccess::READ); + if (f.is_null()) { // No cache found, generate _generate_preview(texture, small_texture, item, cache_base); } else { @@ -265,11 +263,9 @@ void EditorResourcePreview::_iterate() { if (tsize != thumbnail_size) { cache_valid = false; - memdelete(f); } else if (last_modtime != modtime) { String last_md5 = f->get_line(); String md5 = FileAccess::get_md5(item.path); - memdelete(f); if (last_md5 != md5) { cache_valid = false; @@ -278,7 +274,7 @@ void EditorResourcePreview::_iterate() { //update modified time f = FileAccess::open(file, FileAccess::WRITE); - if (!f) { + if (f.is_null()) { // Not returning as this would leave the thread hanging and would require // some proper cleanup/disabling of resource preview generation. ERR_PRINT("Cannot create file '" + file + "'. Check user write permissions."); @@ -287,11 +283,8 @@ void EditorResourcePreview::_iterate() { f->store_line(itos(has_small_texture)); f->store_line(itos(modtime)); f->store_line(md5); - memdelete(f); } } - } else { - memdelete(f); } if (cache_valid) { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 4ddc66ed98..4acbc32e7c 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -842,7 +842,7 @@ void EditorSettings::create() { if (EditorPaths::get_singleton()->are_paths_valid()) { // Validate editor config file. - DirAccessRef dir = DirAccess::open(EditorPaths::get_singleton()->get_config_dir()); + 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); if (!dir->file_exists(config_file_name)) { @@ -1151,12 +1151,11 @@ void EditorSettings::set_favorites(const Vector<String> &p_favorites) { } else { favorites_file = get_project_settings_dir().plus_file("favorites"); } - FileAccess *f = FileAccess::open(favorites_file, FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::WRITE); + if (f.is_valid()) { for (int i = 0; i < favorites.size(); i++) { f->store_line(favorites[i]); } - memdelete(f); } } @@ -1172,12 +1171,11 @@ void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs) { } else { recent_dirs_file = get_project_settings_dir().plus_file("recent_dirs"); } - FileAccess *f = FileAccess::open(recent_dirs_file, FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(recent_dirs_file, FileAccess::WRITE); + if (f.is_valid()) { for (int i = 0; i < recent_dirs.size(); i++) { f->store_line(recent_dirs[i]); } - memdelete(f); } } @@ -1195,24 +1193,22 @@ void EditorSettings::load_favorites_and_recent_dirs() { favorites_file = get_project_settings_dir().plus_file("favorites"); recent_dirs_file = get_project_settings_dir().plus_file("recent_dirs"); } - FileAccess *f = FileAccess::open(favorites_file, FileAccess::READ); - if (f) { + Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::READ); + if (f.is_valid()) { String line = f->get_line().strip_edges(); while (!line.is_empty()) { favorites.push_back(line); line = f->get_line().strip_edges(); } - memdelete(f); } f = FileAccess::open(recent_dirs_file, FileAccess::READ); - if (f) { + if (f.is_valid()) { String line = f->get_line().strip_edges(); while (!line.is_empty()) { recent_dirs.push_back(line); line = f->get_line().strip_edges(); } - memdelete(f); } } @@ -1227,8 +1223,8 @@ bool EditorSettings::is_dark_theme() { void EditorSettings::list_text_editor_themes() { String themes = "Default,Godot 2,Custom"; - DirAccessRef d = DirAccess::open(get_text_editor_themes_dir()); - if (d) { + Ref<DirAccess> d = DirAccess::open(get_text_editor_themes_dir()); + if (d.is_valid()) { List<String> custom_themes; d->list_dir_begin(); String file = d->get_next(); @@ -1293,8 +1289,8 @@ bool EditorSettings::import_text_editor_theme(String p_file) { return false; } - DirAccessRef d = DirAccess::open(get_text_editor_themes_dir()); - if (d) { + Ref<DirAccess> d = DirAccess::open(get_text_editor_themes_dir()); + if (d.is_valid()) { d->copy(p_file, get_text_editor_themes_dir().plus_file(p_file.get_file())); return true; } @@ -1345,8 +1341,8 @@ Vector<String> EditorSettings::get_script_templates(const String &p_extension, c if (!p_custom_path.is_empty()) { template_dir = p_custom_path; } - DirAccessRef d = DirAccess::open(template_dir); - if (d) { + Ref<DirAccess> d = DirAccess::open(template_dir); + if (d.is_valid()) { d->list_dir_begin(); String file = d->get_next(); while (!file.is_empty()) { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 1fea759a90..f4082746d8 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -1220,10 +1220,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("breakpoint", "CodeEdit", theme->get_icon(SNAME("Breakpoint"), SNAME("EditorIcons"))); theme->set_constant("line_spacing", "CodeEdit", EDITOR_GET("text_editor/appearance/whitespace/line_spacing")); - // H/VSplitContainer - theme->set_stylebox("bg", "VSplitContainer", make_stylebox(theme->get_icon(SNAME("GuiVsplitBg"), SNAME("EditorIcons")), 1, 1, 1, 1)); - theme->set_stylebox("bg", "HSplitContainer", make_stylebox(theme->get_icon(SNAME("GuiHsplitBg"), SNAME("EditorIcons")), 1, 1, 1, 1)); - theme->set_icon("grabber", "VSplitContainer", theme->get_icon(SNAME("GuiVsplitter"), SNAME("EditorIcons"))); theme->set_icon("grabber", "HSplitContainer", theme->get_icon(SNAME("GuiHsplitter"), SNAME("EditorIcons"))); diff --git a/editor/editor_translation.cpp b/editor/editor_translation.cpp index f64adcf0a1..b08e5807e7 100644 --- a/editor/editor_translation.cpp +++ b/editor/editor_translation.cpp @@ -59,7 +59,8 @@ void load_editor_translations(const String &p_locale) { int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); - FileAccessMemory *fa = memnew(FileAccessMemory); + Ref<FileAccessMemory> fa; + fa.instantiate(); fa->open_custom(data.ptr(), data.size()); Ref<Translation> tr = TranslationLoaderPO::load_translation(fa); @@ -84,7 +85,8 @@ void load_doc_translations(const String &p_locale) { int ret = Compression::decompress(data.ptrw(), dtl->uncomp_size, dtl->data, dtl->comp_size, Compression::MODE_DEFLATE); ERR_FAIL_COND_MSG(ret == -1, "Compressed file is corrupt."); - FileAccessMemory *fa = memnew(FileAccessMemory); + Ref<FileAccessMemory> fa; + fa.instantiate(); fa->open_custom(data.ptr(), data.size()); Ref<Translation> tr = TranslationLoaderPO::load_translation(fa); diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp index 0954779300..3f2012cc16 100644 --- a/editor/editor_vcs_interface.cpp +++ b/editor/editor_vcs_interface.cpp @@ -168,21 +168,19 @@ 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) { - FileAccess *f = FileAccess::open(p_dir.plus_file(".gitignore"), FileAccess::WRITE); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_dir.plus_file(".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/"); - memdelete(f); } f = FileAccess::open(p_dir.plus_file(".gitattributes"), FileAccess::WRITE); - if (!f) { + if (f.is_null()) { ERR_FAIL_MSG(TTR("Couldn't create .gitattributes in project path.")); } else { f->store_line("# Normalize EOL for all files that Git considers text files."); f->store_line("* text=auto eol=lf"); - memdelete(f); } } } diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index f93c2df13d..a1fd2d9049 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -44,7 +44,7 @@ void ExportTemplateManager::_update_template_status() { // Fetch installed templates from the file system. - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); const String &templates_dir = EditorSettings::get_singleton()->get_templates_dir(); Error err = da->change_dir(templates_dir); @@ -194,7 +194,7 @@ void ExportTemplateManager::_download_template_completed(int p_status, int p_cod bool ret = _install_file_selected(path, true); if (ret) { // Clean up downloaded file. - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Error err = da->remove(path); if (err != OK) { EditorNode::get_singleton()->add_io_error(TTR("Cannot remove temporary file:") + "\n" + path + "\n"); @@ -374,10 +374,7 @@ void ExportTemplateManager::_install_file() { } bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_skip_progress) { - // unzClose() will take care of closing the file stored in the unzFile, - // so we don't need to `memdelete(fa)` in this method. - FileAccess *fa = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&fa); + zlib_filefunc_def io = zipio_create_io(); unzFile pkg = unzOpen2(p_file.utf8().get_data(), &io); if (!pkg) { @@ -441,7 +438,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_ return false; } - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version); Error err = d->make_dir_recursive(template_path); if (err != OK) { @@ -492,8 +489,8 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_ base_dir = base_dir.substr(contents_dir.length(), file_path.length()).trim_prefix("/"); file = base_dir.plus_file(file); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_CONTINUE(!da); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_CONTINUE(da.is_null()); String output_dir = template_path.plus_file(base_dir); @@ -508,9 +505,9 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_ } String to_write = template_path.plus_file(file); - FileAccessRef f = FileAccess::open(to_write, FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE); - if (!f) { + if (f.is_null()) { ret = unzGoToNextFile(pkg); fc++; ERR_CONTINUE_MSG(true, "Can't open file from path '" + String(to_write) + "'."); @@ -542,7 +539,7 @@ void ExportTemplateManager::_uninstall_template(const String &p_version) { } void ExportTemplateManager::_uninstall_template_confirmed() { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); const String &templates_dir = EditorSettings::get_singleton()->get_templates_dir(); Error err = da->change_dir(templates_dir); @@ -656,17 +653,16 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_ // To support custom Android builds, we install the Java source code and buildsystem // from android_source.zip to the project's res://android folder. - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE); // Make res://android dir (if it does not exist). da->make_dir("android"); { // Add version, to ensure building won't work if template and Godot version don't match. - FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::WRITE); - ERR_FAIL_COND_V(!f, ERR_CANT_CREATE); + Ref<FileAccess> f = FileAccess::open("res://android/.build_version", FileAccess::WRITE); + ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE); f->store_line(VERSION_FULL_CONFIG); - f->close(); } // Create the android plugins directory. @@ -677,16 +673,14 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_ ERR_FAIL_COND_V(err != OK, err); { // Add an empty .gdignore file to avoid scan. - FileAccessRef f = FileAccess::open("res://android/build/.gdignore", FileAccess::WRITE); - ERR_FAIL_COND_V(!f, ERR_CANT_CREATE); + Ref<FileAccess> f = FileAccess::open("res://android/build/.gdignore", FileAccess::WRITE); + ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE); f->store_line(""); - f->close(); } // Uncompress source template. - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); unzFile pkg = unzOpen2(p_file.utf8().get_data(), &io); ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android sources not in ZIP format."); @@ -731,10 +725,9 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_ } String to_write = String("res://android/build").plus_file(path); - FileAccess *f = FileAccess::open(to_write, FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE); + if (f.is_valid()) { f->store_buffer(data.ptr(), data.size()); - memdelete(f); #ifndef WINDOWS_ENABLED FileAccess::set_unix_permissions(to_write, (info.external_fa >> 16) & 0x01FF); #endif diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp index 30dc9180e3..46fb767c00 100644 --- a/editor/fileserver/editor_file_server.cpp +++ b/editor/fileserver/editor_file_server.cpp @@ -46,7 +46,6 @@ void EditorFileServer::_close_client(ClientData *cd) { cd->efs->to_wait.insert(cd->thread); } while (cd->files.size()) { - memdelete(cd->files.front()->get()); cd->files.erase(cd->files.front()); } memdelete(cd); @@ -181,8 +180,8 @@ void EditorFileServer::_subthread_start(void *s) { break; } - FileAccess *fa = FileAccess::open(s2, FileAccess::READ); - if (!fa) { + Ref<FileAccess> fa = FileAccess::open(s2, FileAccess::READ); + if (fa.is_null()) { //not found, continue encode_uint32(id, buf4); cd->connection->put_data(buf4, 4); @@ -249,7 +248,6 @@ void EditorFileServer::_subthread_start(void *s) { case FileAccessNetwork::COMMAND_CLOSE: { print_verbose("CLOSED"); ERR_CONTINUE(!cd->files.has(id)); - memdelete(cd->files[id]); cd->files.erase(id); } break; } diff --git a/editor/fileserver/editor_file_server.h b/editor/fileserver/editor_file_server.h index a1bb7ecf4e..ccebd1465d 100644 --- a/editor/fileserver/editor_file_server.h +++ b/editor/fileserver/editor_file_server.h @@ -49,7 +49,7 @@ class EditorFileServer : public Object { struct ClientData { Thread *thread = nullptr; Ref<StreamPeerTCP> connection; - Map<int, FileAccess *> files; + Map<int, Ref<FileAccess>> files; EditorFileServer *efs = nullptr; bool quit = false; }; diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index f6d00470d1..a45568db48 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -225,13 +225,14 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo Vector<String> favorite_paths = EditorSettings::get_singleton()->get_favorites(); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); bool fav_changed = false; for (int i = favorite_paths.size() - 1; i >= 0; i--) { - if (!da->dir_exists(favorite_paths[i])) { - favorite_paths.remove_at(i); - fav_changed = true; + if (da->dir_exists(favorite_paths[i]) || da->file_exists(favorite_paths[i])) { + continue; } + favorite_paths.remove_at(i); + fav_changed = true; } if (fav_changed) { EditorSettings::get_singleton()->set_favorites(favorite_paths); @@ -538,7 +539,7 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa if (target_path.ends_with("/")) { target_path = target_path.substr(0, target_path.length() - 1); } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (da->file_exists(p_path)) { path = target_path; } else if (da->dir_exists(p_path)) { @@ -1182,7 +1183,7 @@ void FileSystemDock::_try_move_item(const FileOrFolder &p_item, const String &p_ _get_all_items_in_dir(EditorFileSystem::get_singleton()->get_filesystem_path(old_path), file_changed_paths, folder_changed_paths); } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); print_verbose("Moving " + old_path + " -> " + new_path); Error err = da->rename(old_path, new_path); if (err == OK) { @@ -1240,7 +1241,7 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin return; } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); print_verbose("Duplicating " + old_path + " -> " + new_path); Error err = p_item.is_file ? da->copy(old_path, new_path) : da->copy_dir(old_path, new_path); if (err == OK) { @@ -1259,7 +1260,7 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin cfg->save(new_path + ".import"); } else if (p_item.is_file && (old_path.get_extension() == "tscn" || old_path.get_extension() == "tres")) { // FIXME: Quick hack to fix text resources. This should be fixed properly. - FileAccessRef file = FileAccess::open(old_path, FileAccess::READ, &err); + Ref<FileAccess> file = FileAccess::open(old_path, FileAccess::READ, &err); if (err == OK) { PackedStringArray lines = file->get_as_utf8_string().split("\n"); String line = lines[0]; @@ -1268,7 +1269,7 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin line = line.substr(0, line.find(" uid")) + "]"; lines.write[0] = line; - FileAccessRef file2 = FileAccess::open(new_path, FileAccess::WRITE, &err); + Ref<FileAccess> file2 = FileAccess::open(new_path, FileAccess::WRITE, &err); if (err == OK) { file2->store_string(String("\n").join(lines)); } @@ -1428,11 +1429,11 @@ void FileSystemDock::_make_dir_confirm() { } print_verbose("Making folder " + dir_name + " in " + directory); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); Error err = da->change_dir(directory); ERR_FAIL_COND_MSG(err != OK, "Cannot open directory '" + directory + "'."); - if (da->dir_exists(directory)) { + if (da->dir_exists(dir_name)) { EditorNode::get_singleton()->show_warning(TTR("Could not create folder. File with that name already exists.")); return; } @@ -1478,7 +1479,7 @@ void FileSystemDock::_make_scene_confirm() { scene_name = directory.plus_file(scene_name); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (da->file_exists(scene_name)) { EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists.")); return; @@ -1493,7 +1494,7 @@ void FileSystemDock::_file_removed(String p_file) { // Find the closest parent directory available, in case multiple items were deleted along the same path. path = p_file.get_base_dir(); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); while (!da->dir_exists(path)) { path = path.get_base_dir(); } @@ -1506,7 +1507,7 @@ void FileSystemDock::_folder_removed(String p_folder) { // Find the closest parent directory available, in case multiple items were deleted along the same path. path = p_folder.get_base_dir(); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); while (!da->dir_exists(path)) { path = path.get_base_dir(); } @@ -1545,7 +1546,7 @@ void FileSystemDock::_rename_operation_confirm() { } // Present a more user friendly warning for name conflict. - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); #if defined(WINDOWS_ENABLED) || defined(UWP_ENABLED) // Workaround case insensitivity on Windows. if ((da->file_exists(new_path) || da->dir_exists(new_path)) && new_path.to_lower() != old_path.to_lower()) { @@ -1598,7 +1599,7 @@ void FileSystemDock::_duplicate_operation_confirm() { String new_path = base_dir.plus_file(new_name); // Present a more user friendly warning for name conflict - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (da->file_exists(new_path) || da->dir_exists(new_path)) { EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists.")); return; @@ -2353,7 +2354,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data, } int exist_counter = 1; - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); while (da->file_exists(new_path) || da->dir_exists(new_path)) { exist_counter++; new_path = vformat(new_path_base, exist_counter); @@ -2830,7 +2831,7 @@ void FileSystemDock::_get_imported_files(const String &p_path, Vector<String> &f return; } - DirAccessRef da = DirAccess::open(p_path); + Ref<DirAccess> da = DirAccess::open(p_path); da->list_dir_begin(); String n = da->get_next(); while (!n.is_empty()) { diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 0dfaaaa1f4..41191271a1 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -211,8 +211,8 @@ float FindInFiles::get_progress() const { } void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) { - DirAccessRef dir = DirAccess::open(path); - if (!dir) { + Ref<DirAccess> dir = DirAccess::open(path); + if (dir.is_null()) { print_verbose("Cannot open directory! " + path); return; } @@ -253,8 +253,8 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) { } void FindInFiles::_scan_file(String fpath) { - FileAccessRef f = FileAccess::open(fpath, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(fpath, FileAccess::READ); + if (f.is_null()) { print_verbose(String("Cannot open file ") + fpath); return; } @@ -274,8 +274,6 @@ void FindInFiles::_scan_file(String fpath) { emit_signal(SNAME(SIGNAL_RESULT_FOUND), fpath, line_number, begin, end, line); } } - - f->close(); } void FindInFiles::_bind_methods() { @@ -873,7 +871,7 @@ void FindInFilesPanel::_on_replace_all_clicked() { // Same as get_line, but preserves line ending characters. class ConservativeGetLine { public: - String get_line(FileAccess *f) { + String get_line(Ref<FileAccess> f) { _line_buffer.clear(); char32_t c = f->get_8(); @@ -908,8 +906,8 @@ void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result> // If there are unsaved changes, the user will be asked on focus, // however that means either losing changes or losing replaces. - FileAccessRef f = FileAccess::open(fpath, FileAccess::READ); - ERR_FAIL_COND_MSG(!f, "Cannot open file from path '" + fpath + "'."); + Ref<FileAccess> f = FileAccess::open(fpath, FileAccess::READ); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file from path '" + fpath + "'."); String buffer; int current_line = 1; @@ -958,8 +956,6 @@ void FindInFilesPanel::apply_replaces_in_file(String fpath, const Vector<Result> ERR_FAIL_COND_MSG(err != OK, "Cannot create file in path '" + fpath + "'."); f->store_string(buffer); - - f->close(); } String FindInFilesPanel::get_replace_text() { diff --git a/editor/icons/AnimationLibrary.svg b/editor/icons/AnimationLibrary.svg new file mode 100644 index 0000000000..0bac67d302 --- /dev/null +++ b/editor/icons/AnimationLibrary.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M14.519 2.006A6 6 0 0 0 8.599 8a6 6 0 0 0 5.92 5.994v-1.01a1 1 0 0 1-.92-.984 1 1 0 0 1 .92-.984V4.984a1 1 0 0 1-.92-.984 1 1 0 0 1 .92-.984Zm-3.432 2.996a1 1 0 0 1 .547.133 1 1 0 0 1 .367 1.365 1 1 0 0 1-1.367.365A1 1 0 0 1 10.27 5.5a1 1 0 0 1 .818-.498ZM11.111 9a1 1 0 0 1 .89.5 1 1 0 0 1-.367 1.365 1 1 0 0 1-1.365-.365 1 1 0 0 1 .365-1.365A1 1 0 0 1 11.111 9Z" style="fill:#e0e0e0;fill-opacity:1"/><path d="M11.094 2.104a6 6 0 0 0-5.92 5.994 6 6 0 0 0 5.92 5.994v-.023a5.795 6.506 0 0 1-2.89-3.104 1 1 0 0 1-1.36-.367 1 1 0 0 1 .365-1.365 1 1 0 0 1 .475-.135 5.795 6.506 0 0 1-.076-.984 5.795 6.506 0 0 1 .082-1.027 1 1 0 0 1-.48-.124 1 1 0 0 1-.366-1.365 1 1 0 0 1 .818-.498 1 1 0 0 1 .547.133 1 1 0 0 1 .004.002 5.795 6.506 0 0 1 2.881-3.076z" style="fill:#e0e0e0;fill-opacity:1"/><path d="M7.616 2.104a6 6 0 0 0-5.92 5.994 6 6 0 0 0 5.92 5.994v-.023a5.795 6.506 0 0 1-2.89-3.104 1 1 0 0 1-1.36-.367 1 1 0 0 1 .366-1.365 1 1 0 0 1 .474-.135 5.795 6.506 0 0 1-.076-.984 5.795 6.506 0 0 1 .082-1.027 1 1 0 0 1-.48-.124 1 1 0 0 1-.366-1.365 1 1 0 0 1 .819-.498 1 1 0 0 1 .547.133 1 1 0 0 1 .003.002 5.795 6.506 0 0 1 2.881-3.076z" style="fill:#e0e0e0;fill-opacity:1"/></svg> diff --git a/editor/icons/ArrayOccluder3D.svg b/editor/icons/ArrayOccluder3D.svg new file mode 100644 index 0000000000..ac45821897 --- /dev/null +++ b/editor/icons/ArrayOccluder3D.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 1c-1.104569 0-2 .8954305-2 2s.895431 2 2 2 2-.8954305 2-2-.895431-2-2-2zm-2 7v3h-3v2h3v3h2v-3h3v-2h-3v-3zm-8 3c-1.1045695 0-2 .895431-2 2s.8954305 2 2 2 2-.895431 2-2-.8954305-2-2-2z" fill="#ffca5f"/></svg> diff --git a/editor/icons/BoxOccluder3D.svg b/editor/icons/BoxOccluder3D.svg new file mode 100644 index 0000000000..3cee3db532 --- /dev/null +++ b/editor/icons/BoxOccluder3D.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m8 .88867188-.5058594.25390622a4.5 4.5 0 0 1 1.3789063 2.2988281l3.0664061 1.5332032-3.5546874 1.7753906a4.5 4.5 0 0 1 -1.6796875 1.6601562l.2949219.1464844v3.9414064l-4-2.001953v-1.7636721a4.5 4.5 0 0 1 -2-1.4179688v4.2968749l7 3.5 7-3.5v-7.2226561zm5 5.66796872v3.9394534l-4 2.001953v-3.9414064z"/><path d="m8 .88867188-.5058594.25390622a4.5 4.5 0 0 1 1.5058594 3.3574219 4.5 4.5 0 0 1 -4.5 4.5 4.5 4.5 0 0 1 -3.5-1.6855469v4.2968749l7 3.5 7-3.5v-7.2226561z" fill="#ffca5f"/></svg> diff --git a/editor/icons/GuiVsplitBg.svg b/editor/icons/GuiVsplitBg.svg deleted file mode 100644 index 9844fc2018..0000000000 --- a/editor/icons/GuiVsplitBg.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="8" viewBox="0 0 8 7.9999995" width="8" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h8v8h-8z" fill-opacity=".098039"/></svg> diff --git a/editor/icons/Occluder3D.svg b/editor/icons/Occluder3D.svg index 850e2651af..c91a77781b 100644 --- a/editor/icons/Occluder3D.svg +++ b/editor/icons/Occluder3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.90625 1a7 7 0 0 0 -1.2988281.1386719 4.5 4.5 0 0 1 3.3925781 4.3613281 4.5 4.5 0 0 1 -4.5 4.5 4.5 4.5 0 0 1 -4.359375-3.3886719 7 7 0 0 0 -.140625 1.3886719 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7 7 7 0 0 0 -.09375 0z" fill="#ffca5f" stroke-width=".365215"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 1a2 2 0 0 0 -1.730469 1h-3.0273435a4.5 4.5 0 0 1 .7285156 2h2.3007809a2 2 0 0 0 .728516.7304688v5.8554692l-3.6933594-3.6933599a4.5 4.5 0 0 1 -1.4140625 1.4140625l3.6933599 3.6933594h-5.8574224a2 2 0 0 0 -.7285156-.730469v-2.3046872a4.5 4.5 0 0 1 -2-.7285157v3.0351559a2 2 0 0 0 -1 1.728516 2 2 0 0 0 2 2 2 2 0 0 0 1.7304688-1h6.5410152a2 2 0 0 0 1.728516 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.03125-1.75h.03125v-6.5214844a2 2 0 0 0 1-1.7285156 2 2 0 0 0 -2-2z" fill="#ffca5f"/></svg> diff --git a/editor/icons/PolygonOccluder3D.svg b/editor/icons/PolygonOccluder3D.svg new file mode 100644 index 0000000000..fc87e5e086 --- /dev/null +++ b/editor/icons/PolygonOccluder3D.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#ffca5f" stroke-linejoin="round"><path d="m8.2421875 2a4.5 4.5 0 0 1 .7578125 2.5 4.5 4.5 0 0 1 -4.5 4.5 4.5 4.5 0 0 1 -2.5-.7636719v5.7636719h12l-6-6 6-6z" stroke-width="2"/><path d="m7.328125 1c.6472144.5230929 1.136703 1.2154082 1.4140625 2h2.8437505l-2.7675786 2.767578c-.2943505.9927946-.9220914 1.8536963-1.7773438 2.4375.0343146.1879491.1217471.3621363.2519532.501953l4.2929692 4.292969h-8.585938v-4.267578c-.785054-.2784421-1.4774185-.7693178-2-1.417969v6.685547c.0000552.552262.4477381.999945 1 1h12c.890637-.00035 1.336587-1.077036.707031-1.707031l-5.2929685-5.292969 5.2929685-5.292969c.629556-.6299945.183606-1.7066812-.707031-1.707031z"/></g></svg> diff --git a/editor/icons/QuadOccluder3D.svg b/editor/icons/QuadOccluder3D.svg new file mode 100644 index 0000000000..16da6f420f --- /dev/null +++ b/editor/icons/QuadOccluder3D.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.328125 1c.6472144.5230929 1.136703 1.2154082 1.4140625 2h4.2578125v8.585938l-4.6933594-4.6933599c-.3593282.5714479-.8426146 1.0547343-1.4140625 1.4140625l4.6933599 4.6933594h-8.585938v-4.2675781c-.785054-.2784421-1.4774185-.7693176-2-1.4179688v7.6855469h14v-14z" fill="#ffca5f"/></svg> diff --git a/editor/icons/SphereOccluder3D.svg b/editor/icons/SphereOccluder3D.svg new file mode 100644 index 0000000000..850e2651af --- /dev/null +++ b/editor/icons/SphereOccluder3D.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.90625 1a7 7 0 0 0 -1.2988281.1386719 4.5 4.5 0 0 1 3.3925781 4.3613281 4.5 4.5 0 0 1 -4.5 4.5 4.5 4.5 0 0 1 -4.359375-3.3886719 7 7 0 0 0 -.140625 1.3886719 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7 7 7 0 0 0 -.09375 0z" fill="#ffca5f" stroke-width=".365215"/></svg> diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 69fa64c24c..97fc33ad25 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -1801,7 +1801,14 @@ Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint3 name = state.animations[i]->get_name(); } - ap->add_animation(name, state.animations[i]); + Ref<AnimationLibrary> library; + if (!ap->has_animation_library("")) { + library.instantiate(); + ap->add_animation_library("", library); + } else { + library = ap->get_animation_library(""); + } + library->add_animation(name, state.animations[i]); } state.scene->add_child(ap, true); ap->set_owner(state.scene); diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp index f0ee14bdcb..ee6500a643 100644 --- a/editor/import/resource_importer_csv_translation.cpp +++ b/editor/import/resource_importer_csv_translation.cpp @@ -88,9 +88,8 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const break; } - FileAccessRef f = FileAccess::open(p_source_file, FileAccess::READ); - - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open file from path '" + p_source_file + "'."); + Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open file from path '" + p_source_file + "'."); Vector<String> line = f->get_csv_line(delimiter); ERR_FAIL_COND_V(line.size() <= 1, ERR_PARSE_ERROR); diff --git a/editor/import/resource_importer_image.cpp b/editor/import/resource_importer_image.cpp index e6a822d827..8514df76bb 100644 --- a/editor/import/resource_importer_image.cpp +++ b/editor/import/resource_importer_image.cpp @@ -71,10 +71,9 @@ void ResourceImporterImage::get_import_options(const String &p_path, List<Import } Error ResourceImporterImage::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { - FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); - - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file from path '" + p_source_file + "'."); + Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file from path '" + p_source_file + "'."); uint64_t len = f->get_length(); Vector<uint8_t> data; @@ -82,10 +81,8 @@ Error ResourceImporterImage::import(const String &p_source_file, const String &p f->get_buffer(data.ptrw(), len); - memdelete(f); - f = FileAccess::open(p_save_path + ".image", FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_CREATE, "Cannot create file in path '" + p_save_path + ".image'."); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_CREATE, "Cannot create file in path '" + p_save_path + ".image'."); //save the header GDIM const uint8_t header[4] = { 'G', 'D', 'I', 'M' }; @@ -95,8 +92,6 @@ Error ResourceImporterImage::import(const String &p_source_file, const String &p //SAVE the actual image f->store_buffer(data.ptr(), len); - memdelete(f); - return OK; } diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp index 9ddee9c058..7c0c99cd29 100644 --- a/editor/import/resource_importer_layered_texture.cpp +++ b/editor/import/resource_importer_layered_texture.cpp @@ -257,7 +257,7 @@ void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, cons } } - FileAccessRef f = FileAccess::open(p_to_path, FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(p_to_path, FileAccess::WRITE); f->store_8('G'); f->store_8('S'); f->store_8('T'); @@ -280,8 +280,6 @@ void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, cons for (int i = 0; i < mipmap_images.size(); i++) { ResourceImporterTexture::save_to_ctex_format(f, mipmap_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy); } - - f->close(); } Error ResourceImporterLayeredTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 9042f1e32c..308eb9cefa 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -44,8 +44,8 @@ uint32_t EditorOBJImporter::get_import_flags() const { } static Error _parse_material_library(const String &p_path, Map<String, Ref<StandardMaterial3D>> &material_map, List<String> *r_missing_deps) { - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path)); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path)); Ref<StandardMaterial3D> current; String current_name; @@ -203,8 +203,8 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Stand } static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, Vector3 p_offset_mesh, List<String> *r_missing_deps) { - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); Ref<ArrayMesh> mesh; mesh.instantiate(); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index e7c605aaf0..bfa71bfda4 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -473,7 +473,9 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I if (_teststr(animname, loop_strings[i])) { anim->set_loop_mode(Animation::LoopMode::LOOP_LINEAR); animname = _fixstr(animname, loop_strings[i]); - ap->rename_animation(E, animname); + + Ref<AnimationLibrary> library = ap->get_animation_library(ap->find_animation_library(anim)); + library->rename_animation(E, animname); } } } @@ -1019,7 +1021,8 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref< Ref<Animation> saved_anim = _save_animation_to_file(anim, save, path, keep_custom); if (saved_anim != anim) { - ap->add_animation(name, saved_anim); //replace + Ref<AnimationLibrary> al = ap->get_animation_library(ap->find_animation_library(anim)); + al->add_animation(name, saved_anim); //replace } } } @@ -1109,6 +1112,7 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_ } Ref<Animation> default_anim = anim->get_animation("default"); + Ref<AnimationLibrary> al = anim->get_animation_library(anim->find_animation(default_anim)); for (int i = 0; i < p_clips.size(); i += 7) { String name = p_clips[i]; @@ -1246,15 +1250,16 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_ new_anim->set_loop_mode(loop_mode); new_anim->set_length(to - from); - anim->add_animation(name, new_anim); + + al->add_animation(name, new_anim); Ref<Animation> saved_anim = _save_animation_to_file(new_anim, save_to_file, save_to_path, keep_current); if (saved_anim != new_anim) { - anim->add_animation(name, saved_anim); + al->add_animation(name, saved_anim); } } - anim->remove_animation("default"); //remove default (no longer needed) + al->remove_animation("default"); // Remove default (no longer needed). } void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle) { @@ -2086,14 +2091,13 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p _generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, mesh_lightmap_caches); if (mesh_lightmap_caches.size()) { - FileAccessRef f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE); + if (f.is_valid()) { f->store_32(mesh_lightmap_caches.size()); for (int i = 0; i < mesh_lightmap_caches.size(); i++) { String md5 = String::md5(mesh_lightmap_caches[i].ptr()); f->store_buffer(mesh_lightmap_caches[i].ptr(), mesh_lightmap_caches[i].size()); } - f->close(); } } err = OK; diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp index cc34259a2d..1d70a47daa 100644 --- a/editor/import/resource_importer_shader_file.cpp +++ b/editor/import/resource_importer_shader_file.cpp @@ -82,7 +82,7 @@ static String _include_function(const String &p_path, void *userpointer) { include = base_path->plus_file(include); } - FileAccessRef file_inc = FileAccess::open(include, FileAccess::READ, &err); + Ref<FileAccess> file_inc = FileAccess::open(include, FileAccess::READ, &err); if (err != OK) { return String(); } @@ -93,7 +93,7 @@ Error ResourceImporterShaderFile::import(const String &p_source_file, const Stri /* STEP 1, Read shader code */ Error err; - FileAccessRef file = FileAccess::open(p_source_file, FileAccess::READ, &err); + Ref<FileAccess> file = FileAccess::open(p_source_file, FileAccess::READ, &err); ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN); ERR_FAIL_COND_V(!file.operator->(), ERR_CANT_OPEN); diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index e2fa624fc6..de51a28c5a 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -229,7 +229,7 @@ void ResourceImporterTexture::get_import_options(const String &p_path, List<Impo } } -void ResourceImporterTexture::save_to_ctex_format(FileAccess *f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality) { +void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality) { switch (p_compress_mode) { case COMPRESS_LOSSLESS: { bool lossless_force_png = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/force_png") || @@ -322,8 +322,8 @@ void ResourceImporterTexture::save_to_ctex_format(FileAccess *f, const Ref<Image } void ResourceImporterTexture::_save_ctex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_roughness, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel) { - FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE); - ERR_FAIL_NULL(f); + Ref<FileAccess> f = FileAccess::open(p_to_path, FileAccess::WRITE); + ERR_FAIL_COND(f.is_null()); f->store_8('G'); f->store_8('S'); f->store_8('T'); @@ -399,8 +399,6 @@ void ResourceImporterTexture::_save_ctex(const Ref<Image> &p_image, const String Image::UsedChannels used_channels = image->detect_used_channels(csource); save_to_ctex_format(f, image, p_compress_mode, used_channels, p_vram_compression, p_lossy_quality); - - memdelete(f); } Error ResourceImporterTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h index b3a68260fc..b932c598a2 100644 --- a/editor/import/resource_importer_texture.h +++ b/editor/import/resource_importer_texture.h @@ -77,7 +77,7 @@ protected: void _save_ctex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel); public: - static void save_to_ctex_format(FileAccess *f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality); + static void save_to_ctex_format(Ref<FileAccess> f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality); static ResourceImporterTexture *get_singleton() { return singleton; } virtual String get_importer_name() const override; diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index 68d1d23dd8..154970f7ed 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -97,7 +97,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s /* STEP 1, READ WAVE FILE */ Error err; - FileAccess *file = FileAccess::open(p_source_file, FileAccess::READ, &err); + Ref<FileAccess> file = FileAccess::open(p_source_file, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); @@ -107,8 +107,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s file->get_buffer((uint8_t *)&riff, 4); //RIFF if (riff[0] != 'R' || riff[1] != 'I' || riff[2] != 'F' || riff[3] != 'F') { - file->close(); - memdelete(file); ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); } @@ -122,8 +120,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s file->get_buffer((uint8_t *)&wave, 4); //RIFF if (wave[0] != 'W' || wave[1] != 'A' || wave[2] != 'V' || wave[3] != 'E') { - file->close(); - memdelete(file); ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Not a WAV file (no WAVE RIFF header)."); } @@ -166,15 +162,11 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s //Consider revision for engine version 3.0 compression_code = file->get_16(); if (compression_code != 1 && compression_code != 3) { - file->close(); - memdelete(file); ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead."); } format_channels = file->get_16(); if (format_channels != 1 && format_channels != 2) { - file->close(); - memdelete(file); ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Format not supported for WAVE file (not stereo or mono)."); } @@ -185,8 +177,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s format_bits = file->get_16(); // bits per sample if (format_bits % 8 || format_bits == 0) { - file->close(); - memdelete(file); ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Invalid amount of bits in the sample (should be one of 8, 16, 24 or 32)."); } @@ -206,8 +196,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s frames = chunksize; if (format_channels == 0) { - file->close(); - memdelete(file); ERR_FAIL_COND_V(format_channels == 0, ERR_INVALID_DATA); } frames /= format_channels; @@ -254,8 +242,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s } if (file->eof_reached()) { - file->close(); - memdelete(file); ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Premature end of file."); } } @@ -295,9 +281,6 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s file->seek(file_pos + chunksize); } - file->close(); - memdelete(file); - // STEP 2, APPLY CONVERSIONS bool is16 = format_bits != 8; diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp index 02cc95e14a..755bf7ce07 100644 --- a/editor/plugin_config_dialog.cpp +++ b/editor/plugin_config_dialog.cpp @@ -50,8 +50,8 @@ void PluginConfigDialog::_on_confirmed() { String path = "res://addons/" + subfolder_edit->get_text(); if (!_edit_mode) { - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_RESOURCES); - if (!d || d->make_dir_recursive(path) != OK) { + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (d.is_null() || d->make_dir_recursive(path) != OK) { return; } } @@ -137,7 +137,7 @@ void PluginConfigDialog::_on_required_text_changed(const String &) { subfolder_validation->set_texture(invalid_icon); subfolder_validation->set_tooltip(TTR("Subfolder name is not a valid folder name.")); } else { - DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_RESOURCES); String path = "res://addons/" + subfolder_edit->get_text(); if (dir->dir_exists(path) && !_edit_mode) { // Only show this error if in "create" mode. is_valid = false; diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp new file mode 100644 index 0000000000..2e9a82a7c2 --- /dev/null +++ b/editor/plugins/animation_library_editor.cpp @@ -0,0 +1,689 @@ +/*************************************************************************/ +/* animation_library_editor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "animation_library_editor.h" +#include "editor/editor_file_dialog.h" +#include "editor/editor_node.h" +#include "editor/editor_scale.h" + +void AnimationLibraryEditor::set_animation_player(Object *p_player) { + player = p_player; +} + +void AnimationLibraryEditor::_add_library() { + add_library_dialog->set_title(TTR("Library Name:")); + add_library_name->set_text(""); + add_library_dialog->popup_centered(); + add_library_name->grab_focus(); + adding_animation = false; + adding_animation_to_library = StringName(); + _add_library_validate(""); +} + +void AnimationLibraryEditor::_add_library_validate(const String &p_name) { + String error; + + if (adding_animation) { + Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library); + ERR_FAIL_COND(al.is_null()); + if (p_name == "") { + error = TTR("Animation name can't be empty."); + + } else if (String(p_name).contains("/") || String(p_name).contains(":") || String(p_name).contains(",") || String(p_name).contains("[")) { + error = TTR("Animation name contains invalid characters: '/', ':', ',' or '['."); + } else if (al->has_animation(p_name)) { + error = TTR("Animation with the same name already exists."); + } + + } else { + if (p_name == "" && bool(player->call("has_animation_library", ""))) { + error = TTR("Enter a library name."); + } else if (String(p_name).contains("/") || String(p_name).contains(":") || String(p_name).contains(",") || String(p_name).contains("[")) { + error = TTR("Library name contains invalid characters: '/', ':', ',' or '['."); + } else if (bool(player->call("has_animation_library", p_name))) { + error = TTR("Library with the same name already exists."); + } + } + + if (error != "") { + add_library_validate->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor"))); + add_library_validate->set_text(error); + add_library_dialog->get_ok_button()->set_disabled(true); + } else { + add_library_validate->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor"))); + if (p_name == "") { + add_library_validate->set_text(TTR("Global library will be created.")); + } else { + add_library_validate->set_text(TTR("Library name is valid.")); + } + add_library_dialog->get_ok_button()->set_disabled(false); + } +} + +void AnimationLibraryEditor::_add_library_confirm() { + if (adding_animation) { + String anim_name = add_library_name->get_text(); + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library); + ERR_FAIL_COND(!al.is_valid()); + + Ref<Animation> anim; + anim.instantiate(); + + undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), anim_name)); + undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, anim); + undo_redo->add_undo_method(al.ptr(), "remove_animation", anim_name); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + + } else { + String lib_name = add_library_name->get_text(); + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + Ref<AnimationLibrary> al; + al.instantiate(); + + undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), lib_name)); + undo_redo->add_do_method(player, "add_animation_library", lib_name, al); + undo_redo->add_undo_method(player, "remove_animation_library", lib_name); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + } +} + +void AnimationLibraryEditor::_load_library() { + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("AnimationLibrary", &extensions); + + file_dialog->set_title(TTR("Load Animation")); + file_dialog->clear_filters(); + for (const String &K : extensions) { + file_dialog->add_filter("*." + K); + } + + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + file_dialog->set_current_file(""); + file_dialog->popup_centered_ratio(); + + file_dialog_action = FILE_DIALOG_ACTION_OPEN_LIBRARY; +} + +void AnimationLibraryEditor::_file_popup_selected(int p_id) { + Ref<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library); + Ref<Animation> anim; + if (file_dialog_animation != StringName()) { + anim = al->get_animation(file_dialog_animation); + ERR_FAIL_COND(anim.is_null()); + } + switch (p_id) { + case FILE_MENU_SAVE_LIBRARY: { + if (al->get_path().is_resource_file()) { + EditorNode::get_singleton()->save_resource(al); + break; + } + [[fallthrough]]; + } + case FILE_MENU_SAVE_AS_LIBRARY: { + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); + file_dialog->set_title(TTR("Save Library")); + if (al->get_path().is_resource_file()) { + file_dialog->set_current_path(al->get_path()); + } else { + file_dialog->set_current_file(String(file_dialog_library) + ".res"); + } + file_dialog->clear_filters(); + List<String> exts; + ResourceLoader::get_recognized_extensions_for_type("AnimationLibrary", &exts); + for (const String &K : exts) { + file_dialog->add_filter("*." + K); + } + + file_dialog->popup_centered_ratio(); + file_dialog_action = FILE_DIALOG_ACTION_SAVE_LIBRARY; + } break; + case FILE_MENU_MAKE_LIBRARY_UNIQUE: { + StringName lib_name = file_dialog_library; + + Ref<AnimationLibrary> ald = al->duplicate(); + + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name)); + undo_redo->add_do_method(player, "remove_animation_library", lib_name); + undo_redo->add_do_method(player, "add_animation_library", lib_name, ald); + undo_redo->add_undo_method(player, "remove_animation_library", lib_name); + undo_redo->add_undo_method(player, "add_animation_library", lib_name, al); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + + } break; + case FILE_MENU_EDIT_LIBRARY: { + EditorNode::get_singleton()->push_item(al.ptr()); + } break; + + case FILE_MENU_SAVE_ANIMATION: { + if (anim->get_path().is_resource_file()) { + EditorNode::get_singleton()->save_resource(anim); + break; + } + [[fallthrough]]; + } + case FILE_MENU_SAVE_AS_ANIMATION: { + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); + file_dialog->set_title(TTR("Save Animation")); + if (anim->get_path().is_resource_file()) { + file_dialog->set_current_path(anim->get_path()); + } else { + file_dialog->set_current_file(String(file_dialog_animation) + ".res"); + } + file_dialog->clear_filters(); + List<String> exts; + ResourceLoader::get_recognized_extensions_for_type("Animation", &exts); + for (const String &K : exts) { + file_dialog->add_filter("*." + K); + } + + file_dialog->popup_centered_ratio(); + file_dialog_action = FILE_DIALOG_ACTION_SAVE_ANIMATION; + } break; + case FILE_MENU_MAKE_ANIMATION_UNIQUE: { + StringName anim_name = file_dialog_animation; + + Ref<Animation> animd = anim->duplicate(); + + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo->create_action(vformat(TTR("Make Animation Unique: %s"), anim_name)); + undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name); + undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, animd); + undo_redo->add_undo_method(al.ptr(), "remove_animation", anim_name); + undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + } break; + case FILE_MENU_EDIT_ANIMATION: { + EditorNode::get_singleton()->push_item(anim.ptr()); + } break; + } +} +void AnimationLibraryEditor::_load_file(String p_path) { + switch (file_dialog_action) { + case FILE_DIALOG_ACTION_OPEN_LIBRARY: { + Ref<AnimationLibrary> al = ResourceLoader::load(p_path); + if (al.is_null()) { + error_dialog->set_text(TTR("Invalid AnimationLibrary file.")); + error_dialog->popup_centered(); + return; + } + + TypedArray<StringName> libs = player->call("get_animation_library_list"); + for (int i = 0; i < libs.size(); i++) { + const StringName K = libs[i]; + Ref<AnimationLibrary> al2 = player->call("get_animation_library", K); + if (al2 == al) { + error_dialog->set_text(TTR("This library is already added to the player.")); + error_dialog->popup_centered(); + + return; + } + } + + String name = p_path.get_file().get_basename(); + + int attempt = 1; + + while (bool(player->call("has_animation_library", name))) { + attempt++; + name = p_path.get_file().get_basename() + " " + itos(attempt); + } + + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name)); + undo_redo->add_do_method(player, "add_animation_library", name, al); + undo_redo->add_undo_method(player, "remove_animation_library", name); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + } break; + case FILE_DIALOG_ACTION_OPEN_ANIMATION: { + Ref<Animation> anim = ResourceLoader::load(p_path); + if (anim.is_null()) { + error_dialog->set_text(TTR("Invalid Animation file.")); + error_dialog->popup_centered(); + return; + } + + Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library); + List<StringName> anims; + al->get_animation_list(&anims); + for (const StringName &K : anims) { + Ref<Animation> a2 = al->get_animation(K); + if (a2 == anim) { + error_dialog->set_text(TTR("This animation is already added to the library.")); + error_dialog->popup_centered(); + return; + } + } + + String name = p_path.get_file().get_basename(); + + int attempt = 1; + + while (al->has_animation(name)) { + attempt++; + name = p_path.get_file().get_basename() + " " + itos(attempt); + } + + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name)); + undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); + undo_redo->add_undo_method(al.ptr(), "remove_animation", name); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + } break; + + case FILE_DIALOG_ACTION_SAVE_LIBRARY: { + Ref<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library); + String prev_path = al->get_path(); + EditorNode::get_singleton()->save_resource_in_path(al, p_path); + + if (al->get_path() != prev_path) { // Save successful. + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + undo_redo->create_action(vformat(TTR("Save Animation library to File: %s"), file_dialog_library)); + undo_redo->add_do_method(al.ptr(), "set_path", al->get_path()); + undo_redo->add_undo_method(al.ptr(), "set_path", prev_path); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + } + + } break; + case FILE_DIALOG_ACTION_SAVE_ANIMATION: { + Ref<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library); + Ref<Animation> anim; + if (file_dialog_animation != StringName()) { + anim = al->get_animation(file_dialog_animation); + ERR_FAIL_COND(anim.is_null()); + } + String prev_path = anim->get_path(); + EditorNode::get_singleton()->save_resource_in_path(anim, p_path); + if (anim->get_path() != prev_path) { // Save successful. + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + undo_redo->create_action(vformat(TTR("Save Animation to File: %s"), file_dialog_animation)); + undo_redo->add_do_method(anim.ptr(), "set_path", anim->get_path()); + undo_redo->add_undo_method(anim.ptr(), "set_path", prev_path); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + } + } break; + } +} + +void AnimationLibraryEditor::_item_renamed() { + TreeItem *ti = tree->get_edited(); + String text = ti->get_text(0); + String old_text = ti->get_metadata(0); + bool restore_text = false; + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + if (String(text).contains("/") || String(text).contains(":") || String(text).contains(",") || String(text).contains("[")) { + restore_text = true; + } else { + if (ti->get_parent() == tree->get_root()) { + // Renamed library + + if (player->call("has_animation_library", text)) { + restore_text = true; + } else { + undo_redo->create_action(vformat(TTR("Rename Animation Library: %s"), text)); + undo_redo->add_do_method(player, "rename_animation_library", old_text, text); + undo_redo->add_undo_method(player, "rename_animation_library", text, old_text); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + updating = true; + undo_redo->commit_action(); + updating = false; + ti->set_metadata(0, text); + if (text == "") { + ti->set_suffix(0, TTR("[Global]")); + } else { + ti->set_suffix(0, ""); + } + } + } else { + // Renamed anim + StringName library = ti->get_parent()->get_metadata(0); + Ref<AnimationLibrary> al = player->call("get_animation_library", library); + + if (al.is_valid()) { + if (al->has_animation(text)) { + restore_text = true; + } else { + undo_redo->create_action(vformat(TTR("Rename Animation: %s"), text)); + undo_redo->add_do_method(al.ptr(), "rename_animation", old_text, text); + undo_redo->add_undo_method(al.ptr(), "rename_animation", text, old_text); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + updating = true; + undo_redo->commit_action(); + updating = false; + + ti->set_metadata(0, text); + } + } else { + restore_text = true; + } + } + } + + if (restore_text) { + ti->set_text(0, old_text); + } +} + +void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int p_button) { + if (p_item->get_parent() == tree->get_root()) { + // Library + StringName lib_name = p_item->get_metadata(0); + Ref<AnimationLibrary> al = player->call("get_animation_library", lib_name); + switch (p_button) { + case LIB_BUTTON_ADD: { + add_library_dialog->set_title(TTR("Animation Name:")); + add_library_name->set_text(""); + add_library_dialog->popup_centered(); + add_library_name->grab_focus(); + adding_animation = true; + adding_animation_to_library = p_item->get_metadata(0); + _add_library_validate(""); + } break; + case LIB_BUTTON_LOAD: { + adding_animation_to_library = p_item->get_metadata(0); + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Animation", &extensions); + + file_dialog->clear_filters(); + for (const String &K : extensions) { + file_dialog->add_filter("*." + K); + } + + file_dialog->set_title(TTR("Load Animation")); + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + file_dialog->set_current_file(""); + file_dialog->popup_centered_ratio(); + + file_dialog_action = FILE_DIALOG_ACTION_OPEN_ANIMATION; + + } break; + case LIB_BUTTON_PASTE: { + Ref<Animation> anim = EditorSettings::get_singleton()->get_resource_clipboard(); + if (!anim.is_valid()) { + error_dialog->set_text(TTR("No animation resource in clipboard!")); + error_dialog->popup_centered(); + return; + } + + anim = anim->duplicate(); // Users simply dont care about referencing, so making a copy works better here. + + String base_name; + if (anim->get_name() != "") { + base_name = anim->get_name(); + } else { + base_name = TTR("Pasted Animation"); + } + + String name = base_name; + int attempt = 1; + while (al->has_animation(name)) { + attempt++; + name = base_name + " " + itos(attempt); + } + + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + + undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), name)); + undo_redo->add_do_method(al.ptr(), "add_animation", name, anim); + undo_redo->add_undo_method(al.ptr(), "remove_animation", name); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + + } break; + case LIB_BUTTON_FILE: { + file_popup->clear(); + file_popup->add_item(TTR("Save"), FILE_MENU_SAVE_LIBRARY); + file_popup->add_item(TTR("Save As"), FILE_MENU_SAVE_AS_LIBRARY); + file_popup->add_separator(); + file_popup->add_item(TTR("Make Unique"), FILE_MENU_MAKE_LIBRARY_UNIQUE); + file_popup->add_separator(); + file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_LIBRARY); + Rect2 pos = tree->get_item_rect(p_item, 1, 0); + Vector2 popup_pos = tree->get_screen_position() + pos.position + Vector2(0, pos.size.height); + file_popup->popup(Rect2(popup_pos, Size2())); + + file_dialog_animation = StringName(); + file_dialog_library = lib_name; + } break; + case LIB_BUTTON_DELETE: { + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo->create_action(vformat(TTR("Remove Animation Library: %s"), lib_name)); + undo_redo->add_do_method(player, "remove_animation_library", lib_name); + undo_redo->add_undo_method(player, "add_animation_library", lib_name, al); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + } break; + } + + } else { + // Animation + StringName lib_name = p_item->get_parent()->get_metadata(0); + StringName anim_name = p_item->get_metadata(0); + Ref<AnimationLibrary> al = player->call("get_animation_library", lib_name); + Ref<Animation> anim = al->get_animation(anim_name); + ERR_FAIL_COND(!anim.is_valid()); + switch (p_button) { + case ANIM_BUTTON_COPY: { + if (anim->get_name() == "") { + anim->set_name(anim_name); // Keep the name around + } + EditorSettings::get_singleton()->set_resource_clipboard(anim); + } break; + case ANIM_BUTTON_FILE: { + file_popup->clear(); + file_popup->add_item(TTR("Save"), FILE_MENU_SAVE_ANIMATION); + file_popup->add_item(TTR("Save As"), FILE_MENU_SAVE_AS_ANIMATION); + file_popup->add_separator(); + file_popup->add_item(TTR("Make Unique"), FILE_MENU_MAKE_ANIMATION_UNIQUE); + file_popup->add_separator(); + file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_ANIMATION); + Rect2 pos = tree->get_item_rect(p_item, 1, 0); + Vector2 popup_pos = tree->get_screen_position() + pos.position + Vector2(0, pos.size.height); + file_popup->popup(Rect2(popup_pos, Size2())); + + file_dialog_animation = anim_name; + file_dialog_library = lib_name; + + } break; + case ANIM_BUTTON_DELETE: { + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo->create_action(vformat(TTR("Remove Animation from Library: %s"), anim_name)); + undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name); + undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim); + undo_redo->add_do_method(this, "_update_editor", player); + undo_redo->add_undo_method(this, "_update_editor", player); + undo_redo->commit_action(); + } break; + } + } +} + +void AnimationLibraryEditor::update_tree() { + if (updating) { + return; + } + + tree->clear(); + ERR_FAIL_COND(!player); + + Color ss_color = get_theme_color(SNAME("prop_subsection"), SNAME("Editor")); + + TreeItem *root = tree->create_item(); + TypedArray<StringName> libs = player->call("get_animation_library_list"); + + for (int i = 0; i < libs.size(); i++) { + const StringName K = libs[i]; + TreeItem *libitem = tree->create_item(root); + libitem->set_text(0, K); + if (K == StringName()) { + libitem->set_suffix(0, TTR("[Global]")); + } else { + libitem->set_suffix(0, ""); + } + libitem->set_editable(0, true); + libitem->set_metadata(0, K); + libitem->set_icon(0, get_theme_icon("AnimationLibrary", "EditorIcons")); + libitem->add_button(0, get_theme_icon("Add", "EditorIcons"), LIB_BUTTON_ADD, false, TTR("Add Animation to Library")); + libitem->add_button(0, get_theme_icon("Load", "EditorIcons"), LIB_BUTTON_LOAD, false, TTR("Load animation from file and add to library")); + libitem->add_button(0, get_theme_icon("ActionPaste", "EditorIcons"), LIB_BUTTON_PASTE, false, TTR("Paste Animation to Library from clipboard")); + Ref<AnimationLibrary> al = player->call("get_animation_library", K); + if (al->get_path().is_resource_file()) { + libitem->set_text(1, al->get_path().get_file()); + libitem->set_tooltip(1, al->get_path()); + } else { + libitem->set_text(1, TTR("[built-in]")); + } + libitem->add_button(1, get_theme_icon("Save", "EditorIcons"), LIB_BUTTON_FILE, false, TTR("Save animation library to resource on disk")); + libitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), LIB_BUTTON_DELETE, false, TTR("Remove animation library")); + + libitem->set_custom_bg_color(0, ss_color); + + List<StringName> animations; + al->get_animation_list(&animations); + for (const StringName &L : animations) { + TreeItem *anitem = tree->create_item(libitem); + anitem->set_text(0, L); + anitem->set_editable(0, true); + anitem->set_metadata(0, L); + anitem->set_icon(0, get_theme_icon("Animation", "EditorIcons")); + anitem->add_button(0, get_theme_icon("ActionCopy", "EditorIcons"), ANIM_BUTTON_COPY, false, TTR("Copy animation to clipboard")); + Ref<Animation> anim = al->get_animation(L); + + if (anim->get_path().is_resource_file()) { + anitem->set_text(1, anim->get_path().get_file()); + anitem->set_tooltip(1, anim->get_path()); + } else { + anitem->set_text(1, TTR("[built-in]")); + } + anitem->add_button(1, get_theme_icon("Save", "EditorIcons"), ANIM_BUTTON_FILE, false, TTR("Save animation to resource on disk")); + anitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), ANIM_BUTTON_DELETE, false, TTR("Remove animation from Library")); + } + } +} + +void AnimationLibraryEditor::show_dialog() { + update_tree(); + popup_centered_ratio(0.5); +} + +void AnimationLibraryEditor::_update_editor(Object *p_player) { + emit_signal("update_editor", p_player); +} + +void AnimationLibraryEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_update_editor", "player"), &AnimationLibraryEditor::_update_editor); + ADD_SIGNAL(MethodInfo("update_editor")); +} + +AnimationLibraryEditor::AnimationLibraryEditor() { + set_title(TTR("Edit Animation Libraries")); + + file_dialog = memnew(EditorFileDialog); + add_child(file_dialog); + file_dialog->connect("file_selected", callable_mp(this, &AnimationLibraryEditor::_load_file)); + + add_library_dialog = memnew(ConfirmationDialog); + VBoxContainer *dialog_vb = memnew(VBoxContainer); + add_library_name = memnew(LineEdit); + dialog_vb->add_child(add_library_name); + add_library_name->connect("text_changed", callable_mp(this, &AnimationLibraryEditor::_add_library_validate)); + add_child(add_library_dialog); + + add_library_validate = memnew(Label); + dialog_vb->add_child(add_library_validate); + add_library_dialog->add_child(dialog_vb); + add_library_dialog->connect("confirmed", callable_mp(this, &AnimationLibraryEditor::_add_library_confirm)); + add_library_dialog->register_text_enter(add_library_name); + + VBoxContainer *vb = memnew(VBoxContainer); + HBoxContainer *hb = memnew(HBoxContainer); + hb->add_spacer(true); + Button *b = memnew(Button(TTR("Add Library"))); + b->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_add_library)); + hb->add_child(b); + b = memnew(Button(TTR("Load Library"))); + b->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_load_library)); + hb->add_child(b); + vb->add_child(hb); + tree = memnew(Tree); + vb->add_child(tree); + + tree->set_columns(2); + tree->set_column_titles_visible(true); + tree->set_column_title(0, TTR("Resource")); + tree->set_column_title(1, TTR("Storage")); + tree->set_column_expand(0, true); + tree->set_column_custom_minimum_width(1, EDSCALE * 250); + tree->set_column_expand(1, false); + tree->set_hide_root(true); + tree->set_hide_folding(true); + tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); + + tree->connect("item_edited", callable_mp(this, &AnimationLibraryEditor::_item_renamed)); + tree->connect("button_pressed", callable_mp(this, &AnimationLibraryEditor::_button_pressed)); + + file_popup = memnew(PopupMenu); + add_child(file_popup); + file_popup->connect("id_pressed", callable_mp(this, &AnimationLibraryEditor::_file_popup_selected)); + + add_child(vb); + + error_dialog = memnew(AcceptDialog); + error_dialog->set_title(TTR("Error:")); + add_child(error_dialog); +} diff --git a/tests/scene/test_gui.h b/editor/plugins/animation_library_editor.h index a1807ed15c..5bd4e8d9e2 100644 --- a/tests/scene/test_gui.h +++ b/editor/plugins/animation_library_editor.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* test_gui.h */ +/* animation_library_editor.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,92 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef TEST_GUI_H -#define TEST_GUI_H +#ifndef ANIMATION_LIBRARY_EDITOR_H +#define ANIMATION_LIBRARY_EDITOR_H -class MainLoop; +#include "editor/animation_track_editor.h" +#include "editor/editor_plugin.h" +#include "scene/animation/animation_player.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/tree.h" -namespace TestGUI { +class EditorFileDialog; -MainLoop *test(); -} +class AnimationLibraryEditor : public AcceptDialog { + GDCLASS(AnimationLibraryEditor, AcceptDialog) -#endif + enum { + LIB_BUTTON_ADD, + LIB_BUTTON_LOAD, + LIB_BUTTON_PASTE, + LIB_BUTTON_FILE, + LIB_BUTTON_DELETE, + }; + enum { + ANIM_BUTTON_COPY, + ANIM_BUTTON_FILE, + ANIM_BUTTON_DELETE, + }; + + enum FileMenuAction { + FILE_MENU_SAVE_LIBRARY, + FILE_MENU_SAVE_AS_LIBRARY, + FILE_MENU_MAKE_LIBRARY_UNIQUE, + FILE_MENU_EDIT_LIBRARY, + + FILE_MENU_SAVE_ANIMATION, + FILE_MENU_SAVE_AS_ANIMATION, + FILE_MENU_MAKE_ANIMATION_UNIQUE, + FILE_MENU_EDIT_ANIMATION, + }; + + enum FileDialogAction { + FILE_DIALOG_ACTION_OPEN_LIBRARY, + FILE_DIALOG_ACTION_SAVE_LIBRARY, + FILE_DIALOG_ACTION_OPEN_ANIMATION, + FILE_DIALOG_ACTION_SAVE_ANIMATION, + }; + + FileDialogAction file_dialog_action = FILE_DIALOG_ACTION_OPEN_ANIMATION; + + StringName file_dialog_animation; + StringName file_dialog_library; + + AcceptDialog *error_dialog = nullptr; + bool adding_animation = false; + StringName adding_animation_to_library; + EditorFileDialog *file_dialog = nullptr; + ConfirmationDialog *add_library_dialog = nullptr; + LineEdit *add_library_name = nullptr; + Label *add_library_validate = nullptr; + PopupMenu *file_popup = nullptr; + + Tree *tree = nullptr; + + Object *player = nullptr; + + void _add_library(); + void _add_library_validate(const String &p_name); + void _add_library_confirm(); + void _load_library(); + void _load_file(String p_path); + + void _item_renamed(); + void _button_pressed(TreeItem *p_item, int p_column, int p_button); + + void _file_popup_selected(int p_id); + + bool updating = false; + +protected: + void _update_editor(Object *p_player); + static void _bind_methods(); + +public: + void set_animation_player(Object *p_player); + void show_dialog(); + void update_tree(); + AnimationLibraryEditor(); +}; + +#endif // ANIMATIONPLAYERLIBRARYEDITOR_H diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index af7c092d03..2081edca25 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -47,6 +47,8 @@ #include "scene/scene_string_names.h" #include "servers/rendering_server.h" +/////////////////////////////////// + void AnimationPlayerEditor::_node_removed(Node *p_node) { if (player && player == p_node) { player = nullptr; @@ -148,9 +150,7 @@ void AnimationPlayerEditor::_notification(int p_what) { #define ITEM_ICON(m_item, m_icon) tool_anim->get_popup()->set_item_icon(tool_anim->get_popup()->get_item_index(m_item), get_theme_icon(SNAME(m_icon), SNAME("EditorIcons"))) ITEM_ICON(TOOL_NEW_ANIM, "New"); - ITEM_ICON(TOOL_LOAD_ANIM, "Load"); - ITEM_ICON(TOOL_SAVE_ANIM, "Save"); - ITEM_ICON(TOOL_SAVE_AS_ANIM, "Save"); + ITEM_ICON(TOOL_ANIM_LIBRARY, "AnimationLibrary"); ITEM_ICON(TOOL_DUPLICATE_ANIM, "Duplicate"); ITEM_ICON(TOOL_RENAME_ANIM, "Rename"); ITEM_ICON(TOOL_EDIT_TRANSITIONS, "Blend"); @@ -166,7 +166,7 @@ void AnimationPlayerEditor::_autoplay_pressed() { if (updating) { return; } - if (animation->get_item_count() == 0) { + if (animation->has_selectable_items() == 0) { return; } @@ -192,10 +192,7 @@ void AnimationPlayerEditor::_autoplay_pressed() { } void AnimationPlayerEditor::_play_pressed() { - String current; - if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); - } + String current = _get_current(); if (!current.is_empty()) { if (current == player->get_assigned_animation()) { @@ -209,10 +206,7 @@ void AnimationPlayerEditor::_play_pressed() { } void AnimationPlayerEditor::_play_from_pressed() { - String current; - if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); - } + String current = _get_current(); if (!current.is_empty()) { float time = player->get_current_animation_position(); @@ -229,12 +223,15 @@ void AnimationPlayerEditor::_play_from_pressed() { stop->set_pressed(false); } -void AnimationPlayerEditor::_play_bw_pressed() { +String AnimationPlayerEditor::_get_current() const { String current; - if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { + if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count() && !animation->is_item_separator(animation->get_selected())) { current = animation->get_item_text(animation->get_selected()); } - + return current; +} +void AnimationPlayerEditor::_play_bw_pressed() { + String current = _get_current(); if (!current.is_empty()) { if (current == player->get_assigned_animation()) { player->stop(); //so it won't blend with itself @@ -247,10 +244,7 @@ void AnimationPlayerEditor::_play_bw_pressed() { } void AnimationPlayerEditor::_play_bw_from_pressed() { - String current; - if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); - } + String current = _get_current(); if (!current.is_empty()) { float time = player->get_current_animation_position(); @@ -282,10 +276,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) { } // when selecting an animation, the idea is that the only interesting behavior // ui-wise is that it should play/blend the next one if currently playing - String current; - if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); - } + String current = _get_current(); if (!current.is_empty()) { player->set_assigned_animation(current); @@ -330,6 +321,20 @@ void AnimationPlayerEditor::_animation_new() { break; } + List<StringName> libraries; + player->get_animation_library_list(&libraries); + library->clear(); + for (const StringName &K : libraries) { + library->add_item((K == StringName()) ? String(TTR("[Global]")) : String(K)); + library->set_item_metadata(0, String(K)); + } + + if (libraries.size() > 1) { + library->show(); + } else { + library->hide(); + } + name->set_text(base); name_dialog->popup_centered(Size2(300, 90)); name->select_all(); @@ -337,7 +342,7 @@ void AnimationPlayerEditor::_animation_new() { } void AnimationPlayerEditor::_animation_rename() { - if (animation->get_item_count() == 0) { + if (!animation->has_selectable_items()) { return; } int selected = animation->get_selected(); @@ -349,84 +354,11 @@ void AnimationPlayerEditor::_animation_rename() { name_dialog->popup_centered(Size2(300, 90)); name->select_all(); name->grab_focus(); -} - -void AnimationPlayerEditor::_animation_load() { - ERR_FAIL_COND(!player); - file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES); - file->clear_filters(); - List<String> extensions; - - ResourceLoader::get_recognized_extensions_for_type("Animation", &extensions); - for (const String &E : extensions) { - file->add_filter("*." + E + " ; " + E.to_upper()); - } - - file->popup_file_dialog(); -} - -void AnimationPlayerEditor::_animation_save_in_path(const Ref<Resource> &p_resource, const String &p_path) { - int flg = 0; - if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) { - flg |= ResourceSaver::FLAG_COMPRESS; - } - - String path = ProjectSettings::get_singleton()->localize_path(p_path); - Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); - - if (err != OK) { - EditorNode::get_singleton()->show_warning(TTR("Error saving resource!")); - return; - } - - ((Resource *)p_resource.ptr())->set_path(path); - EditorNode::get_singleton()->emit_signal(SNAME("resource_saved"), p_resource); -} - -void AnimationPlayerEditor::_animation_save(const Ref<Resource> &p_resource) { - if (p_resource->get_path().is_resource_file()) { - _animation_save_in_path(p_resource, p_resource->get_path()); - } else { - _animation_save_as(p_resource); - } -} - -void AnimationPlayerEditor::_animation_save_as(const Ref<Resource> &p_resource) { - file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); - - List<String> extensions; - ResourceSaver::get_recognized_extensions(p_resource, &extensions); - file->clear_filters(); - for (int i = 0; i < extensions.size(); i++) { - file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); - } - - String path; - //file->set_current_path(current_path); - if (!p_resource->get_path().is_empty()) { - path = p_resource->get_path(); - if (extensions.size()) { - if (extensions.find(p_resource->get_path().get_extension().to_lower()) == nullptr) { - path = p_resource->get_path().get_base_dir() + p_resource->get_name() + "." + extensions.front()->get(); - } - } - } else { - if (extensions.size()) { - if (!p_resource->get_name().is_empty()) { - path = p_resource->get_name() + "." + extensions.front()->get().to_lower(); - } else { - String resource_name_snake_case = p_resource->get_class().camelcase_to_underscore(); - path = "new_" + resource_name_snake_case + "." + extensions.front()->get().to_lower(); - } - } - } - file->set_current_path(path); - file->set_title(TTR("Save Resource As...")); - file->popup_file_dialog(); + library->hide(); } void AnimationPlayerEditor::_animation_remove() { - if (animation->get_item_count() == 0) { + if (!animation->has_selectable_items()) { return; } @@ -440,6 +372,9 @@ void AnimationPlayerEditor::_animation_remove_confirmed() { String current = animation->get_item_text(animation->get_selected()); Ref<Animation> anim = player->get_animation(current); + Ref<AnimationLibrary> al = player->get_animation_library(player->find_animation_library(anim)); + ERR_FAIL_COND(al.is_null()); + undo_redo->create_action(TTR("Remove Animation")); if (player->get_autoplay() == current) { undo_redo->add_do_method(player, "set_autoplay", ""); @@ -447,11 +382,11 @@ void AnimationPlayerEditor::_animation_remove_confirmed() { // Avoid having the autoplay icon linger around if there is only one animation in the player. undo_redo->add_do_method(this, "_animation_player_changed", player); } - undo_redo->add_do_method(player, "remove_animation", current); - undo_redo->add_undo_method(player, "add_animation", current, anim); + undo_redo->add_do_method(al.ptr(), "remove_animation", current); + undo_redo->add_undo_method(al.ptr(), "add_animation", current, anim); undo_redo->add_do_method(this, "_animation_player_changed", player); undo_redo->add_undo_method(this, "_animation_player_changed", player); - if (animation->get_item_count() == 1) { + if (animation->has_selectable_items() && animation->get_selectable_item(false) == animation->get_selectable_item(true)) { // Last item remaining. undo_redo->add_do_method(this, "_stop_onion_skinning"); undo_redo->add_undo_method(this, "_start_onion_skinning"); } @@ -498,7 +433,7 @@ void AnimationPlayerEditor::_animation_name_edited() { return; } - if (name_dialog_op == TOOL_RENAME_ANIM && animation->get_item_count() > 0 && animation->get_item_text(animation->get_selected()) == new_name) { + if (name_dialog_op == TOOL_RENAME_ANIM && animation->has_selectable_items() && animation->get_item_text(animation->get_selected()) == new_name) { name_dialog->hide(); return; } @@ -514,10 +449,13 @@ void AnimationPlayerEditor::_animation_name_edited() { String current = animation->get_item_text(animation->get_selected()); Ref<Animation> anim = player->get_animation(current); + Ref<AnimationLibrary> al = player->get_animation_library(player->find_animation_library(anim)); + ERR_FAIL_COND(al.is_null()); + undo_redo->create_action(TTR("Rename Animation")); - undo_redo->add_do_method(player, "rename_animation", current, new_name); + undo_redo->add_do_method(al.ptr(), "rename_animation", current, new_name); undo_redo->add_do_method(anim.ptr(), "set_name", new_name); - undo_redo->add_undo_method(player, "rename_animation", new_name, current); + undo_redo->add_undo_method(al.ptr(), "rename_animation", new_name, current); undo_redo->add_undo_method(anim.ptr(), "set_name", current); undo_redo->add_do_method(this, "_animation_player_changed", player); undo_redo->add_undo_method(this, "_animation_player_changed", player); @@ -530,15 +468,35 @@ void AnimationPlayerEditor::_animation_name_edited() { Ref<Animation> new_anim = Ref<Animation>(memnew(Animation)); new_anim->set_name(new_name); + Ref<AnimationLibrary> al; + if (library->is_visible()) { + al = player->get_animation_library(library->get_item_metadata(library->get_selected())); + } else { + if (player->has_animation_library("")) { + al = player->get_animation_library(""); + } + } + undo_redo->create_action(TTR("Add Animation")); - undo_redo->add_do_method(player, "add_animation", new_name, new_anim); - undo_redo->add_undo_method(player, "remove_animation", new_name); + + bool lib_added = false; + if (al.is_null()) { + al.instantiate(); + lib_added = true; + undo_redo->add_do_method(player, "add_animation_library", "", al); + } + + undo_redo->add_do_method(al.ptr(), "add_animation", new_name, new_anim); + undo_redo->add_undo_method(al.ptr(), "remove_animation", new_name); undo_redo->add_do_method(this, "_animation_player_changed", player); undo_redo->add_undo_method(this, "_animation_player_changed", player); - if (animation->get_item_count() == 0) { + if (!animation->has_selectable_items()) { undo_redo->add_do_method(this, "_start_onion_skinning"); undo_redo->add_undo_method(this, "_stop_onion_skinning"); } + if (lib_added) { + undo_redo->add_undo_method(player, "remove_animation_library", ""); + } undo_redo->commit_action(); _select_anim_by_name(new_name); @@ -551,9 +509,11 @@ void AnimationPlayerEditor::_animation_name_edited() { Ref<Animation> new_anim = _animation_clone(anim); new_anim->set_name(new_name); + Ref<AnimationLibrary> library = player->get_animation_library(player->find_animation_library(anim)); + undo_redo->create_action(TTR("Duplicate Animation")); - undo_redo->add_do_method(player, "add_animation", new_name, new_anim); - undo_redo->add_undo_method(player, "remove_animation", new_name); + undo_redo->add_do_method(library.ptr(), "add_animation", new_name, new_anim); + undo_redo->add_undo_method(library.ptr(), "remove_animation", new_name); undo_redo->add_do_method(player, "animation_set_next", new_name, player->animation_get_next(current)); undo_redo->add_do_method(this, "_animation_player_changed", player); undo_redo->add_undo_method(this, "_animation_player_changed", player); @@ -567,7 +527,7 @@ void AnimationPlayerEditor::_animation_name_edited() { } void AnimationPlayerEditor::_blend_editor_next_changed(const int p_idx) { - if (animation->get_item_count() == 0) { + if (!animation->has_selectable_items()) { return; } @@ -588,7 +548,7 @@ void AnimationPlayerEditor::_animation_blend() { blend_editor.tree->clear(); - if (animation->get_item_count() == 0) { + if (!animation->has_selectable_items()) { return; } @@ -643,7 +603,7 @@ void AnimationPlayerEditor::_blend_edited() { return; } - if (animation->get_item_count() == 0) { + if (!animation->has_selectable_items()) { return; } @@ -722,16 +682,16 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) { } void AnimationPlayerEditor::_animation_resource_edit() { - if (animation->get_item_count()) { - String current = animation->get_item_text(animation->get_selected()); + String current = _get_current(); + if (current != String()) { Ref<Animation> anim = player->get_animation(current); EditorNode::get_singleton()->edit_resource(anim); } } void AnimationPlayerEditor::_animation_edit() { - if (animation->get_item_count()) { - String current = animation->get_item_text(animation->get_selected()); + String current = _get_current(); + if (current != String()) { Ref<Animation> anim = player->get_animation(current); track_editor->set_animation(anim); @@ -745,51 +705,6 @@ void AnimationPlayerEditor::_animation_edit() { } } -void AnimationPlayerEditor::_save_animation(String p_file) { - String current = animation->get_item_text(animation->get_selected()); - if (!current.is_empty()) { - Ref<Animation> anim = player->get_animation(current); - - ERR_FAIL_COND(!Object::cast_to<Resource>(*anim)); - - RES current_res = RES(Object::cast_to<Resource>(*anim)); - - _animation_save_in_path(current_res, p_file); - } -} - -void AnimationPlayerEditor::_load_animations(Vector<String> p_files) { - ERR_FAIL_COND(!player); - - for (int i = 0; i < p_files.size(); i++) { - String file = p_files[i]; - - Ref<Resource> res = ResourceLoader::load(file, "Animation"); - ERR_FAIL_COND_MSG(res.is_null(), "Cannot load Animation from file '" + file + "'."); - ERR_FAIL_COND_MSG(!res->is_class("Animation"), "Loaded resource from file '" + file + "' is not Animation."); - if (file.rfind("/") != -1) { - file = file.substr(file.rfind("/") + 1, file.length()); - } - if (file.rfind("\\") != -1) { - file = file.substr(file.rfind("\\") + 1, file.length()); - } - - if (file.contains(".")) { - file = file.substr(0, file.find(".")); - } - - undo_redo->create_action(TTR("Load Animation")); - undo_redo->add_do_method(player, "add_animation", file, res); - undo_redo->add_undo_method(player, "remove_animation", file); - if (player->has_animation(file)) { - undo_redo->add_undo_method(player, "add_animation", file, player->get_animation(file)); - } - undo_redo->add_do_method(this, "_animation_player_changed", player); - undo_redo->add_undo_method(this, "_animation_player_changed", player); - undo_redo->commit_action(); - } -} - void AnimationPlayerEditor::_scale_changed(const String &p_scale) { player->set_speed_scale(p_scale.to_float()); } @@ -824,49 +739,66 @@ void AnimationPlayerEditor::_update_animation() { void AnimationPlayerEditor::_update_player() { updating = true; - List<StringName> animlist; - if (player) { - player->get_animation_list(&animlist); - } animation->clear(); -#define ITEM_DISABLED(m_item, m_disabled) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), m_disabled) - - ITEM_DISABLED(TOOL_SAVE_ANIM, animlist.size() == 0); - ITEM_DISABLED(TOOL_SAVE_AS_ANIM, animlist.size() == 0); - ITEM_DISABLED(TOOL_DUPLICATE_ANIM, animlist.size() == 0); - ITEM_DISABLED(TOOL_RENAME_ANIM, animlist.size() == 0); - ITEM_DISABLED(TOOL_EDIT_TRANSITIONS, animlist.size() == 0); - ITEM_DISABLED(TOOL_COPY_ANIM, animlist.size() == 0); - ITEM_DISABLED(TOOL_REMOVE_ANIM, animlist.size() == 0); - - stop->set_disabled(animlist.size() == 0); - play->set_disabled(animlist.size() == 0); - play_bw->set_disabled(animlist.size() == 0); - play_bw_from->set_disabled(animlist.size() == 0); - play_from->set_disabled(animlist.size() == 0); - frame->set_editable(animlist.size() != 0); - animation->set_disabled(animlist.size() == 0); - autoplay->set_disabled(animlist.size() == 0); - tool_anim->set_disabled(player == nullptr); - onion_toggle->set_disabled(animlist.size() == 0); - onion_skinning->set_disabled(animlist.size() == 0); - pin->set_disabled(player == nullptr); - if (!player) { AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying(); return; } + List<StringName> libraries; + if (player) { + player->get_animation_library_list(&libraries); + } + int active_idx = -1; - for (const StringName &E : animlist) { - animation->add_item(E); + bool no_anims_found = true; - if (player->get_assigned_animation() == E) { - active_idx = animation->get_item_count() - 1; + for (const StringName &K : libraries) { + if (K != StringName()) { + animation->add_separator(K); + } + + Ref<AnimationLibrary> library = player->get_animation_library(K); + List<StringName> animlist; + library->get_animation_list(&animlist); + + for (const StringName &E : animlist) { + String path = K; + if (path != "") { + path += "/"; + } + path += E; + animation->add_item(path); + if (player->get_assigned_animation() == path) { + active_idx = animation->get_selectable_item(true); + } + no_anims_found = false; } } +#define ITEM_CHECK_DISABLED(m_item) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), no_anims_found) + + ITEM_CHECK_DISABLED(TOOL_DUPLICATE_ANIM); + ITEM_CHECK_DISABLED(TOOL_RENAME_ANIM); + ITEM_CHECK_DISABLED(TOOL_EDIT_TRANSITIONS); + ITEM_CHECK_DISABLED(TOOL_REMOVE_ANIM); + +#undef ITEM_CHECK_DISABLED + + stop->set_disabled(no_anims_found); + play->set_disabled(no_anims_found); + play_bw->set_disabled(no_anims_found); + play_bw_from->set_disabled(no_anims_found); + play_from->set_disabled(no_anims_found); + frame->set_editable(!no_anims_found); + animation->set_disabled(no_anims_found); + autoplay->set_disabled(no_anims_found); + tool_anim->set_disabled(player == nullptr); + onion_toggle->set_disabled(no_anims_found); + onion_skinning->set_disabled(no_anims_found); + pin->set_disabled(player == nullptr); + _update_animation_list_icons(); updating = false; @@ -874,16 +806,16 @@ void AnimationPlayerEditor::_update_player() { animation->select(active_idx); autoplay->set_pressed(animation->get_item_text(active_idx) == player->get_autoplay()); _animation_selected(active_idx); - - } else if (animation->get_item_count() > 0) { - animation->select(0); - autoplay->set_pressed(animation->get_item_text(0) == player->get_autoplay()); - _animation_selected(0); + } else if (animation->has_selectable_items()) { + int item = animation->get_selectable_item(); + animation->select(item); + autoplay->set_pressed(animation->get_item_text(item) == player->get_autoplay()); + _animation_selected(item); } else { _animation_selected(0); } - if (animation->get_item_count()) { + if (!no_anims_found) { String current = animation->get_item_text(animation->get_selected()); Ref<Animation> anim = player->get_animation(current); track_editor->set_animation(anim); @@ -899,6 +831,9 @@ void AnimationPlayerEditor::_update_player() { void AnimationPlayerEditor::_update_animation_list_icons() { for (int i = 0; i < animation->get_item_count(); i++) { String name = animation->get_item_text(i); + if (animation->is_item_disabled(i) || animation->is_item_separator(i)) { + continue; + } Ref<Texture2D> icon; if (name == player->get_autoplay()) { @@ -925,7 +860,7 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { _update_player(); if (onion.enabled) { - if (animation->get_item_count() > 0) { + if (animation->has_selectable_items()) { _start_onion_skinning(); } else { _stop_onion_skinning(); @@ -940,6 +875,8 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) { track_editor->show_select_node_warning(true); } + + library_editor->set_animation_player(player); } void AnimationPlayerEditor::forward_force_draw_over_viewport(Control *p_overlay) { @@ -993,7 +930,7 @@ void AnimationPlayerEditor::forward_force_draw_over_viewport(Control *p_overlay) } void AnimationPlayerEditor::_animation_duplicate() { - if (!animation->get_item_count()) { + if (!animation->has_selectable_items()) { return; } @@ -1031,29 +968,6 @@ Ref<Animation> AnimationPlayerEditor::_animation_clone(Ref<Animation> p_anim) { return new_anim; } -void AnimationPlayerEditor::_animation_paste(Ref<Animation> p_anim) { - String name = p_anim->get_name(); - if (name.is_empty()) { - name = TTR("Pasted Animation"); - } - - int idx = 1; - String base = name; - while (player->has_animation(name)) { - idx++; - name = base + " " + itos(idx); - } - - undo_redo->create_action(TTR("Paste Animation")); - undo_redo->add_do_method(player, "add_animation", name, p_anim); - undo_redo->add_undo_method(player, "remove_animation", name); - undo_redo->add_do_method(this, "_animation_player_changed", player); - undo_redo->add_undo_method(this, "_animation_player_changed", player); - undo_redo->commit_action(); - - _select_anim_by_name(name); -} - void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool p_timeline_only) { if (updating || !player || player->is_playing()) { return; @@ -1095,6 +1009,9 @@ void AnimationPlayerEditor::_animation_player_changed(Object *p_pl) { if (blend_editor.dialog->is_visible()) { _animation_blend(); // Update. } + if (library_editor->is_visible()) { + library_editor->update_tree(); + } } } @@ -1134,10 +1051,7 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos, bool p_drag, } void AnimationPlayerEditor::_animation_tool_menu(int p_option) { - String current; - if (animation->get_selected() >= 0 && animation->get_selected() < animation->get_item_count()) { - current = animation->get_item_text(animation->get_selected()); - } + String current = _get_current(); Ref<Animation> anim; if (!current.is_empty()) { @@ -1148,18 +1062,9 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { case TOOL_NEW_ANIM: { _animation_new(); } break; - case TOOL_LOAD_ANIM: { - _animation_load(); - } break; - case TOOL_SAVE_ANIM: { - if (anim.is_valid()) { - _animation_save(anim); - } - } break; - case TOOL_SAVE_AS_ANIM: { - if (anim.is_valid()) { - _animation_save_as(anim); - } + case TOOL_ANIM_LIBRARY: { + library_editor->set_animation_player(player); + library_editor->show_dialog(); } break; case TOOL_DUPLICATE_ANIM: { _animation_duplicate(); @@ -1173,39 +1078,8 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) { case TOOL_REMOVE_ANIM: { _animation_remove(); } break; - case TOOL_COPY_ANIM: { - if (!animation->get_item_count()) { - error_dialog->set_text(TTR("No animation to copy!")); - error_dialog->popup_centered(); - return; - } - - String current2 = animation->get_item_text(animation->get_selected()); - Ref<Animation> anim2 = player->get_animation(current2); - EditorSettings::get_singleton()->set_resource_clipboard(anim2); - } break; - case TOOL_PASTE_ANIM: { - Ref<Animation> anim2 = EditorSettings::get_singleton()->get_resource_clipboard(); - if (!anim2.is_valid()) { - error_dialog->set_text(TTR("No animation resource in clipboard!")); - error_dialog->popup_centered(); - return; - } - Ref<Animation> new_anim = _animation_clone(anim2); - _animation_paste(new_anim); - } break; - case TOOL_PASTE_ANIM_REF: { - Ref<Animation> anim2 = EditorSettings::get_singleton()->get_resource_clipboard(); - if (!anim2.is_valid()) { - error_dialog->set_text(TTR("No animation resource in clipboard!")); - error_dialog->popup_centered(); - return; - } - - _animation_paste(anim2); - } break; case TOOL_EDIT_RESOURCE: { - if (!animation->get_item_count()) { + if (!animation->has_selectable_items()) { error_dialog->set_text(TTR("No animation to edit!")); error_dialog->popup_centered(); return; @@ -1300,7 +1174,7 @@ void AnimationPlayerEditor::shortcut_input(const Ref<InputEvent> &p_ev) { } void AnimationPlayerEditor::_editor_visibility_changed() { - if (is_visible() && animation->get_item_count() > 0) { + if (is_visible() && animation->has_selectable_items()) { _start_onion_skinning(); } } @@ -1536,7 +1410,6 @@ void AnimationPlayerEditor::_pin_pressed() { void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_animation_new"), &AnimationPlayerEditor::_animation_new); ClassDB::bind_method(D_METHOD("_animation_rename"), &AnimationPlayerEditor::_animation_rename); - ClassDB::bind_method(D_METHOD("_animation_load"), &AnimationPlayerEditor::_animation_load); ClassDB::bind_method(D_METHOD("_animation_remove"), &AnimationPlayerEditor::_animation_remove); ClassDB::bind_method(D_METHOD("_animation_blend"), &AnimationPlayerEditor::_animation_blend); ClassDB::bind_method(D_METHOD("_animation_edit"), &AnimationPlayerEditor::_animation_edit); @@ -1623,13 +1496,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug tool_anim->set_text(TTR("Animation")); tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/new_animation", TTR("New")), TOOL_NEW_ANIM); tool_anim->get_popup()->add_separator(); - tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/open_animation", TTR("Load")), TOOL_LOAD_ANIM); - tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/save_animation", TTR("Save")), TOOL_SAVE_ANIM); - tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/save_as_animation", TTR("Save As...")), TOOL_SAVE_AS_ANIM); - tool_anim->get_popup()->add_separator(); - tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/copy_animation", TTR("Copy")), TOOL_COPY_ANIM); - tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/paste_animation", TTR("Paste")), TOOL_PASTE_ANIM); - tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/paste_animation_as_reference", TTR("Paste As Reference")), TOOL_PASTE_ANIM_REF); + tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/animation_libraries", TTR("Manage Animations...")), TOOL_ANIM_LIBRARY); tool_anim->get_popup()->add_separator(); tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/duplicate_animation", TTR("Duplicate...")), TOOL_DUPLICATE_ANIM); tool_anim->get_popup()->add_separator(); @@ -1638,6 +1505,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/open_animation_in_inspector", TTR("Open in Inspector")), TOOL_EDIT_RESOURCE); tool_anim->get_popup()->add_separator(); tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/remove_animation", TTR("Remove")), TOOL_REMOVE_ANIM); + tool_anim->set_disabled(true); hb->add_child(tool_anim); animation = memnew(OptionButton); @@ -1705,8 +1573,14 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug name_title = memnew(Label(TTR("Animation Name:"))); vb->add_child(name_title); + HBoxContainer *name_hb = memnew(HBoxContainer); name = memnew(LineEdit); - vb->add_child(name); + name_hb->add_child(name); + name->set_h_size_flags(SIZE_EXPAND_FILL); + library = memnew(OptionButton); + name_hb->add_child(library); + library->hide(); + vb->add_child(name_hb); name_dialog->register_text_enter(name); error_dialog = memnew(ConfirmationDialog); @@ -1742,8 +1616,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug animation->connect("item_selected", callable_mp(this, &AnimationPlayerEditor::_animation_selected)); - file->connect("file_selected", callable_mp(this, &AnimationPlayerEditor::_save_animation)); - file->connect("files_selected", callable_mp(this, &AnimationPlayerEditor::_load_animations)); frame->connect("value_changed", callable_mp(this, &AnimationPlayerEditor::_seek_value_changed), make_binds(true, false)); scale->connect("text_submitted", callable_mp(this, &AnimationPlayerEditor::_scale_changed)); @@ -1759,6 +1631,10 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug _update_player(); + library_editor = memnew(AnimationLibraryEditor); + add_child(library_editor); + library_editor->connect("update_editor", callable_mp(this, &AnimationPlayerEditor::_animation_player_changed)); + // Onion skinning. track_editor->connect("visibility_changed", callable_mp(this, &AnimationPlayerEditor::_editor_visibility_changed)); diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 4f6a9c534f..0cc04460ca 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -33,6 +33,7 @@ #include "editor/animation_track_editor.h" #include "editor/editor_plugin.h" +#include "editor/plugins/animation_library_editor.h" #include "scene/animation/animation_player.h" #include "scene/gui/dialogs.h" #include "scene/gui/slider.h" @@ -40,7 +41,6 @@ #include "scene/gui/texture_button.h" #include "scene/gui/tree.h" -class EditorFileDialog; class AnimationPlayerEditorPlugin; class AnimationPlayerEditor : public VBoxContainer { @@ -51,16 +51,11 @@ class AnimationPlayerEditor : public VBoxContainer { enum { TOOL_NEW_ANIM, - TOOL_LOAD_ANIM, - TOOL_SAVE_ANIM, - TOOL_SAVE_AS_ANIM, + TOOL_ANIM_LIBRARY, TOOL_DUPLICATE_ANIM, TOOL_RENAME_ANIM, TOOL_EDIT_TRANSITIONS, TOOL_REMOVE_ANIM, - TOOL_COPY_ANIM, - TOOL_PASTE_ANIM, - TOOL_PASTE_ANIM_REF, TOOL_EDIT_RESOURCE }; @@ -103,8 +98,10 @@ class AnimationPlayerEditor : public VBoxContainer { SpinBox *frame = nullptr; LineEdit *scale = nullptr; LineEdit *name = nullptr; + OptionButton *library = nullptr; Label *name_title = nullptr; UndoRedo *undo_redo = nullptr; + Ref<Texture2D> autoplay_icon; Ref<Texture2D> reset_icon; Ref<ImageTexture> autoplay_reset_icon; @@ -114,6 +111,8 @@ class AnimationPlayerEditor : public VBoxContainer { EditorFileDialog *file = nullptr; ConfirmationDialog *delete_dialog = nullptr; + AnimationLibraryEditor *library_editor = nullptr; + struct BlendEditor { AcceptDialog *dialog = nullptr; Tree *tree = nullptr; @@ -173,11 +172,6 @@ class AnimationPlayerEditor : public VBoxContainer { void _animation_new(); void _animation_rename(); void _animation_name_edited(); - void _animation_load(); - - void _animation_save_in_path(const Ref<Resource> &p_resource, const String &p_path); - void _animation_save(const Ref<Resource> &p_resource); - void _animation_save_as(const Ref<Resource> &p_resource); void _animation_remove(); void _animation_remove_confirmed(); @@ -185,11 +179,8 @@ class AnimationPlayerEditor : public VBoxContainer { void _animation_edit(); void _animation_duplicate(); Ref<Animation> _animation_clone(const Ref<Animation> p_anim); - void _animation_paste(const Ref<Animation> p_anim); void _animation_resource_edit(); void _scale_changed(const String &p_scale); - void _save_animation(String p_file); - void _load_animations(Vector<String> p_files); void _seek_value_changed(float p_value, bool p_set = false, bool p_timeline_only = false); void _blend_editor_next_changed(const int p_idx); @@ -219,6 +210,7 @@ class AnimationPlayerEditor : public VBoxContainer { void _stop_onion_skinning(); void _pin_pressed(); + String _get_current() const; ~AnimationPlayerEditor(); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 405ece1471..157eed02f4 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -729,9 +729,8 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB 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()); - FileAccess *file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ); - - if (file) { + Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ); + if (file.is_valid()) { PackedByteArray cached_data; int len = file->get_32(); cached_data.resize(len); @@ -740,8 +739,6 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB file->get_buffer(w, len); image_data = cached_data; - file->close(); - memdelete(file); } } @@ -808,23 +805,17 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons 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 new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges(); - FileAccess *file; - - file = FileAccess::open(cache_filename_base + ".etag", FileAccess::WRITE); - if (file) { + Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".etag", FileAccess::WRITE); + if (file.is_valid()) { file->store_line(new_etag); - file->close(); - memdelete(file); } int len = p_data.size(); const uint8_t *r = p_data.ptr(); file = FileAccess::open(cache_filename_base + ".data", FileAccess::WRITE); - if (file) { + if (file.is_valid()) { file->store_32(len); file->store_buffer(r, len); - file->close(); - memdelete(file); } break; @@ -858,11 +849,9 @@ void EditorAssetLibrary::_update_image_queue() { Vector<String> headers; if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) { - FileAccess *file = FileAccess::open(cache_filename_base + ".etag", FileAccess::READ); - if (file) { + Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".etag", FileAccess::READ); + if (file.is_valid()) { headers.push_back("If-None-Match: " + file->get_line()); - file->close(); - memdelete(file); } } diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 0f45415c4d..09bff7c00b 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1091,13 +1091,11 @@ void ScriptEditor::_file_dialog_action(String p_file) { switch (file_dialog_option) { case FILE_NEW_TEXTFILE: { Error err; - FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err); if (err) { EditorNode::get_singleton()->show_warning(TTR("Error writing TextFile:") + "\n" + p_file, TTR("Error!")); break; } - file->close(); - memdelete(file); if (EditorFileSystem::get_singleton()) { if (textfile_extensions.has(p_file.get_extension())) { @@ -2211,17 +2209,14 @@ Error ScriptEditor::_save_text_file(Ref<TextFile> p_text_file, const String &p_p String source = sqscr->get_text(); Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err, err, "Cannot save text file '" + p_path + "'."); file->store_string(source); if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); return ERR_CANT_CREATE; } - file->close(); - memdelete(file); if (ResourceSaver::get_timestamp_on_save()) { p_text_file->set_last_modified_time(FileAccess::get_modified_time(p_path)); diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp index 5afd460831..0835d0212f 100644 --- a/editor/pot_generator.cpp +++ b/editor/pot_generator.cpp @@ -93,7 +93,7 @@ void POTGenerator::generate_pot(const String &p_file) { void POTGenerator::_write_to_pot(const String &p_file) { Error err; - FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err); if (err != OK) { ERR_PRINT("Failed to open " + p_file); return; @@ -155,11 +155,9 @@ void POTGenerator::_write_to_pot(const String &p_file) { } } } - - file->close(); } -void POTGenerator::_write_msgid(FileAccess *r_file, const String &p_id, bool p_plural) { +void POTGenerator::_write_msgid(Ref<FileAccess> r_file, const String &p_id, bool p_plural) { // Split \\n and \n. Vector<String> temp = p_id.split("\\n"); Vector<String> msg_lines; diff --git a/editor/pot_generator.h b/editor/pot_generator.h index 2b42c681e5..e7a5f90cee 100644 --- a/editor/pot_generator.h +++ b/editor/pot_generator.h @@ -49,7 +49,7 @@ class POTGenerator { OrderedHashMap<String, Vector<MsgidData>> all_translation_strings; void _write_to_pot(const String &p_file); - void _write_msgid(FileAccess *r_file, const String &p_id, bool p_plural); + void _write_msgid(Ref<FileAccess> r_file, const String &p_id, bool p_plural); void _add_new_msgid(const String &p_msgid, const String &p_context, const String &p_plural, const String &p_location); #ifdef DEBUG_POT diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 501cb88547..2b24c231ea 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -147,7 +147,7 @@ private: } String _test_path() { - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); String valid_path, valid_install_path; if (d->change_dir(project_path->get_text()) == OK) { valid_path = project_path->get_text(); @@ -186,8 +186,7 @@ private: if (mode == MODE_IMPORT || mode == MODE_RENAME) { if (!valid_path.is_empty() && !d->file_exists("project.godot")) { if (valid_path.ends_with(".zip")) { - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); unzFile pkg = unzOpen2(valid_path.utf8().get_data(), &io); if (!pkg) { @@ -383,7 +382,7 @@ private: return; } - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (d->change_dir(project_path->get_text()) == OK) { if (!d->dir_exists(project_name_no_edges)) { if (d->make_dir(project_name_no_edges) == OK) { @@ -500,8 +499,7 @@ private: zip_path = project_path->get_text(); } - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); unzFile pkg = unzOpen2(zip_path.utf8().get_data(), &io); if (!pkg) { @@ -549,7 +547,7 @@ private: path = path.substr(0, path.length() - 1); String rel_path = path.substr(zip_root.length()); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); da->make_dir(dir.plus_file(rel_path)); } else { Vector<uint8_t> data; @@ -564,11 +562,9 @@ private: } unzCloseCurrentFile(pkg); - FileAccess *f = FileAccess::open(dir.plus_file(rel_path), FileAccess::WRITE); - - if (f) { + Ref<FileAccess> f = FileAccess::open(dir.plus_file(rel_path), FileAccess::WRITE); + if (f.is_valid()) { f->store_buffer(data.ptr(), data.size()); - memdelete(f); } else { failed_files.push_back(rel_path); } @@ -615,7 +611,7 @@ private: void _remove_created_folder() { if (!created_folder_path.is_empty()) { - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); d->remove(created_folder_path); create_dir->set_disabled(false); @@ -719,7 +715,7 @@ public: project_path->set_text(fav_dir); fdialog->set_current_dir(fav_dir); } else { - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); project_path->set_text(d->get_current_dir()); fdialog->set_current_dir(d->get_current_dir()); } @@ -2280,7 +2276,7 @@ void ProjectManager::_run_project() { } void ProjectManager::_scan_dir(const String &path, List<String> *r_projects) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Error error = da->change_dir(path); ERR_FAIL_COND_MSG(error != OK, "Could not scan directory at: " + path); da->list_dir_begin(); @@ -2402,14 +2398,14 @@ void ProjectManager::_install_project(const String &p_zip_path, const String &p_ npdialog->show_dialog(); } -void ProjectManager::_files_dropped(PackedStringArray p_files, int p_screen) { +void ProjectManager::_files_dropped(PackedStringArray p_files) { if (p_files.size() == 1 && p_files[0].ends_with(".zip")) { const String file = p_files[0].get_file(); _install_project(p_files[0], file.substr(0, file.length() - 4).capitalize()); return; } Set<String> folders_set; - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < p_files.size(); i++) { String file = p_files[i]; folders_set.insert(da->dir_exists(file) ? file : file.get_base_dir()); @@ -2422,7 +2418,7 @@ void ProjectManager::_files_dropped(PackedStringArray p_files, int p_screen) { bool confirm = true; if (folders.size() == 1) { - DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (dir->change_dir(folders[0]) == OK) { dir->list_dir_begin(); String file = dir->get_next(); @@ -2849,7 +2845,7 @@ ProjectManager::ProjectManager() { _load_recent_projects(); - DirAccessRef dir_access = DirAccess::create(DirAccess::AccessType::ACCESS_FILESYSTEM); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::AccessType::ACCESS_FILESYSTEM); String default_project_path = EditorSettings::get_singleton()->get("filesystem/directories/default_project_path"); if (!dir_access->dir_exists(default_project_path)) { diff --git a/editor/project_manager.h b/editor/project_manager.h index 9cea6e163f..00f8cfc721 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -127,7 +127,7 @@ class ProjectManager : public Control { void _dim_window(); virtual void shortcut_input(const Ref<InputEvent> &p_ev) override; - void _files_dropped(PackedStringArray p_files, int p_screen); + void _files_dropped(PackedStringArray p_files); void _version_button_pressed(); void _on_order_option_changed(int p_idx); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 71ea625013..03f65cdf52 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -3149,9 +3149,8 @@ void SceneTreeDock::_update_create_root_dialog() { favorite_nodes->get_child(i)->queue_delete(); } - FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites.Node"), FileAccess::READ); - - if (f) { + Ref<FileAccess> f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites.Node"), FileAccess::READ); + if (f.is_valid()) { while (!f->eof_reached()) { String l = f->get_line().strip_edges(); @@ -3168,8 +3167,6 @@ void SceneTreeDock::_update_create_root_dialog() { button->connect("pressed", callable_mp(this, &SceneTreeDock::_favorite_root_selected), make_binds(l)); } } - - memdelete(f); } if (!favorite_nodes->is_visible_in_tree()) { diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 72f77c859b..7d063e13f9 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -246,7 +246,7 @@ String ScriptCreateDialog::_validate_path(const String &p_path, bool p_file_must } { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (da->change_dir(p.get_base_dir()) != OK) { return TTR("Base path is invalid."); } @@ -254,7 +254,7 @@ String ScriptCreateDialog::_validate_path(const String &p_path, bool p_file_must { // Check if file exists. - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (da->dir_exists(p)) { return TTR("A directory with the same name exists."); } else if (p_file_must_exist && !da->file_exists(p)) { @@ -547,7 +547,7 @@ void ScriptCreateDialog::_path_changed(const String &p_path) { } // Check if file exists. - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); String p = ProjectSettings::get_singleton()->localize_path(p_path.strip_edges()); if (da->file_exists(p)) { is_new_script_created = false; @@ -824,8 +824,8 @@ Vector<ScriptLanguage::ScriptTemplate> ScriptCreateDialog::_get_user_templates(c String dir_path = p_dir.plus_file(p_object); - DirAccessRef d = DirAccess::open(dir_path); - if (d) { + Ref<DirAccess> d = DirAccess::open(dir_path); + if (d.is_valid()) { d->list_dir_begin(); String file = d->get_next(); while (file != String()) { @@ -858,7 +858,7 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL // Parse file for meta-information and script content Error err; - FileAccess *file = FileAccess::open(p_path.plus_file(p_filename), FileAccess::READ, &err); + Ref<FileAccess> file = FileAccess::open(p_path.plus_file(p_filename), FileAccess::READ, &err); if (!err) { while (!file->eof_reached()) { String line = file->get_line(); @@ -890,8 +890,6 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL script_template.content += line.replace("\t", "_TS_") + "\n"; } } - file->close(); - memdelete(file); } script_template.content = script_template.content.lstrip("\n"); diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp index dbc78e846c..f07ec161c2 100644 --- a/editor/shader_create_dialog.cpp +++ b/editor/shader_create_dialog.cpp @@ -313,7 +313,7 @@ void ShaderCreateDialog::_path_changed(const String &p_path) { return; } - DirAccessRef f = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> f = DirAccess::create(DirAccess::ACCESS_RESOURCES); String p = ProjectSettings::get_singleton()->localize_path(p_path.strip_edges()); if (f->file_exists(p)) { is_new_shader_created = false; @@ -371,12 +371,12 @@ String ShaderCreateDialog::_validate_path(const String &p_path) { return TTR("Path is not local."); } - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (d->change_dir(p.get_base_dir()) != OK) { return TTR("Invalid base path."); } - DirAccessRef f = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> f = DirAccess::create(DirAccess::ACCESS_RESOURCES); if (f->dir_exists(p)) { return TTR("A directory with the same name exists."); } diff --git a/main/main.cpp b/main/main.cpp index a99654542a..f20ec94fa5 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2112,8 +2112,8 @@ bool Main::start() { } { - DirAccessRef da = DirAccess::open(doc_tool_path); - ERR_FAIL_COND_V_MSG(!da, false, "Argument supplied to --doctool must be a valid directory path."); + Ref<DirAccess> da = DirAccess::open(doc_tool_path); + ERR_FAIL_COND_V_MSG(da.is_null(), false, "Argument supplied to --doctool must be a valid directory path."); } #ifndef MODULE_MONO_ENABLED @@ -2149,7 +2149,7 @@ bool Main::start() { checked_paths.insert(path); // Create the module documentation directory if it doesn't exist - DirAccessRef da = DirAccess::create_for_path(path); + Ref<DirAccess> da = DirAccess::create_for_path(path); err = da->make_dir_recursive(path); ERR_FAIL_COND_V_MSG(err != OK, false, "Error: Can't create directory: " + path + ": " + itos(err)); @@ -2161,7 +2161,7 @@ bool Main::start() { String index_path = doc_tool_path.plus_file("doc/classes"); // Create the main documentation directory if it doesn't exist - DirAccessRef da = DirAccess::create_for_path(index_path); + Ref<DirAccess> da = DirAccess::create_for_path(index_path); err = da->make_dir_recursive(index_path); ERR_FAIL_COND_V_MSG(err != OK, false, "Error: Can't create index directory: " + index_path + ": " + itos(err)); @@ -2501,11 +2501,11 @@ bool Main::start() { int sep = local_game_path.rfind("/"); if (sep == -1) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); local_game_path = da->get_current_dir().plus_file(local_game_path); } else { - DirAccessRef da = DirAccess::open(local_game_path.substr(0, sep)); - if (da) { + 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.substr(sep + 1, local_game_path.length())); } diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index ad2c7d6a3e..8813c3827a 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -200,8 +200,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image, return err; } -Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, - bool p_force_linear, float p_scale) { +Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { bmp_header_s bmp_header; Error err = ERR_INVALID_DATA; @@ -241,7 +240,6 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, case BI_CMYKRLE8: case BI_CMYKRLE4: { // Stop parsing. - f->close(); ERR_FAIL_V_MSG(ERR_UNAVAILABLE, vformat("Compressed BMP files are not supported: %s", f->get_path())); } break; @@ -283,7 +281,6 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f, err = convert_to_image(p_image, bmp_buffer_r, bmp_color_table_r, color_table_size, bmp_header); } - f->close(); } } return err; @@ -294,12 +291,14 @@ void ImageLoaderBMP::get_recognized_extensions(List<String> *p_extensions) const } static Ref<Image> _bmp_mem_loader_func(const uint8_t *p_bmp, int p_size) { - FileAccessMemory memfile; - Error open_memfile_error = memfile.open_custom(p_bmp, p_size); + Ref<FileAccessMemory> memfile; + memfile.instantiate(); + Error open_memfile_error = memfile->open_custom(p_bmp, p_size); ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for BMP image buffer."); + Ref<Image> img; img.instantiate(); - Error load_error = ImageLoaderBMP().load_image(img, &memfile, false, 1.0f); + Error load_error = ImageLoaderBMP().load_image(img, memfile, false, 1.0f); ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load BMP image."); return img; } diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h index 9c9a16a9f5..63dee0a969 100644 --- a/modules/bmp/image_loader_bmp.h +++ b/modules/bmp/image_loader_bmp.h @@ -83,8 +83,7 @@ protected: const bmp_header_s &p_header); public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, - bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderBMP(); }; diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index 7bfe849106..58e5e31f46 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -100,12 +100,12 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, } Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); + if (f.is_null()) { return RES(); } - FileAccessRef fref(f); + Ref<FileAccess> fref(f); if (r_error) { *r_error = ERR_FILE_CORRUPT; } diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 3a0e320e9b..269e6f0580 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -92,6 +92,21 @@ Object *GDScriptNativeClass::instantiate() { return ClassDB::instantiate(name); } +Variant GDScriptNativeClass::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { + if (p_method == SNAME("new")) { + // Constructor. + return Object::callp(p_method, p_args, p_argcount, r_error); + } + MethodBind *method = ClassDB::get_method(name, p_method); + if (method) { + // Native static method. + return method->call(nullptr, p_args, p_argcount, r_error); + } + + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; + return Variant(); +} + GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) { if (p_script->initializer) { return p_script->initializer; @@ -1015,7 +1030,7 @@ Error GDScript::load_byte_code(const String &p_path) { Error GDScript::load_source_code(const String &p_path) { Vector<uint8_t> sourcef; Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { ERR_FAIL_COND_V(err, err); } @@ -1024,8 +1039,6 @@ Error GDScript::load_source_code(const String &p_path) { sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); uint64_t r = f->get_buffer(w, len); - f->close(); - memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); w[len] = 0; @@ -2084,7 +2097,7 @@ bool GDScriptLanguage::handles_global_class_type(const String &p_type) const { String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const { Vector<uint8_t> sourcef; Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { return String(); } @@ -2118,8 +2131,8 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b } else { Vector<StringName> extend_classes = subclass->extends; - FileAccessRef subfile = FileAccess::open(subclass->extends_path, FileAccess::READ); - if (!subfile) { + Ref<FileAccess> subfile = FileAccess::open(subclass->extends_path, FileAccess::READ); + if (subfile.is_null()) { break; } String subsource = subfile->get_as_utf8_string(); @@ -2316,8 +2329,8 @@ String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) con } void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - FileAccessRef file = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_path + "'."); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_path + "'."); String source = file->get_as_utf8_string(); if (source.is_empty()) { @@ -2341,17 +2354,14 @@ Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resou String source = sqscr->get_source_code(); Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'."); file->store_string(source); if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); return ERR_CANT_CREATE; } - file->close(); - memdelete(file); if (ScriptServer::is_reload_scripts_on_save_enabled()) { GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, false); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 82125610c2..79171cac73 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -52,6 +52,7 @@ public: _FORCE_INLINE_ const StringName &get_name() const { return name; } Variant _new(); Object *instantiate(); + virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override; GDScriptNativeClass(const StringName &p_name); }; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 00931961b7..01118a6b4f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2508,8 +2508,9 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a call_type = return_type; } else { - // Check if the name exists as something else. bool found = false; + + // Check if the name exists as something else. if (!p_call->is_super && callee_type != GDScriptParser::Node::NONE) { GDScriptParser::IdentifierNode *callee_id; if (callee_type == GDScriptParser::Node::IDENTIFIER) { @@ -2539,6 +2540,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a if (!found && (is_self || (base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::BUILTIN))) { String base_name = is_self && !p_call->is_super ? "self" : base_type.to_string(); push_error(vformat(R"*(Function "%s()" not found in base %s.)*", p_call->function_name, base_name), p_call->is_super ? p_call : p_call->callee); + } else if (!found && (!p_call->is_super && base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::NATIVE && base_type.is_meta_type)) { + push_error(vformat(R"*(Static function "%s()" not found in base "%s".)*", p_call->function_name, base_type.native_type.operator String()), p_call); } } @@ -3773,6 +3776,7 @@ bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GD r_return_type = type_from_property(p_info.return_val); r_default_arg_count = p_info.default_arguments.size(); r_vararg = (p_info.flags & METHOD_FLAG_VARARG) != 0; + r_static = (p_info.flags & METHOD_FLAG_STATIC) != 0; for (const PropertyInfo &E : p_info.arguments) { r_par_types.push_back(type_from_property(E)); diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 82aa14795e..000d36d2e6 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -1080,6 +1080,24 @@ void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_ append(Variant::get_validated_builtin_method(p_type, p_method)); } +void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) { + bool is_validated = false; + + MethodBind *method = ClassDB::get_method(p_class, p_method); + + if (!is_validated) { + // Perform regular call. + append(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1); + for (int i = 0; i < p_arguments.size(); i++) { + append(p_arguments[i]); + } + append(p_target); + append(method); + append(p_arguments.size()); + return; + } +} + void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) { append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size()); for (int i = 0; i < p_arguments.size(); i++) { diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index db15dc55ef..222ae13390 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -464,6 +464,7 @@ public: virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) override; virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override; virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override; + virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) override; virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override; diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 6ada7d36f5..8c198345c2 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -145,7 +145,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP String GDScriptCache::get_source_code(const String &p_path) { Vector<uint8_t> source_file; Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); if (err) { ERR_FAIL_COND_V(err, ""); } @@ -153,7 +153,6 @@ String GDScriptCache::get_source_code(const String &p_path) { uint64_t len = f->get_length(); source_file.resize(len + 1); uint64_t r = f->get_buffer(source_file.ptrw(), len); - f->close(); ERR_FAIL_COND_V(r != len, ""); source_file.write[len] = 0; diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h index 4542dd94ae..3d42ce06c0 100644 --- a/modules/gdscript/gdscript_codegen.h +++ b/modules/gdscript/gdscript_codegen.h @@ -125,6 +125,7 @@ public: virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) = 0; virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0; + virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0; virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 8190eecbc7..0138147fcc 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -35,6 +35,7 @@ #include "gdscript_cache.h" #include "gdscript_utility_functions.h" +#include "core/config/engine.h" #include "core/config/project_settings.h" bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) { @@ -575,6 +576,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code // May be static built-in method call. if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) { gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments); + } else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") && + ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) { + // It's a static native method call. + gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments); } else { GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base); if (r_error) { diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index cc0be94a9e..e5fbbfa0c1 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -564,6 +564,28 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 5 + argc; } break; + case OPCODE_CALL_NATIVE_STATIC: { + MethodBind *method = _methods_ptr[_code_ptr[ip + 1 + instr_var_args]]; + int argc = _code_ptr[ip + 2 + instr_var_args]; + + text += "call native method static "; + text += DADDR(1 + argc); + text += " = "; + text += method->get_instance_class(); + text += "."; + text += method->get_name(); + text += "("; + + for (int i = 0; i < argc; i++) { + if (i > 0) { + text += ", "; + } + text += DADDR(1 + i); + } + text += ")"; + + incr += 4 + argc; + } break; case OPCODE_CALL_PTRCALL_NO_RETURN: { text += "call-ptrcall (no return) "; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 7f0ffb4586..718df7a0a6 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -777,7 +777,22 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a } } +static void _find_built_in_variants(Map<String, ScriptLanguage::CodeCompletionOption> &r_result, bool exclude_nil = false) { + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (!exclude_nil && Variant::Type(i) == Variant::Type::NIL) { + ScriptLanguage::CodeCompletionOption option("null", ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + r_result.insert(option.display, option); + } else { + ScriptLanguage::CodeCompletionOption option(Variant::get_type_name(Variant::Type(i)), ScriptLanguage::CODE_COMPLETION_KIND_CLASS); + r_result.insert(option.display, option); + } + } +} + static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) { + // Built-in Variant Types + _find_built_in_variants(r_result, true); + List<StringName> native_types; ClassDB::get_class_list(&native_types); for (const StringName &E : native_types) { @@ -957,7 +972,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base bool _static = base_type.is_meta_type; if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) { - ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); + ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, ScriptLanguage::LOCATION_LOCAL); option.insert_text += "("; r_result.insert(option.display, option); } @@ -1058,22 +1073,25 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base } } - if (!_static || Engine::get_singleton()->has_singleton(type)) { - List<MethodInfo> methods; - ClassDB::get_method_list(type, &methods, false, true); - for (const MethodInfo &E : methods) { - if (E.name.begins_with("_")) { - continue; - } - int location = p_recursion_depth + _get_method_location(type, E.name); - ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location); - if (E.arguments.size()) { - option.insert_text += "("; - } else { - option.insert_text += "()"; - } - r_result.insert(option.display, option); + bool only_static = _static && !Engine::get_singleton()->has_singleton(type); + + List<MethodInfo> methods; + ClassDB::get_method_list(type, &methods, false, true); + for (const MethodInfo &E : methods) { + if (only_static && (E.flags & METHOD_FLAG_STATIC) == 0) { + continue; + } + if (E.name.begins_with("_")) { + continue; + } + int location = p_recursion_depth + _get_method_location(type, E.name); + ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location); + if (E.arguments.size()) { + option.insert_text += "("; + } else { + option.insert_text += "()"; } + r_result.insert(option.display, option); } return; } break; @@ -1150,17 +1168,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool return; } - static const char *_type_names[Variant::VARIANT_MAX] = { - "null", "bool", "int", "float", "String", "StringName", "Vector2", "Vector2i", "Rect2", "Rect2i", "Vector3", "Vector3i", "Transform2D", "Plane", "Quaternion", "AABB", "Basis", "Transform3D", - "Color", "NodePath", "RID", "Signal", "Callable", "Object", "Dictionary", "Array", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "PackedFloat32Array", "PackedFloat64Array", "PackedStringArray", - "PackedVector2Array", "PackedVector3Array", "PackedColorArray" - }; - static_assert((sizeof(_type_names) / sizeof(*_type_names)) == Variant::VARIANT_MAX, "Completion for builtin types is incomplete"); - - for (int i = 0; i < Variant::VARIANT_MAX; i++) { - ScriptLanguage::CodeCompletionOption option(_type_names[i], ScriptLanguage::CODE_COMPLETION_KIND_CLASS); - r_result.insert(option.display, option); - } + _find_built_in_variants(r_result); static const char *_keywords[] = { "false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super", diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 3ee664c76d..a7ad2b65fd 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -259,6 +259,7 @@ public: OPCODE_CALL_METHOD_BIND, OPCODE_CALL_METHOD_BIND_RET, OPCODE_CALL_BUILTIN_STATIC, + OPCODE_CALL_NATIVE_STATIC, // ptrcall have one instruction per return type. OPCODE_CALL_PTRCALL_NO_RETURN, OPCODE_CALL_PTRCALL_BOOL, diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 41c59c7703..152f548f4e 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -93,9 +93,13 @@ static String _get_var_type(const Variant *p_var) { basestr = "null instance"; } } else { - basestr = bobj->get_class(); - if (bobj->get_script_instance()) { - basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")"; + if (bobj->is_class_ptr(GDScriptNativeClass::get_class_ptr_static())) { + basestr = Object::cast_to<GDScriptNativeClass>(bobj)->get_name(); + } else { + basestr = bobj->get_class(); + if (bobj->get_script_instance()) { + basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")"; + } } } @@ -263,6 +267,7 @@ void (*type_init_function_table[])(Variant *) = { &&OPCODE_CALL_METHOD_BIND, \ &&OPCODE_CALL_METHOD_BIND_RET, \ &&OPCODE_CALL_BUILTIN_STATIC, \ + &&OPCODE_CALL_NATIVE_STATIC, \ &&OPCODE_CALL_PTRCALL_NO_RETURN, \ &&OPCODE_CALL_PTRCALL_BOOL, \ &&OPCODE_CALL_PTRCALL_INT, \ @@ -1710,6 +1715,47 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_CALL_NATIVE_STATIC) { + CHECK_SPACE(3 + instr_arg_count); + + ip += instr_arg_count; + + GD_ERR_BREAK(_code_ptr[ip + 1] < 0 || _code_ptr[ip + 1] >= _methods_count); + MethodBind *method = _methods_ptr[_code_ptr[ip + 1]]; + + int argc = _code_ptr[ip + 2]; + GD_ERR_BREAK(argc < 0); + + GET_INSTRUCTION_ARG(ret, argc); + + const Variant **argptrs = const_cast<const Variant **>(instruction_args); + +#ifdef DEBUG_ENABLED + uint64_t call_time = 0; + + if (GDScriptLanguage::get_singleton()->profiling) { + call_time = OS::get_singleton()->get_ticks_usec(); + } +#endif + + Callable::CallError err; + *ret = method->call(nullptr, argptrs, argc, err); + +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->profiling) { + function_call_time += OS::get_singleton()->get_ticks_usec() - call_time; + } + + if (err.error != Callable::CallError::CALL_OK) { + err_text = _get_call_error(err, "static function '" + method->get_name().operator String() + "' in type '" + method->get_instance_class().operator String() + "'", argptrs); + OPCODE_BREAK; + } +#endif + + ip += 3; + } + DISPATCH_OPCODE; + #ifdef DEBUG_ENABLED #define OPCODE_CALL_PTR(m_type) \ OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \ diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 17886181d5..4c4e810370 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -108,7 +108,7 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) { document_links.clear(); GDScriptTokenizer tokenizer; - FileAccessRef fs = FileAccess::create(FileAccess::ACCESS_RESOURCES); + Ref<FileAccess> fs = FileAccess::create(FileAccess::ACCESS_RESOURCES); tokenizer.set_source_code(p_code); while (true) { GDScriptTokenizer::Token token = tokenizer.scan(); diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index d5ef8fed74..c42bd58aeb 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -424,10 +424,6 @@ GDScriptTextDocument::GDScriptTextDocument() { file_checker = FileAccess::create(FileAccess::ACCESS_RESOURCES); } -GDScriptTextDocument::~GDScriptTextDocument() { - memdelete(file_checker); -} - void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) { String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path); GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content); diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h index a0e584e525..9732765f34 100644 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ b/modules/gdscript/language_server/gdscript_text_document.h @@ -40,7 +40,7 @@ class GDScriptTextDocument : public RefCounted { protected: static void _bind_methods(); - FileAccess *file_checker = nullptr; + Ref<FileAccess> file_checker; void didOpen(const Variant &p_param); void didClose(const Variant &p_param); @@ -75,7 +75,6 @@ public: void initialize(); GDScriptTextDocument(); - virtual ~GDScriptTextDocument(); }; #endif diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 1bf0b40842..229c322f26 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -221,7 +221,7 @@ void GDScriptWorkspace::reload_all_workspace_scripts() { void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String> &r_files) { Error err; - DirAccessRef dir = DirAccess::open(p_root_dir, &err); + Ref<DirAccess> dir = DirAccess::open(p_root_dir, &err); if (OK == err) { dir->list_dir_begin(); String file_name = dir->get_next(); diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index 16c143f7d9..e78517a708 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -229,7 +229,7 @@ bool GDScriptTestRunner::generate_outputs() { bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { Error err = OK; - DirAccessRef dir(DirAccess::open(p_dir, &err)); + Ref<DirAccess> dir(DirAccess::open(p_dir, &err)); if (err != OK) { return false; @@ -254,7 +254,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; - FileAccessRef script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err)); + Ref<FileAccess> script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err)); if (open_err != OK) { ERR_PRINT(vformat(R"(Couldn't open test file "%s".)", next)); next = dir->get_next(); @@ -286,7 +286,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { bool GDScriptTestRunner::make_tests() { Error err = OK; - DirAccessRef dir(DirAccess::open(source_dir, &err)); + Ref<DirAccess> dir(DirAccess::open(source_dir, &err)); ERR_FAIL_COND_V_MSG(err != OK, false, "Could not open specified test directory."); @@ -611,7 +611,7 @@ bool GDScriptTest::generate_output() { } Error err = OK; - FileAccessRef out_file = FileAccess::open(output_file, FileAccess::WRITE, &err); + Ref<FileAccess> out_file = FileAccess::open(output_file, FileAccess::WRITE, &err); if (err != OK) { return false; } @@ -620,7 +620,6 @@ bool GDScriptTest::generate_output() { output += "\n"; // Make sure to insert newline for CI static checks. out_file->store_string(output); - out_file->close(); return true; } diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index 4255030b4e..d8f60d5e9b 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -204,8 +204,8 @@ void test(TestType p_type) { return; } - FileAccessRef fa = FileAccess::open(test, FileAccess::READ); - ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test); + Ref<FileAccess> fa = FileAccess::open(test, FileAccess::READ); + ERR_FAIL_COND_MSG(fa.is_null(), "Could not open file: " + test); // Initialize the language for the test routine. init_language(fa->get_path_absolute().get_base_dir()); diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp index cdb22b7d19..ae05c1b68d 100644 --- a/modules/gltf/editor/editor_scene_importer_blend.cpp +++ b/modules/gltf/editor/editor_scene_importer_blend.cpp @@ -62,10 +62,11 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_ List<String> *r_missing_deps, Error *r_err) { // Get global paths for source and sink. - const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path); + // 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( vformat("%s-%s.gltf", p_path.get_file().get_basename(), p_path.md5_text())); - const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink); + const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape(); // Handle configuration options. diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp index 7cfd85c73a..24564f55be 100644 --- a/modules/gltf/editor/editor_scene_importer_fbx.cpp +++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp @@ -53,10 +53,13 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t List<String> *r_missing_deps, Error *r_err) { // Get global paths for source and sink. - const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path); + // Don't use `c_escape()` as it can generate broken paths. These paths will be + // 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( vformat("%s-%s.glb", p_path.get_file().get_basename(), p_path.md5_text())); - const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink); + const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape_multiline(); // Run fbx2gltf. @@ -65,9 +68,9 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t List<String> args; args.push_back("--pbr-metallic-roughness"); args.push_back("--input"); - args.push_back(vformat("\"%s\"", source_global)); + args.push_back(source_global); args.push_back("--output"); - args.push_back(vformat("\"%s\"", sink_global)); + args.push_back(sink_global); args.push_back("--binary"); String standard_out; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index ee756c6d2e..73222330db 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -256,8 +256,8 @@ Error GLTFDocument::_serialize_scenes(Ref<GLTFState> state) { Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { Error err; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); + if (f.is_null()) { return err; } @@ -278,7 +278,7 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { return OK; } -Error GLTFDocument::_parse_glb(FileAccess *f, Ref<GLTFState> state) { +Error GLTFDocument::_parse_glb(Ref<FileAccess> f, Ref<GLTFState> state) { ERR_FAIL_NULL_V(f, ERR_INVALID_PARAMETER); ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(f->get_position() != 0, ERR_FILE_CANT_READ); @@ -696,8 +696,8 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_pat String filename = p_path.get_basename().get_file() + itos(i) + ".bin"; String path = p_path.get_base_dir() + "/" + filename; Error err; - FileAccessRef f = FileAccess::open(path, FileAccess::WRITE, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err); + if (f.is_null()) { return err; } if (buffer_data.size() == 0) { @@ -705,7 +705,6 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_pat } f->create(FileAccess::ACCESS_RESOURCES); f->store_buffer(buffer_data.ptr(), buffer_data.size()); - f->close(); gltf_buffer["uri"] = filename; gltf_buffer["byteLength"] = buffer_data.size(); buffers.push_back(gltf_buffer); @@ -729,8 +728,8 @@ Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_pa String filename = p_path.get_basename().get_file() + itos(i) + ".bin"; String path = p_path.get_base_dir() + "/" + filename; Error err; - FileAccessRef f = FileAccess::open(path, FileAccess::WRITE, &err); - if (!f) { + Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err); + if (f.is_null()) { return err; } if (buffer_data.size() == 0) { @@ -738,7 +737,6 @@ Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_pa } f->create(FileAccess::ACCESS_RESOURCES); f->store_buffer(buffer_data.ptr(), buffer_data.size()); - f->close(); gltf_buffer["uri"] = filename; gltf_buffer["byteLength"] = buffer_data.size(); buffers.push_back(gltf_buffer); @@ -3021,7 +3019,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path String texture_dir = "textures"; String path = p_path.get_base_dir(); String new_texture_dir = path + "/" + texture_dir; - DirAccessRef da = DirAccess::open(path); + Ref<DirAccess> da = DirAccess::open(path); if (!da->dir_exists(new_texture_dir)) { da->make_dir(new_texture_dir); } @@ -6097,7 +6095,14 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, animation->set_length(length); - ap->add_animation(name, animation); + Ref<AnimationLibrary> library; + if (!ap->has_animation_library("")) { + library.instantiate(); + ap->add_animation_library("", library); + } else { + library = ap->get_animation_library(""); + } + library->add_animation(name, animation); } void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { @@ -6588,9 +6593,9 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, } } -Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, FileAccess *f, int p_bake_fps) { +Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps) { Error err; - if (!f) { + if (f.is_null()) { return FAILED; } f->seek(0); @@ -6614,7 +6619,6 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, FileAccess *f, i ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR); state->json = json.get_data(); } - f->close(); if (!state->json.has("asset")) { return ERR_PARSE_ERROR; @@ -6703,8 +6707,8 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { if (p_path.to_lower().ends_with("glb")) { err = _encode_buffer_glb(state, p_path); ERR_FAIL_COND_V(err != OK, err); - FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(!f, FAILED); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(f.is_null(), FAILED); String json = Variant(state->json).to_json_string(); @@ -6741,18 +6745,15 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) { f->store_8(0); } - - f->close(); } else { err = _encode_buffer_bins(state, p_path); ERR_FAIL_COND_V(err != OK, err); - FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V(!f, FAILED); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V(f.is_null(), FAILED); f->create(FileAccess::ACCESS_RESOURCES); String json = Variant(state->json).to_json_string(); f->store_string(json); - f->close(); } return err; } @@ -6927,9 +6928,10 @@ Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_pa ERR_FAIL_COND_V(state.is_null(), FAILED); // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire Error err = FAILED; - state->use_named_skin_binds = - p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; - FileAccessMemory *file_access = memnew(FileAccessMemory); + state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; + + Ref<FileAccessMemory> file_access; + file_access.instantiate(); file_access->open_custom(p_bytes.ptr(), p_bytes.size()); err = _parse(state, p_base_path.get_base_dir(), file_access, p_bake_fps); ERR_FAIL_COND_V(err != OK, FAILED); @@ -7032,7 +7034,7 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint r_state->filename = p_path.get_file().get_basename(); r_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS; Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN); ERR_FAIL_NULL_V(f, ERR_FILE_CANT_OPEN); String base_path = p_base_path; diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 0b7664a616..19bc507a8d 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -196,7 +196,7 @@ private: Ref<Texture2D> _get_texture(Ref<GLTFState> state, const GLTFTextureIndex p_texture); Error _parse_json(const String &p_path, Ref<GLTFState> state); - Error _parse_glb(FileAccess *f, Ref<GLTFState> state); + Error _parse_glb(Ref<FileAccess> f, Ref<GLTFState> state); void _compute_node_heights(Ref<GLTFState> state); Error _parse_buffers(Ref<GLTFState> state, const String &p_base_path); Error _parse_buffer_views(Ref<GLTFState> state); @@ -457,7 +457,7 @@ public: void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name); Error _serialize(Ref<GLTFState> state, const String &p_path); - Error _parse(Ref<GLTFState> state, String p_path, FileAccess *f, int p_bake_fps); + Error _parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps); }; #endif // GLTF_DOCUMENT_H diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index 4166f92502..e09c76f052 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -87,7 +87,7 @@ static void _editor_init() { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "filesystem/import/fbx/fbx2gltf_path", PROPERTY_HINT_GLOBAL_FILE)); if (fbx_enabled) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (fbx2gltf_path.is_empty()) { WARN_PRINT("FBX file import is enabled, but no FBX2glTF path is configured. FBX files will not be imported."); } else if (!da->file_exists(fbx2gltf_path)) { diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp index 996bbfadd1..4588caf0a5 100644 --- a/modules/hdr/image_loader_hdr.cpp +++ b/modules/hdr/image_loader_hdr.cpp @@ -33,7 +33,7 @@ #include "core/os/os.h" #include "core/string/print_string.h" -Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { String header = f->get_token(); ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + "."); diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h index 0213fdbcb2..f2d53cc206 100644 --- a/modules/hdr/image_loader_hdr.h +++ b/modules/hdr/image_loader_hdr.h @@ -35,7 +35,7 @@ class ImageLoaderHDR : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderHDR(); }; diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index e8c66ab9da..51358876a4 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -103,7 +103,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p return OK; } -Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -113,8 +113,6 @@ Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force f->get_buffer(&w[0], src_image_len); - f->close(); - Error err = jpeg_load_image_from_buffer(p_image.ptr(), w, src_image_len); return err; diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h index 8e64f6fba7..de9700faec 100644 --- a/modules/jpg/image_loader_jpegd.h +++ b/modules/jpg/image_loader_jpegd.h @@ -35,7 +35,7 @@ class ImageLoaderJPG : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderJPG(); }; diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp index ea6b6d8233..e62581ab40 100644 --- a/modules/mbedtls/crypto_mbedtls.cpp +++ b/modules/mbedtls/crypto_mbedtls.cpp @@ -55,14 +55,13 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) { ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Key is in use"); PackedByteArray out; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'."); uint64_t flen = f->get_length(); out.resize(flen + 1); f->get_buffer(out.ptrw(), flen); out.write[flen] = 0; // string terminator - memdelete(f); int ret = 0; if (p_public_only) { @@ -79,8 +78,8 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) { } Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) { - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'."); unsigned char w[16000]; memset(w, 0, sizeof(w)); @@ -92,14 +91,12 @@ Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) { ret = mbedtls_pk_write_key_pem(&pkey, w, sizeof(w)); } if (ret != 0) { - memdelete(f); mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize anything we might have written. ERR_FAIL_V_MSG(FAILED, "Error writing key '" + itos(ret) + "'."); } size_t len = strlen((char *)w); f->store_buffer(w, len); - memdelete(f); mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize temporary buffer. return OK; } @@ -143,14 +140,13 @@ Error X509CertificateMbedTLS::load(String p_path) { ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Certificate is in use"); PackedByteArray out; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'."); uint64_t flen = f->get_length(); out.resize(flen + 1); f->get_buffer(out.ptrw(), flen); out.write[flen] = 0; // string terminator - memdelete(f); int ret = mbedtls_x509_crt_parse(&cert, out.ptr(), out.size()); ERR_FAIL_COND_V_MSG(ret, FAILED, "Error parsing some certificates: " + itos(ret)); @@ -167,8 +163,8 @@ Error X509CertificateMbedTLS::load_from_memory(const uint8_t *p_buffer, int p_le } Error X509CertificateMbedTLS::save(String p_path) { - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save X509CertificateMbedTLS file '" + p_path + "'."); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save X509CertificateMbedTLS file '" + p_path + "'."); mbedtls_x509_crt *crt = &cert; while (crt) { @@ -176,14 +172,12 @@ Error X509CertificateMbedTLS::save(String p_path) { size_t wrote = 0; int ret = mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT, cert.raw.p, cert.raw.len, w, sizeof(w), &wrote); if (ret != 0 || wrote == 0) { - memdelete(f); ERR_FAIL_V_MSG(FAILED, "Error writing certificate '" + itos(ret) + "'."); } f->store_buffer(w, wrote - 1); // don't write the string terminator crt = crt->next; } - memdelete(f); return OK; } diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp index 0e0da806bf..6cd710e792 100644 --- a/modules/minimp3/resource_importer_mp3.cpp +++ b/modules/minimp3/resource_importer_mp3.cpp @@ -75,9 +75,8 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s bool loop = p_options["loop"]; float loop_offset = p_options["loop_offset"]; - FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); - - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); + ERR_FAIL_COND_V(f.is_null(), ERR_CANT_OPEN); uint64_t len = f->get_length(); @@ -87,8 +86,6 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s f->get_buffer(w, len); - memdelete(f); - Ref<AudioStreamMP3> mp3_stream; mp3_stream.instantiate(); diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index 5884a24454..9253f105bb 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -238,11 +238,10 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { } } - FileAccessRef f = FileAccess::open(p_output_file, FileAccess::WRITE); - ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_output_file + "'."); + Ref<FileAccess> f = FileAccess::open(p_output_file, FileAccess::WRITE); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file '" + p_output_file + "'."); JSON json; f->store_string(json.stringify(classes_dict, "\t")); - f->close(); print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file)); } diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 8acd119880..2a8f7c17c7 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -3642,19 +3642,15 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r #endif Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'."); file->store_string(source); if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); return ERR_CANT_CREATE; } - file->close(); - memdelete(file); - #ifdef TOOLS_ENABLED if (ScriptServer::is_reload_scripts_on_save_enabled()) { CSharpLanguage::get_singleton()->reload_tool_script(p_resource, false); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index d8f5b814e4..2a93c15282 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -1035,8 +1035,8 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) { Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE); if (!DirAccess::exists(p_proj_dir)) { Error err = da->make_dir_recursive(p_proj_dir); @@ -1170,8 +1170,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) { Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) { ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE); if (!DirAccess::exists(p_proj_dir)) { Error err = da->make_dir_recursive(p_proj_dir); @@ -1280,8 +1280,8 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) { String output_dir = path::abspath(path::realpath(p_output_dir)); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, ERR_CANT_CREATE); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE); if (!DirAccess::exists(output_dir)) { Error err = da->make_dir_recursive(output_dir); @@ -2255,12 +2255,10 @@ uint32_t BindingsGenerator::get_version() { } Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) { - FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE); - - ERR_FAIL_COND_V_MSG(!file, ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'."); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(file.is_null(), ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'."); file->store_string(p_content.as_string()); - file->close(); return OK; } diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp index 3a41b3f6f5..79015686c3 100644 --- a/modules/mono/editor/code_completion.cpp +++ b/modules/mono/editor/code_completion.cpp @@ -144,7 +144,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr } } break; case CompletionKind::SCENE_PATHS: { - DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); List<String> directories; directories.push_back(dir_access->get_current_dir()); diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 7c2cb2e260..cb2b60fcce 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -76,7 +76,7 @@ String _get_mono_user_dir() { exe_dir = exe_dir.plus_file("../../..").simplify_path(); } - DirAccessRef d = DirAccess::create_for_path(exe_dir); + Ref<DirAccess> d = DirAccess::create_for_path(exe_dir); if (d->file_exists("._sc_") || d->file_exists("_sc_")) { // contain yourself diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index 424b74906f..e98ce8f6c1 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -643,7 +643,7 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const // Create destination directory if needed if (!DirAccess::exists(dst_dir)) { - DirAccessRef da = DirAccess::create_for_path(dst_dir); + Ref<DirAccess> da = DirAccess::create_for_path(dst_dir); Error err = da->make_dir_recursive(dst_dir); if (err != OK) { @@ -652,7 +652,7 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const } } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); String xml_file = assembly_name + ".xml"; if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) { diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index 01a6521876..1fbacca5bf 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -77,7 +77,7 @@ static String make_text(const char *log_domain, const char *log_level, const cha } void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) { - FileAccess *f = GDMonoLog::get_singleton()->log_file; + Ref<FileAccess> f = GDMonoLog::get_singleton()->log_file; if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) { String text = make_text(log_domain, log_level, message); @@ -93,7 +93,6 @@ void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, // Make sure to flush before aborting f->flush(); f->close(); - memdelete(f); abort(); } @@ -101,8 +100,8 @@ void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) { if (!DirAccess::exists(p_logs_dir)) { - DirAccessRef diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!diraccess, false); + Ref<DirAccess> diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(diraccess.is_null(), false); Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir); ERR_FAIL_COND_V_MSG(logs_mkdir_err != OK, false, "Failed to create mono logs directory."); } @@ -113,8 +112,8 @@ bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) { void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) { static const uint64_t MAX_SECS = 5 * 86400; // 5 days - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND(!da); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND(da.is_null()); Error err = da->change_dir(p_logs_dir); ERR_FAIL_COND_MSG(err != OK, "Cannot change directory to '" + p_logs_dir + "'."); @@ -170,7 +169,7 @@ void GDMonoLog::initialize() { log_file_path = logs_dir.plus_file(log_file_name); log_file = FileAccess::open(log_file_path, FileAccess::WRITE); - if (!log_file) { + if (log_file.is_null()) { ERR_PRINT("Mono: Cannot create log file at: " + log_file_path); } } @@ -178,7 +177,7 @@ void GDMonoLog::initialize() { mono_trace_set_level_string(log_level.get_data()); log_level_id = get_log_level_id(log_level.get_data()); - if (log_file) { + if (log_file.is_valid()) { OS::get_singleton()->print("Mono: Log file is: '%s'\n", log_file_path.utf8().get_data()); mono_trace_set_log_handler(mono_log_callback, this); } else { @@ -192,11 +191,6 @@ GDMonoLog::GDMonoLog() { GDMonoLog::~GDMonoLog() { singleton = nullptr; - - if (log_file) { - log_file->close(); - memdelete(log_file); - } } #else diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h index 9aa67a09e2..9fc35f8e31 100644 --- a/modules/mono/mono_gd/gd_mono_log.h +++ b/modules/mono/mono_gd/gd_mono_log.h @@ -48,7 +48,7 @@ class GDMonoLog { #ifdef GD_MONO_LOG_ENABLED int log_level_id = -1; - FileAccess *log_file = nullptr; + Ref<FileAccess> log_file; String log_file_path; bool _try_create_logs_dir(const String &p_logs_dir); diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp index dd29299330..e6975611d2 100644 --- a/modules/mono/utils/string_utils.cpp +++ b/modules/mono/utils/string_utils.cpp @@ -167,15 +167,13 @@ String escape_csharp_keyword(const String &p_name) { Error read_all_file_utf8(const String &p_path, String &r_content) { Vector<uint8_t> sourcef; Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'."); uint64_t len = f->get_length(); sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); uint64_t r = f->get_buffer(w, len); - f->close(); - memdelete(f); ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); w[len] = 0; diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index 61c3cefc7a..9e2daf3a99 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -124,6 +124,28 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform } } +void NavigationMeshGenerator::_add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) { + Vector<Vector3> mesh_vertices = p_array[Mesh::ARRAY_VERTEX]; + const Vector3 *vr = mesh_vertices.ptr(); + + Vector<int> mesh_indices = p_array[Mesh::ARRAY_INDEX]; + const int *ir = mesh_indices.ptr(); + + const int face_count = mesh_indices.size() / 3; + const int current_vertex_count = p_vertices.size() / 3; + + for (int j = 0; j < mesh_vertices.size(); j++) { + _add_vertex(p_xform.xform(vr[j]), p_vertices); + } + + for (int j = 0; j < face_count; j++) { + // CCW + p_indices.push_back(current_vertex_count + (ir[j * 3 + 0])); + p_indices.push_back(current_vertex_count + (ir[j * 3 + 2])); + p_indices.push_back(current_vertex_count + (ir[j * 3 + 1])); + } +} + void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) { int face_count = p_faces.size() / 3; int current_vertex_count = p_vertices.size() / 3; @@ -187,43 +209,38 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans Transform3D transform = p_navmesh_transform * static_body->get_global_transform() * col_shape->get_transform(); - Ref<Mesh> mesh; Ref<Shape3D> s = col_shape->get_shape(); BoxShape3D *box = Object::cast_to<BoxShape3D>(*s); if (box) { - Ref<BoxMesh> box_mesh; - box_mesh.instantiate(); - box_mesh->set_size(box->get_size()); - mesh = box_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + BoxMesh::create_mesh_array(arr, box->get_size()); + _add_mesh_array(arr, transform, p_vertices, p_indices); } CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s); if (capsule) { - Ref<CapsuleMesh> capsule_mesh; - capsule_mesh.instantiate(); - capsule_mesh->set_radius(capsule->get_radius()); - capsule_mesh->set_height(capsule->get_height()); - mesh = capsule_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + CapsuleMesh::create_mesh_array(arr, capsule->get_radius(), capsule->get_height()); + _add_mesh_array(arr, transform, p_vertices, p_indices); } CylinderShape3D *cylinder = Object::cast_to<CylinderShape3D>(*s); if (cylinder) { - Ref<CylinderMesh> cylinder_mesh; - cylinder_mesh.instantiate(); - cylinder_mesh->set_height(cylinder->get_height()); - cylinder_mesh->set_bottom_radius(cylinder->get_radius()); - cylinder_mesh->set_top_radius(cylinder->get_radius()); - mesh = cylinder_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + CylinderMesh::create_mesh_array(arr, cylinder->get_radius(), cylinder->get_radius(), cylinder->get_height()); + _add_mesh_array(arr, transform, p_vertices, p_indices); } SphereShape3D *sphere = Object::cast_to<SphereShape3D>(*s); if (sphere) { - Ref<SphereMesh> sphere_mesh; - sphere_mesh.instantiate(); - sphere_mesh->set_radius(sphere->get_radius()); - sphere_mesh->set_height(sphere->get_radius() * 2.0); - mesh = sphere_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + SphereMesh::create_mesh_array(arr, sphere->get_radius(), sphere->get_radius() * 2.0); + _add_mesh_array(arr, transform, p_vertices, p_indices); } ConcavePolygonShape3D *concave_polygon = Object::cast_to<ConcavePolygonShape3D>(*s); @@ -254,10 +271,6 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans _add_faces(faces, transform, p_vertices, p_indices); } } - - if (mesh.is_valid()) { - _add_mesh(mesh, transform, p_vertices, p_indices); - } } } } @@ -284,44 +297,39 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans RID shape = shapes[i + 1]; PhysicsServer3D::ShapeType type = PhysicsServer3D::get_singleton()->shape_get_type(shape); Variant data = PhysicsServer3D::get_singleton()->shape_get_data(shape); - Ref<Mesh> mesh; switch (type) { case PhysicsServer3D::SHAPE_SPHERE: { real_t radius = data; - Ref<SphereMesh> sphere_mesh; - sphere_mesh.instantiate(); - sphere_mesh->set_radius(radius); - sphere_mesh->set_height(radius * 2.0); - mesh = sphere_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + SphereMesh::create_mesh_array(arr, radius, radius * 2.0); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); } break; case PhysicsServer3D::SHAPE_BOX: { Vector3 extents = data; - Ref<BoxMesh> box_mesh; - box_mesh.instantiate(); - box_mesh->set_size(2.0 * extents); - mesh = box_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + BoxMesh::create_mesh_array(arr, extents * 2.0); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); } break; case PhysicsServer3D::SHAPE_CAPSULE: { Dictionary dict = data; real_t radius = dict["radius"]; real_t height = dict["height"]; - Ref<CapsuleMesh> capsule_mesh; - capsule_mesh.instantiate(); - capsule_mesh->set_radius(radius); - capsule_mesh->set_height(height); - mesh = capsule_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + CapsuleMesh::create_mesh_array(arr, radius, height); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); } break; case PhysicsServer3D::SHAPE_CYLINDER: { Dictionary dict = data; real_t radius = dict["radius"]; real_t height = dict["height"]; - Ref<CylinderMesh> cylinder_mesh; - cylinder_mesh.instantiate(); - cylinder_mesh->set_height(height); - cylinder_mesh->set_bottom_radius(radius); - cylinder_mesh->set_top_radius(radius); - mesh = cylinder_mesh; + Array arr; + arr.resize(RS::ARRAY_MAX); + CylinderMesh::create_mesh_array(arr, radius, radius, height); + _add_mesh_array(arr, shapes[i], p_vertices, p_indices); } break; case PhysicsServer3D::SHAPE_CONVEX_POLYGON: { PackedVector3Array vertices = data; @@ -354,10 +362,6 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans WARN_PRINT("Unsupported collision shape type."); } break; } - - if (mesh.is_valid()) { - _add_mesh(mesh, shapes[i], p_vertices, p_indices); - } } } } diff --git a/modules/navigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h index 21f7a4941b..8cc1531b53 100644 --- a/modules/navigation/navigation_mesh_generator.h +++ b/modules/navigation/navigation_mesh_generator.h @@ -51,6 +51,7 @@ protected: static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_vertices); static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices); + static void _add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices); static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices); static void _parse_geometry(const Transform3D &p_navmesh_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children); diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index 1ea1346f61..2ba33419d7 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -226,27 +226,6 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); - // Create our HP MR controller profile - profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller"); - profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); - profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); - profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); - // hpmr controllers have no select button we can use - profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); - // hpmr controllers only register click, not touch, on our a/b/x/y buttons - profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand - profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand - profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); - profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); - profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); - profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); - // primary on our hpmr controller is our thumbstick - profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); - profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); - // No secondary on our hpmr controller - profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); - add_interaction_profile(profile); - // Create our Meta touch controller profile profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller"); profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); @@ -297,6 +276,116 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); add_interaction_profile(profile); + + // Note, the following profiles are all part of extensions. + // We include these regardless of whether the extension is active. + // We want our action map to be as complete as possible so our game is as portable as possible. + // It is very possible these will in due time become core. + + // Create our HP MR controller profile + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // hpmr controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + // hpmr controllers only register click, not touch, on our a/b/x/y buttons + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); + // primary on our hpmr controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + // No secondary on our hpmr controller + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Samsung Odyssey controller profile, + // Note that this controller is only identified specifically on WMR, on SteamVR this is identified as a normal WMR controller. + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/samsung/odyssey_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + // Odyssey controllers have no select button we can use + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click"); + // Odyssey controller has no a/b/x/y buttons + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our Odyssey controller is our thumbstick, no touch + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + // secondary on our Odyssey controller is our trackpad + profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); + profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Vive Cosmos controller + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_cosmos_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); + profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our Cosmos controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // No secondary on our cosmos controller + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Vive Focus 3 controller + // Note, Vive Focus 3 currently is not yet supported as a stand alone device + // however HTC currently has a beta OpenXR runtime in testing we may support in the near future + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_focus3_controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); + profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select + profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand + profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch"); + profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); + // primary on our Focus 3 controller is our thumbstick + profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick"); + profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch"); + // We only have a thumb rest + profile->add_new_binding(secondary_touch, "/user/hand/left/input/thumbrest/touch,/user/hand/right/input/thumbrest/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); + + // Create our Huawei controller + profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/huawei/controller"); + profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose"); + profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); + profile->add_new_binding(menu_button, "/user/hand/left/input/home/click,/user/hand/right/input/home/click"); + profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); + profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click"); + // primary on our Huawei controller is our trackpad + profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad"); + profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click"); + profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch"); + profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic"); + add_interaction_profile(profile); } void OpenXRActionMap::create_editor_action_sets() { diff --git a/modules/openxr/action_map/openxr_defs.cpp b/modules/openxr/action_map/openxr_defs.cpp index 3358b03276..e10326449c 100644 --- a/modules/openxr/action_map/openxr_defs.cpp +++ b/modules/openxr/action_map/openxr_defs.cpp @@ -234,6 +234,150 @@ OpenXRDefs::IOPath OpenXRDefs::index_io_paths[] = { { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, }; +// Samsung odyssey controller +OpenXRDefs::IOPath OpenXRDefs::odyssey_io_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Vive Cosmos controller +OpenXRDefs::IOPath OpenXRDefs::vive_cosmos_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Shoulder click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/right/input/shoulder/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Shoulder click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/shoulder/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Vive Focus 3 controller +OpenXRDefs::IOPath OpenXRDefs::vive_focus3_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch ", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Squeeze touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Thumbrest touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbrest/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + +// Huawei controller +OpenXRDefs::IOPath OpenXRDefs::huawei_controller_paths[] = { + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE }, + + { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Back click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/back/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Back click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/back/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Volume up click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/volume_up/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Volume up click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/volume_up/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Volume down click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/volume_down/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Volume down click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/volume_down/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT }, + { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 }, + { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL }, + { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL }, + + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, + { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC }, +}; + OpenXRDefs::InteractionProfile OpenXRDefs::available_interaction_profiles[] = { { "Simple controller", // display_name @@ -271,6 +415,30 @@ OpenXRDefs::InteractionProfile OpenXRDefs::available_interaction_profiles[] = { index_io_paths, // io_paths sizeof(index_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count }, + { + "Samsung Odyssey controller", // display_name + "/interaction_profiles/samsung/odyssey_controller", // openxr_path + odyssey_io_paths, // io_paths + sizeof(odyssey_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "Vive Cosmos controller", // display_name + "/interaction_profiles/htc/vive_cosmos_controller", // openxr_path + vive_cosmos_paths, // io_paths + sizeof(vive_cosmos_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "Vive Focus 3 controller", // display_name + "/interaction_profiles/htc/vive_focus3_controller", // openxr_path + vive_focus3_paths, // io_paths + sizeof(vive_focus3_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, + { + "Huawei controller", // display_name + "/interaction_profiles/huawei/controller", // openxr_path + huawei_controller_paths, // io_paths + sizeof(huawei_controller_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count + }, }; int OpenXRDefs::available_interaction_profile_count = sizeof(OpenXRDefs::available_interaction_profiles) / sizeof(OpenXRDefs::InteractionProfile); diff --git a/modules/openxr/action_map/openxr_defs.h b/modules/openxr/action_map/openxr_defs.h index aa3b2a8f8a..dbda4757f1 100644 --- a/modules/openxr/action_map/openxr_defs.h +++ b/modules/openxr/action_map/openxr_defs.h @@ -85,6 +85,10 @@ private: static IOPath hpmr_io_paths[]; static IOPath touch_io_paths[]; static IOPath index_io_paths[]; + static IOPath odyssey_io_paths[]; + static IOPath vive_cosmos_paths[]; + static IOPath vive_focus3_paths[]; + static IOPath huawei_controller_paths[]; static InteractionProfile available_interaction_profiles[]; static int available_interaction_profile_count; diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index 00f81731c2..f3064041b8 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -40,6 +40,7 @@ #include <openxr/openxr.h> class OpenXRAPI; +class OpenXRActionMap; class OpenXRExtensionWrapper { protected: diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp index 861038be33..ae3617938e 100644 --- a/modules/openxr/openxr_api.cpp +++ b/modules/openxr/openxr_api.cpp @@ -172,11 +172,18 @@ bool OpenXRAPI::load_supported_extensions() { bool OpenXRAPI::is_extension_supported(const char *p_extension) const { for (uint32_t i = 0; i < num_supported_extensions; i++) { - if (strcmp(supported_extensions[i].extensionName, p_extension)) { + if (strcmp(supported_extensions[i].extensionName, p_extension) == 0) { +#ifdef DEBUG + print_line("OpenXR: requested extension", p_extension, "is supported"); +#endif return true; } } +#ifdef DEBUG + print_line("OpenXR: requested extension", p_extension, "is not supported"); +#endif + return false; } @@ -207,6 +214,14 @@ bool OpenXRAPI::create_instance() { } } + // Add optional extensions for controllers that may be supported. + // Overkill to create extension classes for this. + requested_extensions[XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME] = &ext_hp_mixed_reality_available; + requested_extensions[XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME] = &ext_samsung_odyssey_available; + requested_extensions[XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_cosmos_available; + requested_extensions[XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_focus3_available; + requested_extensions[XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_huawei_controller_available; + // Check which extensions are supported enabled_extensions.clear(); for (auto &requested_extension : requested_extensions) { diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index d641767a9b..7baf581a05 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -75,6 +75,12 @@ private: Vector<OpenXRExtensionWrapper *> registered_extension_wrappers; Vector<const char *> enabled_extensions; + bool ext_hp_mixed_reality_available = false; + bool ext_samsung_odyssey_available = false; + bool ext_vive_cosmos_available = false; + bool ext_vive_focus3_available = false; + bool ext_huawei_controller_available = false; + // composition layer providers Vector<OpenXRCompositionLayerProvider *> composition_layer_providers; diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp index 79ef2de929..7fe2e589b1 100644 --- a/modules/svg/image_loader_svg.cpp +++ b/modules/svg/image_loader_svg.cpp @@ -136,7 +136,7 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const p_extensions->push_back("svg"); } -Error ImageLoaderSVG::load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) { +Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) { String svg = p_fileaccess->get_as_utf8_string(); create_image_from_string(p_image, svg, p_scale, false, false); ERR_FAIL_COND_V(p_image->is_empty(), FAILED); diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h index d0bd71d92d..94c17fda43 100644 --- a/modules/svg/image_loader_svg.h +++ b/modules/svg/image_loader_svg.h @@ -42,7 +42,7 @@ public: void set_replace_colors(Dictionary p_replace_colors) { replace_colors = p_replace_colors; } void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color); - virtual Error load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) override; + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) override; virtual void get_recognized_extensions(List<String> *p_extensions) const override; }; diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 0fce54a18a..4cd5dada4d 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -410,7 +410,6 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) { } uint64_t len = f->get_length(); PackedByteArray icu_data = f->get_buffer(len); - f->close(); UErrorCode err = U_ZERO_ERROR; udata_setCommonData(icu_data.ptr(), &err); @@ -461,9 +460,8 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const { icu_data.resize(U_ICUDATA_SIZE); memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE); f->store_buffer(icu_data); - f->close(); - return true; + return true; #else return false; #endif diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp index 5060c1ab35..08ad1ef9f8 100644 --- a/modules/tga/image_loader_tga.cpp +++ b/modules/tga/image_loader_tga.cpp @@ -230,7 +230,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff return OK; } -Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -330,7 +330,6 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force } } - f->close(); return err; } @@ -339,12 +338,14 @@ void ImageLoaderTGA::get_recognized_extensions(List<String> *p_extensions) const } static Ref<Image> _tga_mem_loader_func(const uint8_t *p_tga, int p_size) { - FileAccessMemory memfile; - Error open_memfile_error = memfile.open_custom(p_tga, p_size); + Ref<FileAccessMemory> memfile; + memfile.instantiate(); + Error open_memfile_error = memfile->open_custom(p_tga, p_size); ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for TGA image buffer."); + Ref<Image> img; img.instantiate(); - Error load_error = ImageLoaderTGA().load_image(img, &memfile, false, 1.0f); + Error load_error = ImageLoaderTGA().load_image(img, memfile, false, 1.0f); ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load TGA image."); return img; } diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h index 282a2a1662..9b7cbbac77 100644 --- a/modules/tga/image_loader_tga.h +++ b/modules/tga/image_loader_tga.h @@ -73,7 +73,7 @@ class ImageLoaderTGA : public ImageFormatLoader { static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size); public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderTGA(); }; diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 94f60a7d9d..441fc8edbd 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -114,7 +114,7 @@ void VideoStreamPlaybackTheora::video_write() { } void VideoStreamPlaybackTheora::clear() { - if (!file) { + if (file.is_null()) { return; } @@ -152,10 +152,7 @@ void VideoStreamPlaybackTheora::clear() { theora_eos = false; vorbis_eos = false; - if (file) { - memdelete(file); - } - file = nullptr; + file = Ref<FileAccess>(); playing = false; }; @@ -165,11 +162,8 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { th_setup_info *ts = nullptr; file_name = p_file; - if (file) { - memdelete(file); - } file = FileAccess::open(p_file, FileAccess::READ); - ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_file + "'."); + ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_file + "'."); #ifdef THEORA_USE_THREAD_STREAMING thread_exit = false; @@ -375,7 +369,7 @@ Ref<Texture2D> VideoStreamPlaybackTheora::get_texture() const { } void VideoStreamPlaybackTheora::update(float p_delta) { - if (!file) { + if (file.is_null()) { return; } @@ -506,9 +500,9 @@ void VideoStreamPlaybackTheora::update(float p_delta) { } #ifdef THEORA_USE_THREAD_STREAMING - if (file && thread_eof && no_theora && theora_eos && ring_buffer.data_left() == 0) { + if (file.is_valid() && thread_eof && no_theora && theora_eos && ring_buffer.data_left() == 0) { #else - if (file && /*!videobuf_ready && */ no_theora && theora_eos) { + if (file.is_valid() && /*!videobuf_ready && */ no_theora && theora_eos) { #endif //printf("video done, stopping\n"); stop(); @@ -664,10 +658,6 @@ VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() { memdelete(thread_sem); #endif clear(); - - if (file) { - memdelete(file); - } }; void VideoStreamTheora::_bind_methods() { @@ -680,8 +670,8 @@ void VideoStreamTheora::_bind_methods() { //////////// RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { if (r_error) { *r_error = ERR_CANT_OPEN; } @@ -697,8 +687,6 @@ RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_origi *r_error = OK; } - f->close(); - memdelete(f); return ogv_stream; } diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index b61412e665..6fa7313fad 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -56,7 +56,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback { Image::Format format = Image::Format::FORMAT_L8; Vector<uint8_t> frame_data; int frames_pending = 0; - FileAccess *file = nullptr; + Ref<FileAccess> file; String file_name; int audio_frames_wrote = 0; Point2i size; diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp index 688707a42d..1ff2600839 100644 --- a/modules/tinyexr/image_loader_tinyexr.cpp +++ b/modules/tinyexr/image_loader_tinyexr.cpp @@ -37,7 +37,7 @@ #include "thirdparty/tinyexr/tinyexr.h" -Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -47,8 +47,6 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f f->get_buffer(&w[0], src_image_len); - f->close(); - // Re-implementation of tinyexr's LoadEXRFromMemory using Godot types to store the Image data // and Godot's error codes. // When debugging after updating the thirdparty library, check that we're still in sync with diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h index aba5fdb959..c147861c26 100644 --- a/modules/tinyexr/image_loader_tinyexr.h +++ b/modules/tinyexr/image_loader_tinyexr.h @@ -35,7 +35,7 @@ class ImageLoaderTinyEXR : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderTinyEXR(); }; diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp index 3750994663..5fa6ace827 100644 --- a/modules/tinyexr/image_saver_tinyexr.cpp +++ b/modules/tinyexr/image_saver_tinyexr.cpp @@ -275,8 +275,8 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) print_error(String("Saving EXR failed. Error: {0}").format(varray(err))); return ERR_FILE_CANT_WRITE; } else { - FileAccessRef ref = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V(!ref, ERR_FILE_CANT_WRITE); + Ref<FileAccess> ref = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V(ref.is_null(), ERR_FILE_CANT_WRITE); ref->store_buffer(mem, bytes); free(mem); } diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp index d12e65a96a..03e145216a 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp @@ -78,9 +78,8 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin bool loop = p_options["loop"]; float loop_offset = p_options["loop_offset"]; - FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ); - - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); + Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); uint64_t len = f->get_length(); @@ -90,8 +89,6 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin f->get_buffer(w, len); - memdelete(f); - Ref<AudioStreamOGGVorbis> ogg_vorbis_stream; ogg_vorbis_stream.instantiate(); diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index 902e182d83..0e41f6c973 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -211,7 +211,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { return img; } -Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { +Error ImageLoaderWEBP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) { Vector<uint8_t> src_image; uint64_t src_image_len = f->get_length(); ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT); @@ -221,8 +221,6 @@ Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_forc f->get_buffer(&w[0], src_image_len); - f->close(); - Error err = webp_load_image_from_buffer(p_image.ptr(), w, src_image_len); return err; diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h index 327582ca55..1acd1459a0 100644 --- a/modules/webp/image_loader_webp.h +++ b/modules/webp/image_loader_webp.h @@ -35,7 +35,7 @@ class ImageLoaderWEBP : public ImageFormatLoader { public: - virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); + virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderWEBP(); }; diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp index 7fb4f54fca..e2b1c757d6 100644 --- a/platform/android/dir_access_jandroid.cpp +++ b/platform/android/dir_access_jandroid.cpp @@ -42,7 +42,7 @@ jmethodID DirAccessJAndroid::_dir_next = nullptr; jmethodID DirAccessJAndroid::_dir_close = nullptr; jmethodID DirAccessJAndroid::_dir_is_dir = nullptr; -DirAccess *DirAccessJAndroid::create_fs() { +Ref<DirAccess> DirAccessJAndroid::create_fs() { return memnew(DirAccessJAndroid); } @@ -143,7 +143,7 @@ Error DirAccessJAndroid::change_dir(String p_dir) { return OK; } -String DirAccessJAndroid::get_current_dir(bool p_include_drive) { +String DirAccessJAndroid::get_current_dir(bool p_include_drive) const { return "res://" + current_dir; } @@ -155,9 +155,9 @@ bool DirAccessJAndroid::file_exists(String p_file) { sd = current_dir.plus_file(p_file); } - FileAccessAndroid *f = memnew(FileAccessAndroid); + Ref<FileAccessAndroid> f; + f.instantiate(); bool exists = f->file_exists(sd); - memdelete(f); return exists; } diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h index 4f4a984b12..3d3c9f9223 100644 --- a/platform/android/dir_access_jandroid.h +++ b/platform/android/dir_access_jandroid.h @@ -51,7 +51,7 @@ class DirAccessJAndroid : public DirAccess { String current_dir; String current; - static DirAccess *create_fs(); + static Ref<DirAccess> create_fs(); public: virtual Error list_dir_begin(); ///< This starts dir listing @@ -64,7 +64,7 @@ public: virtual String get_drive(int p_drive); virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success - virtual String get_current_dir(bool p_include_drive = true); ///< return current dir location + virtual String get_current_dir(bool p_include_drive = true) const; ///< return current dir location virtual bool file_exists(String p_file); virtual bool dir_exists(String p_dir); diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 51f2885fbe..8cfa3a67b9 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -596,8 +596,8 @@ Vector<String> EditorExportPlatformAndroid::get_abis() { /// List the gdap files in the directory specified by the p_path parameter. Vector<String> EditorExportPlatformAndroid::list_gdap_files(const String &p_path) { Vector<String> dir_files; - DirAccessRef da = DirAccess::open(p_path); - if (da) { + Ref<DirAccess> da = DirAccess::open(p_path); + if (da.is_valid()) { da->list_dir_begin(); while (true) { String file = da->get_next(); @@ -2008,7 +2008,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() { Error errn; String build_tools_dir = sdk_path.plus_file("build-tools"); - DirAccessRef da = DirAccess::open(build_tools_dir, &errn); + Ref<DirAccess> da = DirAccess::open(build_tools_dir, &errn); if (errn != OK) { print_error("Unable to open Android 'build-tools' directory."); return apksigner_path; @@ -2125,7 +2125,7 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr } else { Error errn; // Check for the platform-tools directory. - DirAccessRef da = DirAccess::open(sdk_path.plus_file("platform-tools"), &errn); + Ref<DirAccess> da = DirAccess::open(sdk_path.plus_file("platform-tools"), &errn); if (errn != OK) { err += TTR("Invalid Android SDK path in Editor Settings."); err += TTR("Missing 'platform-tools' directory!"); @@ -2143,7 +2143,7 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr } // Check for the build-tools directory. - DirAccessRef build_tools_da = DirAccess::open(sdk_path.plus_file("build-tools"), &errn); + Ref<DirAccess> build_tools_da = DirAccess::open(sdk_path.plus_file("build-tools"), &errn); if (errn != OK) { err += TTR("Invalid Android SDK path in Editor Settings."); err += TTR("Missing 'build-tools' directory!"); @@ -2422,12 +2422,12 @@ Error EditorExportPlatformAndroid::sign_apk(const Ref<EditorExportPreset> &p_pre } void EditorExportPlatformAndroid::_clear_assets_directory() { - DirAccessRef da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES); // Clear the APK assets directory if (da_res->dir_exists(APK_ASSETS_DIRECTORY)) { print_verbose("Clearing APK assets directory.."); - DirAccessRef da_assets = DirAccess::open(APK_ASSETS_DIRECTORY); + Ref<DirAccess> da_assets = DirAccess::open(APK_ASSETS_DIRECTORY); da_assets->erase_contents_recursive(); da_res->remove(APK_ASSETS_DIRECTORY); } @@ -2435,7 +2435,7 @@ void EditorExportPlatformAndroid::_clear_assets_directory() { // Clear the AAB assets directory if (da_res->dir_exists(AAB_ASSETS_DIRECTORY)) { print_verbose("Clearing AAB assets directory.."); - DirAccessRef da_assets = DirAccess::open(AAB_ASSETS_DIRECTORY); + Ref<DirAccess> da_assets = DirAccess::open(AAB_ASSETS_DIRECTORY); da_assets->erase_contents_recursive(); da_res->remove(AAB_ASSETS_DIRECTORY); } @@ -2455,7 +2455,7 @@ void EditorExportPlatformAndroid::_remove_copied_libs() { ERR_FAIL_COND_MSG(error, "Error parsing \"" + libs_json + "\" on line " + itos(json.get_error_line()) + ": " + json.get_error_message()); Vector<String> libs = json.get_data(); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); for (int i = 0; i < libs.size(); i++) { print_verbose("Removing previously installed library " + libs[i]); da->remove(libs[i]); @@ -2544,14 +2544,13 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP //test that installed build version is alright { print_verbose("Checking build version.."); - FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open("res://android/.build_version", FileAccess::READ); + if (f.is_null()) { EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu.")); return ERR_UNCONFIGURED; } String version = f->get_line().strip_edges(); print_verbose("- build version: " + version); - f->close(); if (version != VERSION_FULL_CONFIG) { EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG)); return ERR_UNCONFIGURED; @@ -2587,10 +2586,9 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP return err; } if (user_data.libs.size() > 0) { - FileAccessRef fa = FileAccess::open(GDNATIVE_LIBS_PATH, FileAccess::WRITE); + Ref<FileAccess> fa = FileAccess::open(GDNATIVE_LIBS_PATH, FileAccess::WRITE); JSON json; fa->store_string(json.stringify(user_data.libs, "\t")); - fa->close(); } } else { print_verbose("Saving apk expansion file.."); @@ -2770,8 +2768,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP return ERR_FILE_BAD_PATH; } - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); if (ep.step(TTR("Creating APK..."), 0)) { return ERR_SKIP; @@ -2785,9 +2782,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP int ret = unzGoToFirstFile(pkg); - zlib_filefunc_def io2 = io; - FileAccess *dst_f = nullptr; - io2.opaque = &dst_f; + zlib_filefunc_def io2 = zipio_create_io(); String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk"); @@ -2983,9 +2978,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP ret = unzGoToFirstFile(tmp_unaligned); - io2 = io; - dst_f = nullptr; - io2.opaque = &dst_f; + io2 = zipio_create_io(); zipFile final_apk = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2); // Take files from the unaligned APK and write them out to the aligned one diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index 430aeaf036..173bb8bcb7 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -75,8 +75,8 @@ String _get_android_orientation_label(DisplayServer::ScreenOrientation screen_or // Utility method used to create a directory. Error create_directory(const String &p_dir) { if (!DirAccess::exists(p_dir)) { - DirAccessRef filesystem_da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'."); + Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + ERR_FAIL_COND_V_MSG(filesystem_da.is_null(), ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'."); Error err = filesystem_da->make_dir_recursive(p_dir); ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Cannot create directory '" + p_dir + "'."); } @@ -91,10 +91,9 @@ Error store_file_at_path(const String &p_path, const Vector<uint8_t> &p_data) { if (err != OK) { return err; } - FileAccess *fa = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); + Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); fa->store_buffer(p_data.ptr(), p_data.size()); - memdelete(fa); return OK; } @@ -109,10 +108,9 @@ Error store_string_at_path(const String &p_path, const String &p_data) { } return err; } - FileAccess *fa = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); + Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); fa->store_string(p_data); - memdelete(fa); return OK; } @@ -152,8 +150,8 @@ Error _create_project_name_strings_files(const Ref<EditorExportPreset> &p_preset store_string_at_path("res://android/build/res/values/godot_project_name_string.xml", processed_default_xml_string); // Searches the Gradle project res/ directory to find all supported locales - DirAccessRef da = DirAccess::open("res://android/build/res"); - if (!da) { + Ref<DirAccess> da = DirAccess::open("res://android/build/res"); + if (da.is_null()) { if (OS::get_singleton()->is_stdout_verbose()) { print_error("Unable to open Android resources directory."); } diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index c84a919b6b..ee6eeaa849 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -34,7 +34,7 @@ AAssetManager *FileAccessAndroid::asset_manager = nullptr; -FileAccess *FileAccessAndroid::create_android() { +Ref<FileAccess> FileAccessAndroid::create_android() { return memnew(FileAccessAndroid); } diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index fb612cd008..ea7531e9ad 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -38,7 +38,7 @@ //#include <android_native_app_glue.h> class FileAccessAndroid : public FileAccess { - static FileAccess *create_android(); + static Ref<FileAccess> create_android(); mutable AAsset *a = nullptr; mutable uint64_t len = 0; mutable uint64_t pos = 0; diff --git a/platform/iphone/export/export_plugin.cpp b/platform/iphone/export/export_plugin.cpp index c83d13c0b8..a540a7658c 100644 --- a/platform/iphone/export/export_plugin.cpp +++ b/platform/iphone/export/export_plugin.cpp @@ -530,8 +530,8 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr String json_description = "{\"images\":["; String sizes; - DirAccessRef da = DirAccess::open(p_iconset_dir); - ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_iconset_dir + "'."); + Ref<DirAccess> da = DirAccess::open(p_iconset_dir); + ERR_FAIL_COND_V_MSG(da.is_null(), ERR_CANT_OPEN, "Cannot open directory '" + p_iconset_dir + "'."); for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { IconInfo info = icon_infos[i]; @@ -588,17 +588,15 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr } json_description += "]}"; - FileAccess *json_file = FileAccess::open(p_iconset_dir + "Contents.json", FileAccess::WRITE); - ERR_FAIL_COND_V(!json_file, ERR_CANT_CREATE); + Ref<FileAccess> json_file = FileAccess::open(p_iconset_dir + "Contents.json", FileAccess::WRITE); + ERR_FAIL_COND_V(json_file.is_null(), ERR_CANT_CREATE); CharString json_utf8 = json_description.utf8(); json_file->store_buffer((const uint8_t *)json_utf8.get_data(), json_utf8.length()); - memdelete(json_file); - FileAccess *sizes_file = FileAccess::open(p_iconset_dir + "sizes", FileAccess::WRITE); - ERR_FAIL_COND_V(!sizes_file, ERR_CANT_CREATE); + Ref<FileAccess> sizes_file = FileAccess::open(p_iconset_dir + "sizes", FileAccess::WRITE); + ERR_FAIL_COND_V(sizes_file.is_null(), ERR_CANT_CREATE); CharString sizes_utf8 = sizes.utf8(); sizes_file->store_buffer((const uint8_t *)sizes_utf8.get_data(), sizes_utf8.length()); - memdelete(sizes_file); return OK; } @@ -672,8 +670,8 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor } Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) { - DirAccessRef da = DirAccess::open(p_dest_dir); - ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'."); + Ref<DirAccess> da = DirAccess::open(p_dest_dir); + ERR_FAIL_COND_V_MSG(da.is_null(), ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'."); for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { LoadingScreenInfo info = loading_screen_infos[i]; @@ -761,7 +759,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExp return OK; } -Error EditorExportPlatformIOS::_walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata) { +Error EditorExportPlatformIOS::_walk_dir_recursive(Ref<DirAccess> &p_da, FileHandler p_handler, void *p_userdata) { Vector<String> dirs; String current_dir = p_da->get_current_dir(); p_da->list_dir_begin(); @@ -964,8 +962,8 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) { String binary_name = p_out_dir.get_file().get_basename(); - DirAccessRef da = DirAccess::create_for_path(p_asset); - if (!da) { + Ref<DirAccess> da = DirAccess::create_for_path(p_asset); + if (da.is_null()) { ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't create directory: " + p_asset + "."); } bool file_exists = da->file_exists(p_asset); @@ -1030,8 +1028,8 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String destination = p_out_dir.plus_file(asset_path); } - DirAccessRef filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'."); + Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V_MSG(filesystem_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'."); if (!filesystem_da->dir_exists(destination_dir)) { Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir); @@ -1097,11 +1095,9 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String String info_plist = info_plist_format.replace("$name", file_name); - FileAccess *f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE); + if (f.is_valid()) { f->store_string(info_plist); - f->close(); - memdelete(f); } } } @@ -1411,8 +1407,8 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p } { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (da) { + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (da.is_valid()) { String current_dir = da->get_current_dir(); // remove leftovers from last export so they don't interfere @@ -1488,12 +1484,11 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p Vector<IOSExportAsset> assets; - DirAccessRef tmp_app_path = DirAccess::create_for_path(dest_dir); - ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE); + Ref<DirAccess> tmp_app_path = DirAccess::create_for_path(dest_dir); + ERR_FAIL_COND_V(tmp_app_path.is_null(), ERR_CANT_CREATE); print_line("Unzipping..."); - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); if (!src_pkg_zip) { EditorNode::add_io_error("Could not open export template (not a zip file?):\n" + src_pkg_name); @@ -1575,15 +1570,13 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p } /* write the file */ - FileAccess *f = FileAccess::open(file, FileAccess::WRITE); - if (!f) { + Ref<FileAccess> f = FileAccess::open(file, FileAccess::WRITE); + if (f.is_null()) { ERR_PRINT("Can't write '" + file + "'."); unzClose(src_pkg_zip); return ERR_CANT_CREATE; }; f->store_buffer(data.ptr(), data.size()); - f->close(); - memdelete(f); #if defined(OSX_ENABLED) || defined(X11_ENABLED) if (is_execute) { @@ -1614,7 +1607,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p { String fname = dest_dir + binary_name + "/en.lproj"; tmp_app_path->make_dir_recursive(fname); - FileAccessRef f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); f->store_line("/* Localized versions of Info.plist keys */"); f->store_line(""); f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get("application/config/name").operator String() + "\";"); @@ -1629,7 +1622,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p String lang = tr->get_locale(); String fname = dest_dir + binary_name + "/" + lang + ".lproj"; tmp_app_path->make_dir_recursive(fname); - FileAccessRef f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); f->store_line("/* Localized versions of Info.plist keys */"); f->store_line(""); if (appnames.has(lang)) { @@ -1683,9 +1676,8 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p String launch_image_path = dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/"; String splash_image_path = dest_dir + binary_name + "/Images.xcassets/SplashImage.imageset/"; - DirAccessRef launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - - if (!launch_screen_da) { + Ref<DirAccess> launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (launch_screen_da.is_null()) { return ERR_CANT_CREATE; } @@ -1722,25 +1714,22 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p _export_additional_assets(dest_dir + binary_name, libraries, assets); _add_assets_to_project(p_preset, project_file_data, assets); String project_file_name = dest_dir + binary_name + ".xcodeproj/project.pbxproj"; - FileAccess *f = FileAccess::open(project_file_name, FileAccess::WRITE); - if (!f) { + Ref<FileAccess> f = FileAccess::open(project_file_name, FileAccess::WRITE); + if (f.is_null()) { ERR_PRINT("Can't write '" + project_file_name + "'."); return ERR_CANT_CREATE; }; f->store_buffer(project_file_data.ptr(), project_file_data.size()); - f->close(); - memdelete(f); #ifdef OSX_ENABLED { if (ep.step("Code-signing dylibs", 2)) { return ERR_SKIP; } - DirAccess *dylibs_dir = DirAccess::open(dest_dir + binary_name + "/dylibs"); - ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN); + Ref<DirAccess> dylibs_dir = DirAccess::open(dest_dir + binary_name + "/dylibs"); + ERR_FAIL_COND_V(dylibs_dir.is_null(), ERR_CANT_OPEN); CodesignData codesign_data(p_preset, p_debug); err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data); - memdelete(dylibs_dir); ERR_FAIL_COND_V(err, err); } diff --git a/platform/iphone/export/export_plugin.h b/platform/iphone/export/export_plugin.h index d88b387073..3831f3bff2 100644 --- a/platform/iphone/export/export_plugin.h +++ b/platform/iphone/export/export_plugin.h @@ -65,7 +65,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { Vector<PluginConfigIOS> plugins; typedef Error (*FileHandler)(String p_file, void *p_userdata); - static Error _walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata); + static Error _walk_dir_recursive(Ref<DirAccess> &p_da, FileHandler p_handler, void *p_userdata); static Error _codesign(String p_file, void *p_userdata); void _blend_and_rotate(Ref<Image> &p_dst, Ref<Image> &p_src, bool p_rot); @@ -215,8 +215,8 @@ public: /// List the gdip files in the directory specified by the p_path parameter. static Vector<String> list_plugin_config_files(const String &p_path, bool p_check_directories) { Vector<String> dir_files; - DirAccessRef da = DirAccess::open(p_path); - if (da) { + Ref<DirAccess> da = DirAccess::open(p_path); + if (da.is_valid()) { da->list_dir_begin(); while (true) { String file = da->get_next(); diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm index 1d990b5625..ea1bc0ef64 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/iphone/os_iphone.mm @@ -259,7 +259,7 @@ Error OSIPhone::shell_open(String p_uri) { } void OSIPhone::set_user_data_dir(String p_dir) { - DirAccessRef da = DirAccess::open(p_dir); + Ref<DirAccess> da = DirAccess::open(p_dir); user_data_dir = da->get_current_dir(); printf("setting data dir to %s from %s\n", user_data_dir.utf8().get_data(), p_dir.utf8().get_data()); } diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/javascript/api/javascript_tools_editor_plugin.cpp index 0442a1eaeb..46eec8eda2 100644 --- a/platform/javascript/api/javascript_tools_editor_plugin.cpp +++ b/platform/javascript/api/javascript_tools_editor_plugin.cpp @@ -64,8 +64,7 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) { } String resource_path = ProjectSettings::get_singleton()->get_resource_path(); - FileAccess *src_f; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); // Name the downloaded ZIP file to contain the project name and download date for easier organization. // Replace characters not allowed (or risky) in Windows file names with safe characters. @@ -82,22 +81,20 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) { const String base_path = resource_path.substr(0, resource_path.rfind("/")) + "/"; _zip_recursive(resource_path, base_path, zip); zipClose(zip, nullptr); - FileAccess *f = FileAccess::open(output_path, FileAccess::READ); - ERR_FAIL_COND_MSG(!f, "Unable to create ZIP file."); + Ref<FileAccess> f = FileAccess::open(output_path, FileAccess::READ); + ERR_FAIL_COND_MSG(f.is_null(), "Unable to create ZIP file."); Vector<uint8_t> buf; buf.resize(f->get_length()); f->get_buffer(buf.ptrw(), buf.size()); godot_js_os_download_buffer(buf.ptr(), buf.size(), output_name.utf8().get_data(), "application/zip"); - f->close(); - memdelete(f); // Remove the temporary file since it was sent to the user's native filesystem as a download. DirAccess::remove_file_or_error(output_path); } void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, zipFile p_zip) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { WARN_PRINT("Unable to open file for zipping: " + p_path); return; } @@ -105,8 +102,6 @@ void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, z uint64_t len = f->get_length(); data.resize(len); f->get_buffer(data.ptrw(), len); - f->close(); - memdelete(f); String path = p_path.replace_first(p_base_path, ""); zipOpenNewFileInZip(p_zip, @@ -124,7 +119,7 @@ void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, z } void JavaScriptToolsEditorPlugin::_zip_recursive(String p_path, String p_base_path, zipFile p_zip) { - DirAccessRef dir = DirAccess::open(p_path); + Ref<DirAccess> dir = DirAccess::open(p_path); if (!dir) { WARN_PRINT("Unable to open directory for zipping: " + p_path); return; diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp index ef1c170625..66d93d7c49 100644 --- a/platform/javascript/export/export_plugin.cpp +++ b/platform/javascript/export/export_plugin.cpp @@ -33,8 +33,7 @@ #include "core/config/project_settings.h" Error EditorExportPlatformJavaScript::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) { - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io); if (!pkg) { @@ -70,14 +69,13 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template //write String dst = p_dir.plus_file(file.replace("godot", p_name)); - FileAccess *f = FileAccess::open(dst, FileAccess::WRITE); - if (!f) { + Ref<FileAccess> f = FileAccess::open(dst, FileAccess::WRITE); + if (f.is_null()) { EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + dst); unzClose(pkg); return ERR_FILE_CANT_WRITE; } f->store_buffer(data.ptr(), data.size()); - memdelete(f); } while (unzGoToNextFile(pkg) == UNZ_OK); unzClose(pkg); @@ -85,13 +83,12 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template } Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, int p_size, String p_path) { - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + if (f.is_null()) { EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path); return ERR_FILE_CANT_WRITE; } f->store_buffer(p_content, p_size); - memdelete(f); return OK; } @@ -233,15 +230,13 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & const String sw_path = dir.plus_file(name + ".service.worker.js"); Vector<uint8_t> sw; { - FileAccess *f = FileAccess::open(sw_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(sw_path, FileAccess::READ); + if (f.is_null()) { EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + sw_path); return ERR_FILE_CANT_READ; } sw.resize(f->get_length()); f->get_buffer(sw.ptrw(), sw.size()); - memdelete(f); - f = nullptr; } _replace_strings(replaces, sw); Error err = _write_or_error(sw.ptr(), sw.size(), dir.plus_file(name + ".service.worker.js")); @@ -252,7 +247,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & // Custom offline page const String offline_page = p_preset->get("progressive_web_app/offline_page"); if (!offline_page.is_empty()) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); const String offline_dest = dir.plus_file(name + ".offline.html"); err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest); if (err != OK) { @@ -456,7 +451,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese } { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + 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()); error = da->copy(shared_objects[i].path, dst); @@ -475,32 +470,25 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese // Parse generated file sizes (pck and wasm, to help show a meaningful loading bar). Dictionary file_sizes; - FileAccess *f = nullptr; - f = FileAccess::open(pck_path, FileAccess::READ); - if (f) { + Ref<FileAccess> f = FileAccess::open(pck_path, FileAccess::READ); + if (f.is_valid()) { file_sizes[pck_path.get_file()] = (uint64_t)f->get_length(); - memdelete(f); - f = nullptr; } f = FileAccess::open(base_path + ".wasm", FileAccess::READ); - if (f) { + if (f.is_valid()) { file_sizes[base_name + ".wasm"] = (uint64_t)f->get_length(); - memdelete(f); - f = nullptr; } // Read the HTML shell file (custom or from template). const String html_path = custom_html.is_empty() ? base_path + ".html" : custom_html; Vector<uint8_t> html; f = FileAccess::open(html_path, FileAccess::READ); - if (!f) { + if (f.is_null()) { EditorNode::get_singleton()->show_warning(TTR("Could not read HTML shell:") + "\n" + html_path); return ERR_FILE_CANT_READ; } html.resize(f->get_length()); f->get_buffer(html.ptrw(), html.size()); - memdelete(f); - f = nullptr; // Generate HTML file with replaced strings. _fix_html(html, p_preset, base_name, p_debug, p_flags, shared_objects, file_sizes); @@ -586,7 +574,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese } const String dest = EditorPaths::get_singleton()->get_cache_dir().plus_file("web"); - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); if (!da->dir_exists(dest)) { Error err = da->make_dir_recursive(dest); if (err != OK) { diff --git a/platform/javascript/export/export_server.h b/platform/javascript/export/export_server.h index 1b908ad9b0..f77ac3d1ad 100644 --- a/platform/javascript/export/export_server.h +++ b/platform/javascript/export/export_server.h @@ -153,8 +153,8 @@ public: } const String ctype = mimes[req_ext]; - FileAccess *f = FileAccess::open(filepath, FileAccess::READ); - ERR_FAIL_COND(!f); + Ref<FileAccess> f = FileAccess::open(filepath, FileAccess::READ); + ERR_FAIL_COND(f.is_null()); String s = "HTTP/1.1 200 OK\r\n"; s += "Connection: Close\r\n"; s += "Content-Type: " + ctype + "\r\n"; @@ -166,7 +166,6 @@ public: CharString cs = s.utf8(); Error err = peer->put_data((const uint8_t *)cs.get_data(), cs.size() - 1); if (err != OK) { - memdelete(f); ERR_FAIL(); } @@ -178,11 +177,9 @@ public: } err = peer->put_data(bytes, read); if (err != OK) { - memdelete(f); ERR_FAIL(); } } - memdelete(f); } void poll() { diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp index 24906fa3fb..9f7fab6ee8 100644 --- a/platform/linuxbsd/export/export_plugin.cpp +++ b/platform/linuxbsd/export/export_plugin.cpp @@ -34,8 +34,8 @@ #include "editor/editor_node.h" Error EditorExportPlatformLinuxBSD::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { - FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V(!f, ERR_CANT_CREATE); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE); f->store_line("#!/bin/sh"); f->store_line("echo -ne '\\033c\\033]0;" + p_app_name + "\\a'"); @@ -101,8 +101,8 @@ List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<Edito Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const { // Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data - FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ_WRITE); + if (f.is_null()) { return ERR_CANT_OPEN; } @@ -110,7 +110,6 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int { uint32_t magic = f->get_32(); if (magic != 0x464c457f) { // 0x7F + "ELF" - f->close(); return ERR_FILE_CORRUPT; } } @@ -120,7 +119,6 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int int bits = f->get_8() * 32; if (bits == 32 && p_embedded_size >= 0x100000000) { - f->close(); ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB."); } @@ -165,7 +163,6 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int f->seek(string_data_pos); strings = (uint8_t *)memalloc(string_data_size); if (!strings) { - f->close(); return ERR_OUT_OF_MEMORY; } f->get_buffer(strings, string_data_size); @@ -198,7 +195,6 @@ Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int } memfree(strings); - f->close(); return found ? OK : ERR_FILE_CORRUPT; } diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index 86874687ad..62e9aaed45 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -131,20 +131,19 @@ void OS_LinuxBSD::initialize_joypads() { String OS_LinuxBSD::get_unique_id() const { static String machine_id; if (machine_id.is_empty()) { - if (FileAccess *f = FileAccess::open("/etc/machine-id", FileAccess::READ)) { + Ref<FileAccess> f = FileAccess::open("/etc/machine-id", FileAccess::READ); + if (f.is_valid()) { while (machine_id.is_empty() && !f->eof_reached()) { machine_id = f->get_line().strip_edges(); } - f->close(); - memdelete(f); } } return machine_id; } String OS_LinuxBSD::get_processor_name() const { - FileAccessRef f = FileAccess::open("/proc/cpuinfo", FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, "", String("Couldn't open `/proc/cpuinfo` to get the CPU model name. Returning an empty string.")); + Ref<FileAccess> f = FileAccess::open("/proc/cpuinfo", FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), "", String("Couldn't open `/proc/cpuinfo` to get the CPU model name. Returning an empty string.")); while (!f->eof_reached()) { const String line = f->get_line(); @@ -465,7 +464,7 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { // Create needed directories for decided trash can location. { - DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Error err = dir_access->make_dir_recursive(trash_path); // Issue an error if trash can is not created properly. @@ -512,13 +511,12 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { String trash_info = "[Trash Info]\nPath=" + path.uri_encode() + "\nDeletionDate=" + timestamp + "\n"; { Error err; - FileAccessRef file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file: \"" + trash_path + "/info/" + file_name + ".trashinfo\""); file->store_string(trash_info); - file->close(); // Rename our resource before moving it to the trash can. - DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); err = dir_access->rename(path, renamed_path); ERR_FAIL_COND_V_MSG(err != OK, err, "Can't rename file \"" + path + "\" to \"" + renamed_path + "\""); } @@ -535,7 +533,7 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { // Issue an error if "mv" failed to move the given resource to the trash can. if (err != OK || retval != 0) { ERR_PRINT("move_to_trash: Could not move the resource \"" + path + "\" to the trash can \"" + trash_path + "/files\""); - DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); err = dir_access->rename(renamed_path, path); ERR_FAIL_COND_V_MSG(err != OK, err, "Could not rename \"" + renamed_path + "\" back to its original name: \"" + path + "\""); return FAILED; diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 986c711fc9..c7381f06e3 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -2892,14 +2892,13 @@ void DisplayServerOSX::swap_buffers() { void DisplayServerOSX::set_native_icon(const String &p_filename) { _THREAD_SAFE_METHOD_ - FileAccess *f = FileAccess::open(p_filename, FileAccess::READ); - ERR_FAIL_COND(!f); + Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::READ); + ERR_FAIL_COND(f.is_null()); Vector<uint8_t> data; uint64_t len = f->get_length(); data.resize(len); f->get_buffer((uint8_t *)&data.write[0], len); - memdelete(f); NSData *icon_data = [[NSData alloc] initWithBytes:&data.write[0] length:len]; ERR_FAIL_COND_MSG(!icon_data, "Error reading icon data."); diff --git a/platform/osx/export/codesign.cpp b/platform/osx/export/codesign.cpp index dab9f3eccb..fd044c00cc 100644 --- a/platform/osx/export/codesign.cpp +++ b/platform/osx/export/codesign.cpp @@ -49,8 +49,8 @@ /*************************************************************************/ String CodeSignCodeResources::hash_sha1_base64(const String &p_path) { - FileAccessRef fa = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!fa, String(), vformat("CodeSign/CodeResources: Can't open file: \"%s\".", p_path)); + Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(fa.is_null(), String(), vformat("CodeSign/CodeResources: Can't open file: \"%s\".", p_path)); CryptoCore::SHA1Context ctx; ctx.start(); @@ -68,14 +68,13 @@ String CodeSignCodeResources::hash_sha1_base64(const String &p_path) { unsigned char hash[0x14]; ctx.finish(hash); - fa->close(); return CryptoCore::b64_encode_str(hash, 0x14); } String CodeSignCodeResources::hash_sha256_base64(const String &p_path) { - FileAccessRef fa = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!fa, String(), vformat("CodeSign/CodeResources: Can't open file: \"%s\".", p_path)); + Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(fa.is_null(), String(), vformat("CodeSign/CodeResources: Can't open file: \"%s\".", p_path)); CryptoCore::SHA256Context ctx; ctx.start(); @@ -93,7 +92,6 @@ String CodeSignCodeResources::hash_sha256_base64(const String &p_path) { unsigned char hash[0x20]; ctx.finish(hash); - fa->close(); return CryptoCore::b64_encode_str(hash, 0x20); } @@ -211,16 +209,14 @@ bool CodeSignCodeResources::add_nested_file(const String &p_root, const String & } \ } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, false); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V(da.is_null(), false); Vector<String> files_to_add; if (LipO::is_lipo(p_exepath)) { String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file("_lipo"); Error err = da->make_dir_recursive(tmp_path_name); - if (err != OK) { - ERR_FAIL_V_MSG(false, vformat("CodeSign/CodeResources: Failed to create \"%s\" subfolder.", 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++) { @@ -287,8 +283,8 @@ 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) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(!da, false); + 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)); ERR_FAIL_COND_V(err != OK, false); @@ -431,12 +427,11 @@ bool CodeSignCodeResources::save_to_file(const String &p_path) { String text = pl.save_text(); ERR_FAIL_COND_V_MSG(text.is_empty(), false, "CodeSign/CodeResources: Generating resources PList failed."); - FileAccessRef fa = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!fa, false, vformat("CodeSign/CodeResources: Can't open file: \"%s\".", p_path)); + Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("CodeSign/CodeResources: Can't open file: \"%s\".", p_path)); CharString cs = text.utf8(); fa->store_buffer((const uint8_t *)cs.ptr(), cs.length()); - fa->close(); return true; } @@ -809,8 +804,8 @@ int CodeSignRequirements::get_size() const { return blob.size(); } -void CodeSignRequirements::write_to_file(FileAccess *p_file) const { - ERR_FAIL_COND_MSG(!p_file, "CodeSign/Requirements: Invalid file handle."); +void CodeSignRequirements::write_to_file(Ref<FileAccess> p_file) const { + ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/Requirements: Invalid file handle."); p_file->store_buffer(blob.ptr(), blob.size()); } @@ -863,8 +858,8 @@ int CodeSignEntitlementsText::get_size() const { return blob.size(); } -void CodeSignEntitlementsText::write_to_file(FileAccess *p_file) const { - ERR_FAIL_COND_MSG(!p_file, "CodeSign/EntitlementsText: Invalid file handle."); +void CodeSignEntitlementsText::write_to_file(Ref<FileAccess> p_file) const { + ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/EntitlementsText: Invalid file handle."); p_file->store_buffer(blob.ptr(), blob.size()); } @@ -918,8 +913,8 @@ int CodeSignEntitlementsBinary::get_size() const { return blob.size(); } -void CodeSignEntitlementsBinary::write_to_file(FileAccess *p_file) const { - ERR_FAIL_COND_MSG(!p_file, "CodeSign/EntitlementsBinary: Invalid file handle."); +void CodeSignEntitlementsBinary::write_to_file(Ref<FileAccess> p_file) const { + ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/EntitlementsBinary: Invalid file handle."); p_file->store_buffer(blob.ptr(), blob.size()); } @@ -1040,8 +1035,8 @@ int CodeSignCodeDirectory::get_size() const { return blob.size(); } -void CodeSignCodeDirectory::write_to_file(FileAccess *p_file) const { - ERR_FAIL_COND_MSG(!p_file, "CodeSign/CodeDirectory: Invalid file handle."); +void CodeSignCodeDirectory::write_to_file(Ref<FileAccess> p_file) const { + ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/CodeDirectory: Invalid file handle."); p_file->store_buffer(blob.ptr(), blob.size()); } @@ -1086,8 +1081,8 @@ int CodeSignSignature::get_size() const { return blob.size(); } -void CodeSignSignature::write_to_file(FileAccess *p_file) const { - ERR_FAIL_COND_MSG(!p_file, "CodeSign/Signature: Invalid file handle."); +void CodeSignSignature::write_to_file(Ref<FileAccess> p_file) const { + ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/Signature: Invalid file handle."); p_file->store_buffer(blob.ptr(), blob.size()); } @@ -1115,8 +1110,8 @@ int CodeSignSuperBlob::get_size() const { return size; } -void CodeSignSuperBlob::write_to_file(FileAccess *p_file) const { - ERR_FAIL_COND_MSG(!p_file, "CodeSign/SuperBlob: Invalid file handle."); +void CodeSignSuperBlob::write_to_file(Ref<FileAccess> p_file) const { + ERR_FAIL_COND_MSG(p_file.is_null(), "CodeSign/SuperBlob: Invalid file handle."); uint32_t size = get_size(); uint32_t data_offset = 12 + blobs.size() * 8; @@ -1147,8 +1142,8 @@ void CodeSignSuperBlob::write_to_file(FileAccess *p_file) const { PackedByteArray CodeSign::file_hash_sha1(const String &p_path) { PackedByteArray file_hash; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, PackedByteArray(), vformat("CodeSign: Can't open file: \"%s\".", p_path)); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), PackedByteArray(), vformat("CodeSign: Can't open file: \"%s\".", p_path)); CryptoCore::SHA1Context ctx; ctx.start(); @@ -1171,8 +1166,8 @@ PackedByteArray CodeSign::file_hash_sha1(const String &p_path) { PackedByteArray CodeSign::file_hash_sha256(const String &p_path) { PackedByteArray file_hash; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, PackedByteArray(), vformat("CodeSign: Can't open file: \"%s\".", p_path)); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), PackedByteArray(), vformat("CodeSign: Can't open file: \"%s\".", p_path)); CryptoCore::SHA256Context ctx; ctx.start(); @@ -1208,8 +1203,8 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const String id; String main_exe = p_exe_path; - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (!da) { + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (da.is_null()) { r_error_msg = TTR("Can't get filesystem access."); ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CodeSign: Can't get filesystem access."); } @@ -1522,8 +1517,8 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const } Error CodeSign::codesign(bool p_use_hardened_runtime, bool p_force, const String &p_path, const String &p_ent_path, String &r_error_msg) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (!da) { + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + if (da.is_null()) { r_error_msg = TTR("Can't get filesystem access."); ERR_FAIL_V_MSG(ERR_CANT_CREATE, "CodeSign: Can't get filesystem access."); } diff --git a/platform/osx/export/codesign.h b/platform/osx/export/codesign.h index e5e9be5c28..3a08c0ea86 100644 --- a/platform/osx/export/codesign.h +++ b/platform/osx/export/codesign.h @@ -132,7 +132,7 @@ public: virtual int get_size() const = 0; virtual uint32_t get_index_type() const = 0; - virtual void write_to_file(FileAccess *p_file) const = 0; + virtual void write_to_file(Ref<FileAccess> p_file) const = 0; }; /*************************************************************************/ @@ -168,7 +168,7 @@ public: virtual int get_size() const override; virtual uint32_t get_index_type() const override { return 0x00000002; }; - virtual void write_to_file(FileAccess *p_file) const override; + virtual void write_to_file(Ref<FileAccess> p_file) const override; }; /*************************************************************************/ @@ -190,7 +190,7 @@ public: virtual int get_size() const override; virtual uint32_t get_index_type() const override { return 0x00000005; }; - virtual void write_to_file(FileAccess *p_file) const override; + virtual void write_to_file(Ref<FileAccess> p_file) const override; }; /*************************************************************************/ @@ -212,7 +212,7 @@ public: virtual int get_size() const override; virtual uint32_t get_index_type() const override { return 0x00000007; }; - virtual void write_to_file(FileAccess *p_file) const override; + virtual void write_to_file(Ref<FileAccess> p_file) const override; }; /*************************************************************************/ @@ -314,7 +314,7 @@ public: virtual int get_size() const override; virtual uint32_t get_index_type() const override { return 0x00000000; }; - virtual void write_to_file(FileAccess *p_file) const override; + virtual void write_to_file(Ref<FileAccess> p_file) const override; }; /*************************************************************************/ @@ -333,7 +333,7 @@ public: virtual int get_size() const override; virtual uint32_t get_index_type() const override { return 0x00010000; }; - virtual void write_to_file(FileAccess *p_file) const override; + virtual void write_to_file(Ref<FileAccess> p_file) const override; }; /*************************************************************************/ @@ -347,7 +347,7 @@ public: bool add_blob(const Ref<CodeSignBlob> &p_blob); int get_size() const; - void write_to_file(FileAccess *p_file) const; + void write_to_file(Ref<FileAccess> p_file) const; }; /*************************************************************************/ diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp index 682f722a85..580cd81583 100644 --- a/platform/osx/export/export_plugin.cpp +++ b/platform/osx/export/export_plugin.cpp @@ -256,8 +256,8 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png"); ResourceSaver::save(path, it); - FileAccess *f = FileAccess::open(path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ); + if (f.is_null()) { // Clean up generated file. DirAccess::remove_file_or_error(path); ERR_FAIL(); @@ -267,7 +267,6 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ uint64_t len = f->get_length(); data.resize(data.size() + len + 8); f->get_buffer(&data.write[ofs + 8], len); - memdelete(f); len += 8; len = BSWAP32(len); memcpy(&data.write[ofs], icon_infos[i].name, 4); @@ -565,7 +564,7 @@ Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset } Error dir_access_error; - DirAccessRef dir_access{ DirAccess::open(p_path, &dir_access_error) }; + Ref<DirAccess> dir_access{ DirAccess::open(p_path, &dir_access_error) }; if (dir_access_error != OK) { return dir_access_error; @@ -603,7 +602,7 @@ Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset return OK; } -Error EditorExportPlatformOSX::_copy_and_sign_files(DirAccessRef &dir_access, const String &p_src_path, +Error EditorExportPlatformOSX::_copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path, const String &p_in_app_path, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path, bool p_should_error_on_non_code_sign) { @@ -633,7 +632,7 @@ Error EditorExportPlatformOSX::_copy_and_sign_files(DirAccessRef &dir_access, co } Error EditorExportPlatformOSX::_export_osx_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, - const String &p_app_path_name, DirAccessRef &dir_access, + const String &p_app_path_name, Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path) { Error error{ OK }; @@ -683,8 +682,8 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin } Error EditorExportPlatformOSX::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { - FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V(!f, ERR_CANT_CREATE); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE); f->store_line("#!/bin/sh"); f->store_line("echo -ne '\\033c\\033]0;" + p_app_name + "\\a'"); @@ -721,8 +720,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p return ERR_FILE_BAD_PATH; } - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); if (ep.step(TTR("Creating app bundle"), 0)) { return ERR_SKIP; @@ -778,8 +776,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p Error err = OK; - DirAccessRef tmp_app_dir = DirAccess::create_for_path(tmp_base_path_name); - if (!tmp_app_dir) { + Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_base_path_name); + if (tmp_app_dir.is_null()) { err = ERR_CANT_CREATE; } @@ -832,7 +830,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p { String fname = tmp_app_path_name + "/Contents/Resources/en.lproj"; tmp_app_dir->make_dir_recursive(fname); - FileAccessRef f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); f->store_line("/* Localized versions of Info.plist keys */"); f->store_line(""); f->store_line("CFBundleDisplayName = \"" + ProjectSettings::get_singleton()->get("application/config/name").operator String() + "\";"); @@ -878,7 +876,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p String lang = tr->get_locale(); String fname = tmp_app_path_name + "/Contents/Resources/" + lang + ".lproj"; tmp_app_dir->make_dir_recursive(fname); - FileAccessRef f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); f->store_line("/* Localized versions of Info.plist keys */"); f->store_line(""); if (appnames.has(lang)) { @@ -996,12 +994,10 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (!iconpath.is_empty()) { if (iconpath.get_extension() == "icns") { - FileAccess *icon = FileAccess::open(iconpath, FileAccess::READ); - if (icon) { + Ref<FileAccess> icon = FileAccess::open(iconpath, FileAccess::READ); + if (icon.is_valid()) { data.resize(icon->get_length()); icon->get_buffer(&data.write[0], icon->get_length()); - icon->close(); - memdelete(icon); } } else { Ref<Image> icon; @@ -1042,15 +1038,13 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = tmp_app_dir->make_dir_recursive(file.get_base_dir()); } if (err == OK) { - FileAccess *f = FileAccess::open(file, FileAccess::WRITE); - if (f) { + Ref<FileAccess> f = FileAccess::open(file, FileAccess::WRITE); + if (f.is_valid()) { f->store_buffer(data.ptr(), data.size()); - f->close(); if (is_execute) { // chmod with 0755 if the file is executable. FileAccess::set_unix_permissions(file, 0755); } - memdelete(f); } else { err = ERR_CANT_CREATE; } @@ -1094,8 +1088,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p if (sign_enabled && (ent_path.is_empty())) { ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements"); - FileAccess *ent_f = FileAccess::open(ent_path, FileAccess::WRITE); - if (ent_f) { + Ref<FileAccess> ent_f = FileAccess::open(ent_path, FileAccess::WRITE); + if (ent_f.is_valid()) { ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"); ent_f->store_line("<plist version=\"1.0\">"); @@ -1216,16 +1210,13 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p ent_f->store_line("</dict>"); ent_f->store_line("</plist>"); - - ent_f->close(); - memdelete(ent_f); } else { err = ERR_CANT_CREATE; } if ((err == OK) && helpers.size() > 0) { ent_f = FileAccess::open(hlp_ent_path, FileAccess::WRITE); - if (ent_f) { + if (ent_f.is_valid()) { ent_f->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"); ent_f->store_line("<plist version=\"1.0\">"); @@ -1236,9 +1227,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p ent_f->store_line("<true/>"); ent_f->store_line("</dict>"); ent_f->store_line("</plist>"); - - ent_f->close(); - memdelete(ent_f); } else { err = ERR_CANT_CREATE; } @@ -1246,7 +1234,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } if ((err == OK) && helpers.size() > 0) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < helpers.size(); i++) { String hlp_path = helpers[i]; err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file()); @@ -1273,7 +1261,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } if (err == OK) { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < shared_objects.size(); i++) { String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path); if (shared_objects[i].target.is_empty()) { @@ -1337,8 +1325,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p OS::get_singleton()->move_to_trash(p_path); } - FileAccess *dst_f = nullptr; - zlib_filefunc_def io_dst = zipio_create_io_from_file(&dst_f); + zlib_filefunc_def io_dst = zipio_create_io(); zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst); _zip_folder_recursive(zip, tmp_base_path_name, "", pkg_name); @@ -1383,7 +1370,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p void EditorExportPlatformOSX::_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); - DirAccessRef da = DirAccess::open(dir); + Ref<DirAccess> da = DirAccess::open(dir); da->list_dir_begin(); String f = da->get_next(); while (!f.is_empty()) { @@ -1474,8 +1461,8 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions 0); - FileAccessRef fa = FileAccess::open(dir.plus_file(f), FileAccess::READ); - if (!fa) { + Ref<FileAccess> fa = FileAccess::open(dir.plus_file(f), FileAccess::READ); + if (fa.is_null()) { ERR_FAIL_MSG(vformat("Can't open file to read from path \"%s\".", dir.plus_file(f))); } const int bufsize = 16384; diff --git a/platform/osx/export/export_plugin.h b/platform/osx/export/export_plugin.h index b3edfb7f90..013e5eaa71 100644 --- a/platform/osx/export/export_plugin.h +++ b/platform/osx/export/export_plugin.h @@ -58,11 +58,11 @@ class EditorExportPlatformOSX : public EditorExportPlatform { Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path); Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true); Error _code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_should_error_on_non_code = true); - Error _copy_and_sign_files(DirAccessRef &dir_access, const String &p_src_path, const String &p_in_app_path, + Error _copy_and_sign_files(Ref<DirAccess> &dir_access, const String &p_src_path, const String &p_in_app_path, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path, bool p_should_error_on_non_code_sign); Error _export_osx_plugins_for(Ref<EditorExportPlugin> p_editor_export_plugin, const String &p_app_path_name, - DirAccessRef &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, + Ref<DirAccess> &dir_access, bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path); Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name); void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name); diff --git a/platform/osx/export/lipo.cpp b/platform/osx/export/lipo.cpp index 66d2ecdbcf..82baf18c52 100644 --- a/platform/osx/export/lipo.cpp +++ b/platform/osx/export/lipo.cpp @@ -35,8 +35,8 @@ #ifdef MODULE_REGEX_ENABLED bool LipO::is_lipo(const String &p_path) { - FileAccessRef fb = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!fb, false, vformat("LipO: Can't open file: \"%s\".", p_path)); + Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path)); uint32_t magic = fb->get_32(); return (magic == 0xbebafeca || magic == 0xcafebabe || magic == 0xbfbafeca || magic == 0xcafebabf); } @@ -45,7 +45,7 @@ bool LipO::create_file(const String &p_output_path, const PackedStringArray &p_f close(); fa = FileAccess::open(p_output_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!fa, false, vformat("LipO: Can't open file: \"%s\".", p_output_path)); + ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_output_path)); uint64_t max_size = 0; for (int i = 0; i < p_files.size(); i++) { @@ -64,8 +64,8 @@ bool LipO::create_file(const String &p_output_path, const PackedStringArray &p_f archs.push_back(arch); - FileAccessRef fb = FileAccess::open(p_files[i], FileAccess::READ); - if (!fb) { + Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ); + if (fb.is_null()) { close(); ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s.\"", p_files[i])); } @@ -101,8 +101,8 @@ bool LipO::create_file(const String &p_output_path, const PackedStringArray &p_f // Write files and padding. for (int i = 0; i < archs.size(); i++) { - FileAccessRef fb = FileAccess::open(p_files[i], FileAccess::READ); - if (!fb) { + Ref<FileAccess> fb = FileAccess::open(p_files[i], FileAccess::READ); + if (fb.is_null()) { close(); ERR_FAIL_V_MSG(false, vformat("LipO: Can't open file: \"%s.\"", p_files[i])); } @@ -123,7 +123,6 @@ bool LipO::create_file(const String &p_output_path, const PackedStringArray &p_f if (br > 0) { fa->store_buffer(step, br); } - fb->close(); } return true; } @@ -132,7 +131,7 @@ bool LipO::open_file(const String &p_path) { close(); fa = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!fa, false, vformat("LipO: Can't open file: \"%s\".", p_path)); + ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path)); uint32_t magic = fa->get_32(); if (magic == 0xbebafeca) { @@ -197,16 +196,16 @@ bool LipO::open_file(const String &p_path) { } int LipO::get_arch_count() const { - ERR_FAIL_COND_V_MSG(!fa, 0, "LipO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "LipO: File not opened."); return archs.size(); } bool LipO::extract_arch(int p_index, const String &p_path) { - ERR_FAIL_COND_V_MSG(!fa, false, "LipO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), false, "LipO: File not opened."); ERR_FAIL_INDEX_V(p_index, archs.size(), false); - FileAccessRef fb = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V_MSG(!fb, false, vformat("LipO: Can't open file: \"%s\".", p_path)); + Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("LipO: Can't open file: \"%s\".", p_path)); fa->seek(archs[p_index].offset); @@ -223,16 +222,10 @@ bool LipO::extract_arch(int p_index, const String &p_path) { if (br > 0) { fb->store_buffer(step, br); } - fb->close(); return true; } void LipO::close() { - if (fa) { - fa->close(); - memdelete(fa); - fa = nullptr; - } archs.clear(); } diff --git a/platform/osx/export/lipo.h b/platform/osx/export/lipo.h index 68bbe42dd6..0e419be17e 100644 --- a/platform/osx/export/lipo.h +++ b/platform/osx/export/lipo.h @@ -50,7 +50,7 @@ class LipO : public RefCounted { uint32_t align; }; - FileAccess *fa = nullptr; + Ref<FileAccess> fa; Vector<FatArch> archs; static inline size_t PAD(size_t s, size_t a) { diff --git a/platform/osx/export/macho.cpp b/platform/osx/export/macho.cpp index 08f2a855b0..e6e67eff06 100644 --- a/platform/osx/export/macho.cpp +++ b/platform/osx/export/macho.cpp @@ -49,7 +49,7 @@ uint32_t MachO::seg_align(uint64_t p_vmaddr, uint32_t p_min, uint32_t p_max) { } bool MachO::alloc_signature(uint64_t p_size) { - ERR_FAIL_COND_V_MSG(!fa, false, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened."); if (signature_offset != 0) { // Nothing to do, already have signature load command. return true; @@ -103,15 +103,15 @@ bool MachO::alloc_signature(uint64_t p_size) { } bool MachO::is_macho(const String &p_path) { - FileAccessRef fb = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!fb, false, vformat("MachO: Can't open file: \"%s\".", p_path)); + Ref<FileAccess> fb = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(fb.is_null(), false, vformat("MachO: Can't open file: \"%s\".", p_path)); uint32_t magic = fb->get_32(); return (magic == 0xcefaedfe || magic == 0xfeedface || magic == 0xcffaedfe || magic == 0xfeedfacf); } bool MachO::open_file(const String &p_path) { fa = FileAccess::open(p_path, FileAccess::READ_WRITE); - ERR_FAIL_COND_V_MSG(!fa, false, vformat("MachO: Can't open file: \"%s\".", p_path)); + ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("MachO: Can't open file: \"%s\".", p_path)); uint32_t magic = fa->get_32(); MachHeader mach_header; @@ -232,37 +232,37 @@ bool MachO::open_file(const String &p_path) { } uint64_t MachO::get_exe_base() { - ERR_FAIL_COND_V_MSG(!fa, 0, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); return exe_base; } uint64_t MachO::get_exe_limit() { - ERR_FAIL_COND_V_MSG(!fa, 0, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); return exe_limit; } int32_t MachO::get_align() { - ERR_FAIL_COND_V_MSG(!fa, 0, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); return align; } uint32_t MachO::get_cputype() { - ERR_FAIL_COND_V_MSG(!fa, 0, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); return cputype; } uint32_t MachO::get_cpusubtype() { - ERR_FAIL_COND_V_MSG(!fa, 0, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); return cpusubtype; } uint64_t MachO::get_size() { - ERR_FAIL_COND_V_MSG(!fa, 0, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); return fa->get_length(); } uint64_t MachO::get_signature_offset() { - ERR_FAIL_COND_V_MSG(!fa, 0, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); ERR_FAIL_COND_V_MSG(signature_offset == 0, 0, "MachO: No signature load command."); fa->seek(signature_offset + 8); @@ -274,7 +274,7 @@ uint64_t MachO::get_signature_offset() { } uint64_t MachO::get_code_limit() { - ERR_FAIL_COND_V_MSG(!fa, 0, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); if (signature_offset == 0) { return fa->get_length() + PAD(fa->get_length(), 16); @@ -284,7 +284,7 @@ uint64_t MachO::get_code_limit() { } uint64_t MachO::get_signature_size() { - ERR_FAIL_COND_V_MSG(!fa, 0, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "MachO: File not opened."); ERR_FAIL_COND_V_MSG(signature_offset == 0, 0, "MachO: No signature load command."); fa->seek(signature_offset + 12); @@ -296,7 +296,7 @@ uint64_t MachO::get_signature_size() { } bool MachO::is_signed() { - ERR_FAIL_COND_V_MSG(!fa, false, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened."); if (signature_offset == 0) { return false; } @@ -325,7 +325,7 @@ bool MachO::is_signed() { } PackedByteArray MachO::get_cdhash_sha1() { - ERR_FAIL_COND_V_MSG(!fa, PackedByteArray(), "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened."); if (signature_offset == 0) { return PackedByteArray(); } @@ -372,7 +372,7 @@ PackedByteArray MachO::get_cdhash_sha1() { } PackedByteArray MachO::get_cdhash_sha256() { - ERR_FAIL_COND_V_MSG(!fa, PackedByteArray(), "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened."); if (signature_offset == 0) { return PackedByteArray(); } @@ -419,7 +419,7 @@ PackedByteArray MachO::get_cdhash_sha256() { } PackedByteArray MachO::get_requirements() { - ERR_FAIL_COND_V_MSG(!fa, PackedByteArray(), "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "MachO: File not opened."); if (signature_offset == 0) { return PackedByteArray(); } @@ -451,16 +451,16 @@ PackedByteArray MachO::get_requirements() { return PackedByteArray(); } -const FileAccess *MachO::get_file() const { +const Ref<FileAccess> MachO::get_file() const { return fa; } -FileAccess *MachO::get_file() { +Ref<FileAccess> MachO::get_file() { return fa; } bool MachO::set_signature_size(uint64_t p_size) { - ERR_FAIL_COND_V_MSG(!fa, false, "MachO: File not opened."); + ERR_FAIL_COND_V_MSG(fa.is_null(), false, "MachO: File not opened."); // Ensure signature load command exists. ERR_FAIL_COND_V_MSG(link_edit_offset == 0, false, "MachO: No __LINKEDIT segment found."); @@ -545,12 +545,4 @@ bool MachO::set_signature_size(uint64_t p_size) { return true; } -MachO::~MachO() { - if (fa) { - fa->close(); - memdelete(fa); - fa = nullptr; - } -} - #endif // MODULE_REGEX_ENABLED diff --git a/platform/osx/export/macho.h b/platform/osx/export/macho.h index e09906898b..6cfc3c44f5 100644 --- a/platform/osx/export/macho.h +++ b/platform/osx/export/macho.h @@ -161,7 +161,7 @@ class MachO : public RefCounted { uint32_t reserved3; }; - FileAccess *fa = nullptr; + Ref<FileAccess> fa; bool swap = false; uint64_t lc_limit = 0; @@ -203,13 +203,11 @@ public: PackedByteArray get_requirements(); - const FileAccess *get_file() const; - FileAccess *get_file(); + const Ref<FileAccess> get_file() const; + Ref<FileAccess> get_file(); uint64_t get_signature_size(); bool set_signature_size(uint64_t p_size); - - ~MachO(); }; #endif // MODULE_REGEX_ENABLED diff --git a/platform/osx/export/plist.cpp b/platform/osx/export/plist.cpp index 3580ad877d..d089233b80 100644 --- a/platform/osx/export/plist.cpp +++ b/platform/osx/export/plist.cpp @@ -343,8 +343,8 @@ PList::PList(const String &p_string) { bool PList::load_file(const String &p_filename) { root = Ref<PListNode>(); - FileAccessRef fb = FileAccess::open(p_filename, FileAccess::READ); - if (!fb) { + Ref<FileAccess> fb = FileAccess::open(p_filename, FileAccess::READ); + if (fb.is_null()) { return false; } diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index afbd338832..33fee01c08 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -47,7 +47,7 @@ _FORCE_INLINE_ String OS_OSX::get_framework_executable(const String &p_path) { // Append framework executable name, or return as is if p_path is not a framework. - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + 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()); } else { diff --git a/platform/uwp/export/app_packager.cpp b/platform/uwp/export/app_packager.cpp index e5a1e951e4..8d09a16653 100644 --- a/platform/uwp/export/app_packager.cpp +++ b/platform/uwp/export/app_packager.cpp @@ -46,7 +46,7 @@ String AppxPackager::hash_block(const uint8_t *p_block_data, size_t p_block_len) } void AppxPackager::make_block_map(const String &p_path) { - FileAccess *tmp_file = FileAccess::open(p_path, FileAccess::WRITE); + Ref<FileAccess> tmp_file = FileAccess::open(p_path, FileAccess::WRITE); tmp_file->store_string("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"); tmp_file->store_string("<BlockMap xmlns=\"http://schemas.microsoft.com/appx/2010/blockmap\" HashMethod=\"http://www.w3.org/2001/04/xmlenc#sha256\">"); @@ -69,9 +69,6 @@ void AppxPackager::make_block_map(const String &p_path) { } tmp_file->store_string("</BlockMap>"); - - tmp_file->close(); - memdelete(tmp_file); } String AppxPackager::content_type(String p_extension) { @@ -89,7 +86,7 @@ String AppxPackager::content_type(String p_extension) { } void AppxPackager::make_content_types(const String &p_path) { - FileAccess *tmp_file = FileAccess::open(p_path, FileAccess::WRITE); + Ref<FileAccess> tmp_file = FileAccess::open(p_path, FileAccess::WRITE); tmp_file->store_string("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); tmp_file->store_string("<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">"); @@ -118,9 +115,6 @@ void AppxPackager::make_content_types(const String &p_path) { tmp_file->store_string("<Override PartName=\"/AppxMetadata/CodeIntegrity.cat\" ContentType=\"application/vnd.ms-pkiseccat\" />"); tmp_file->store_string("</Types>"); - - tmp_file->close(); - memdelete(tmp_file); } Vector<uint8_t> AppxPackager::make_file_header(FileMeta p_file_meta) { @@ -285,7 +279,7 @@ Vector<uint8_t> AppxPackager::make_end_of_central_record() { return buf; } -void AppxPackager::init(FileAccess *p_fa) { +void AppxPackager::init(Ref<FileAccess> p_fa) { package = p_fa; central_dir_offset = 0; end_of_central_dir_offset = 0; @@ -308,7 +302,6 @@ Error AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t // Data for compression z_stream strm; - FileAccess *strm_f = nullptr; Vector<uint8_t> strm_in; strm_in.resize(BLOCK_SIZE); Vector<uint8_t> strm_out; @@ -316,7 +309,7 @@ Error AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t if (p_compress) { strm.zalloc = zipio_alloc; strm.zfree = zipio_free; - strm.opaque = &strm_f; + strm.opaque = Z_NULL; strm_out.resize(BLOCK_SIZE + 8); @@ -418,16 +411,15 @@ void AppxPackager::finish() { const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml"); make_block_map(tmp_blockmap_file_path); - FileAccess *blockmap_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::READ); - Vector<uint8_t> blockmap_buffer; - blockmap_buffer.resize(blockmap_file->get_length()); - - blockmap_file->get_buffer(blockmap_buffer.ptrw(), blockmap_buffer.size()); + { + Ref<FileAccess> blockmap_file = FileAccess::open(tmp_blockmap_file_path, FileAccess::READ); + Vector<uint8_t> blockmap_buffer; + blockmap_buffer.resize(blockmap_file->get_length()); - add_file("AppxBlockMap.xml", blockmap_buffer.ptr(), blockmap_buffer.size(), -1, -1, true); + blockmap_file->get_buffer(blockmap_buffer.ptrw(), blockmap_buffer.size()); - blockmap_file->close(); - memdelete(blockmap_file); + add_file("AppxBlockMap.xml", blockmap_buffer.ptr(), blockmap_buffer.size(), -1, -1, true); + } // Add content types @@ -436,16 +428,15 @@ void AppxPackager::finish() { const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml"); make_content_types(tmp_content_types_file_path); - FileAccess *types_file = FileAccess::open(tmp_content_types_file_path, FileAccess::READ); - Vector<uint8_t> types_buffer; - types_buffer.resize(types_file->get_length()); - - types_file->get_buffer(types_buffer.ptrw(), types_buffer.size()); + { + Ref<FileAccess> types_file = FileAccess::open(tmp_content_types_file_path, FileAccess::READ); + Vector<uint8_t> types_buffer; + types_buffer.resize(types_file->get_length()); - add_file("[Content_Types].xml", types_buffer.ptr(), types_buffer.size(), -1, -1, true); + types_file->get_buffer(types_buffer.ptrw(), types_buffer.size()); - types_file->close(); - memdelete(types_file); + add_file("[Content_Types].xml", types_buffer.ptr(), types_buffer.size(), -1, -1, true); + } // Cleanup generated files. DirAccess::remove_file_or_error(tmp_blockmap_file_path); @@ -466,9 +457,7 @@ void AppxPackager::finish() { Vector<uint8_t> end_record = make_end_of_central_record(); package->store_buffer(end_record.ptr(), end_record.size()); - package->close(); - memdelete(package); - package = nullptr; + package = Ref<FileAccess>(); } AppxPackager::AppxPackager() {} diff --git a/platform/uwp/export/app_packager.h b/platform/uwp/export/app_packager.h index da118449c7..a32b78bf04 100644 --- a/platform/uwp/export/app_packager.h +++ b/platform/uwp/export/app_packager.h @@ -87,7 +87,7 @@ class AppxPackager { }; String progress_task; - FileAccess *package = nullptr; + Ref<FileAccess> package; Set<String> mime_types; @@ -138,7 +138,7 @@ class AppxPackager { public: void set_progress_task(String p_task) { progress_task = p_task; } - void init(FileAccess *p_fa); + void init(Ref<FileAccess> p_fa); Error add_file(String p_file_name, const uint8_t *p_buffer, size_t p_len, int p_file_no, int p_total_files, bool p_compress = false); void finish(); diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp index 375e860f5a..7e06bf01e3 100644 --- a/platform/uwp/export/export_plugin.cpp +++ b/platform/uwp/export/export_plugin.cpp @@ -295,14 +295,13 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p Error err = OK; - FileAccess *fa_pack = FileAccess::open(p_path, FileAccess::WRITE, &err); + Ref<FileAccess> fa_pack = FileAccess::open(p_path, FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); AppxPackager packager; packager.init(fa_pack); - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); + zlib_filefunc_def io = zipio_create_io(); if (ep.step("Creating package...", 0)) { return ERR_SKIP; diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h index e2a4314ef5..7f10b00dc1 100644 --- a/platform/uwp/export/export_plugin.h +++ b/platform/uwp/export/export_plugin.h @@ -346,7 +346,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform { ERR_FAIL_V_MSG(data, err_string); } - FileAccess *f = FileAccess::open(tmp_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(tmp_path, FileAccess::READ, &err); if (err != OK) { String err_string = "Couldn't open temp logo file."; @@ -359,8 +359,6 @@ class EditorExportPlatformUWP : public EditorExportPlatform { data.resize(f->get_length()); f->get_buffer(data.ptrw(), data.size()); - f->close(); - memdelete(f); DirAccess::remove_file_or_error(tmp_path); return data; diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index a8acffb0db..736dc7d383 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1765,8 +1765,8 @@ void DisplayServerWindows::swap_buffers() { void DisplayServerWindows::set_native_icon(const String &p_filename) { _THREAD_SAFE_METHOD_ - FileAccess *f = FileAccess::open(p_filename, FileAccess::READ); - ERR_FAIL_COND_MSG(!f, "Cannot open file with icon '" + p_filename + "'."); + Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::READ); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file with icon '" + p_filename + "'."); ICONDIR *icon_dir = (ICONDIR *)memalloc(sizeof(ICONDIR)); int pos = 0; @@ -1852,7 +1852,6 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) { err = GetLastError(); ERR_FAIL_COND_MSG(err, "Error setting ICON_BIG: " + format_error_message(err) + "."); - memdelete(f); memdelete(icon_dir); } diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index e627253739..917a0af90b 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -42,8 +42,8 @@ Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPres } Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) { - FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V(!f, ERR_CANT_CREATE); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE); + ERR_FAIL_COND_V(f.is_null(), ERR_CANT_CREATE); f->store_line("@echo off"); f->store_line("title \"" + p_app_name + "\""); @@ -359,7 +359,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p } #ifndef WINDOWS_ENABLED - DirAccessRef tmp_dir = DirAccess::create_for_path(p_path.get_base_dir()); + Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir()); err = tmp_dir->remove(p_path); ERR_FAIL_COND_V(err != OK, err); @@ -417,8 +417,8 @@ bool EditorExportPlatformWindows::can_export(const Ref<EditorExportPreset> &p_pr Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const { // Patch the header of the "pck" section in the PE file so that it corresponds to the embedded data - FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ_WRITE); + if (f.is_null()) { return ERR_CANT_OPEN; } @@ -430,7 +430,6 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6 f->seek(pe_pos); uint32_t magic = f->get_32(); if (magic != 0x00004550) { - f->close(); return ERR_FILE_CORRUPT; } } @@ -480,7 +479,5 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6 } } - f->close(); - return found ? OK : ERR_FILE_CORRUPT; } diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 191a04b6a0..3461caf638 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -1101,7 +1101,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa //#define DEBUG_SIMPLICES_AS_OBJ_FILE #ifdef DEBUG_SIMPLICES_AS_OBJ_FILE { - FileAccessRef f = FileAccess::open("res://bsp.obj", FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open("res://bsp.obj", FileAccess::WRITE); for (uint32_t i = 0; i < bsp_simplices.size(); i++) { f->store_line("o Simplex" + itos(i)); for (int j = 0; j < 4; j++) { @@ -1118,7 +1118,6 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa f->store_line(vformat("f %d %d %d", 4 * i + face_order[j][0], 4 * i + face_order[j][1], 4 * i + face_order[j][2])); } } - f->close(); } #endif @@ -1150,7 +1149,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } //#define DEBUG_BSP_TREE #ifdef DEBUG_BSP_TREE - FileAccessRef f = FileAccess::open("res://bsp.txt", FileAccess::WRITE); + Ref<FileAccess> f = FileAccess::open("res://bsp.txt", FileAccess::WRITE); for (uint32_t i = 0; i < bsp_nodes.size(); i++) { f->store_line(itos(i) + " - plane: " + bsp_nodes[i].plane + " over: " + itos(bsp_nodes[i].over) + " under: " + itos(bsp_nodes[i].under)); } diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 1ab2e2419e..6949e3681c 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -83,8 +83,31 @@ bool AnimationPlayer::_set(const StringName &p_name, const Variant &p_value) { set_current_animation(p_value); } else if (name.begins_with("anims/")) { + // Backwards compatibility with 3.x, add them to "default" library. String which = name.get_slicec('/', 1); - add_animation(which, p_value); + + Ref<Animation> anim = p_value; + Ref<AnimationLibrary> al; + if (!has_animation_library(StringName())) { + al.instantiate(); + add_animation_library(StringName(), al); + } else { + al = get_animation_library(StringName()); + } + al->add_animation(which, anim); + + } else if (name.begins_with("libraries")) { + Dictionary d = p_value; + while (animation_libraries.size()) { + remove_animation_library(animation_libraries[0].name); + } + List<Variant> keys; + d.get_key_list(&keys); + for (const Variant &K : keys) { + StringName lib_name = K; + Ref<AnimationLibrary> lib = d[lib_name]; + add_animation_library(lib_name, lib); + } } else if (name.begins_with("next/")) { String which = name.get_slicec('/', 1); @@ -117,9 +140,13 @@ bool AnimationPlayer::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_current_animation(); - } else if (name.begins_with("anims/")) { - String which = name.get_slicec('/', 1); - r_ret = get_animation(which); + } else if (name.begins_with("libraries")) { + Dictionary d; + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + d[animation_libraries[i].name] = animation_libraries[i].library; + } + + r_ret = d; } else if (name.begins_with("next/")) { String which = name.get_slicec('/', 1); @@ -173,8 +200,9 @@ void AnimationPlayer::_validate_property(PropertyInfo &property) const { void AnimationPlayer::_get_property_list(List<PropertyInfo> *p_list) const { List<PropertyInfo> anim_names; + anim_names.push_back(PropertyInfo(Variant::DICTIONARY, "libraries")); + for (const KeyValue<StringName, AnimationData> &E : animation_set) { - anim_names.push_back(PropertyInfo(Variant::OBJECT, "anims/" + String(E.key), PROPERTY_HINT_RESOURCE_TYPE, "Animation", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); if (E.value.next != StringName()) { anim_names.push_back(PropertyInfo(Variant::STRING, "next/" + String(E.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); } @@ -1155,71 +1183,106 @@ void AnimationPlayer::_animation_process(double p_delta) { } } -Error AnimationPlayer::add_animation(const StringName &p_name, const Ref<Animation> &p_animation) { -#ifdef DEBUG_ENABLED - ERR_FAIL_COND_V_MSG(String(p_name).contains("/") || String(p_name).contains(":") || String(p_name).contains(",") || String(p_name).contains("["), ERR_INVALID_PARAMETER, "Invalid animation name: " + String(p_name) + "."); -#endif +void AnimationPlayer::_animation_set_cache_update() { + // Relatively fast function to update all animations. - ERR_FAIL_COND_V(p_animation.is_null(), ERR_INVALID_PARAMETER); + animation_set_update_pass++; + bool clear_cache_needed = false; - if (animation_set.has(p_name)) { - _unref_anim(animation_set[p_name].animation); - animation_set[p_name].animation = p_animation; - clear_caches(); - } else { - AnimationData ad; - ad.animation = p_animation; - ad.name = p_name; - animation_set[p_name] = ad; - } + // Update changed and add otherwise + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) { + StringName key = animation_libraries[i].name == StringName() ? K.key : StringName(String(animation_libraries[i].name) + "/" + String(K.key)); + if (!animation_set.has(key)) { + AnimationData ad; + ad.animation = K.value; + ad.animation_library = animation_libraries[i].name; + ad.name = key; + ad.last_update = animation_set_update_pass; + animation_set.insert(ad.name, ad); + } else { + AnimationData &ad = animation_set[key]; + if (ad.last_update != animation_set_update_pass) { + // Was not updated, update. If the animation is duplicated, the second one will be ignored. + if (ad.animation != K.value || ad.animation_library != animation_libraries[i].name) { + // Animation changed, update and clear caches. + clear_cache_needed = true; + ad.animation = K.value; + ad.animation_library = animation_libraries[i].name; + } - _ref_anim(p_animation); - notify_property_list_changed(); - return OK; -} + ad.last_update = animation_set_update_pass; + } + } + } + } -void AnimationPlayer::remove_animation(const StringName &p_name) { - ERR_FAIL_COND(!animation_set.has(p_name)); + // Check removed + List<StringName> to_erase; + for (const KeyValue<StringName, AnimationData> &E : animation_set) { + if (E.value.last_update != animation_set_update_pass) { + // Was not updated, must be erased + to_erase.push_back(E.key); + clear_cache_needed = true; + } + } - stop(); - _unref_anim(animation_set[p_name].animation); - animation_set.erase(p_name); + while (to_erase.size()) { + animation_set.erase(to_erase.front()->get()); + to_erase.pop_front(); + } - clear_caches(); - notify_property_list_changed(); + if (clear_cache_needed) { + // If something was modified or removed, caches need to be cleared + clear_caches(); + } } -void AnimationPlayer::_ref_anim(const Ref<Animation> &p_anim) { - Ref<Animation>(p_anim)->connect(SceneStringNames::get_singleton()->tracks_changed, callable_mp(this, &AnimationPlayer::_animation_changed), varray(), CONNECT_REFERENCE_COUNTED); -} +void AnimationPlayer::_animation_added(const StringName &p_name, const StringName &p_library) { + _animation_set_cache_update(); -void AnimationPlayer::_unref_anim(const Ref<Animation> &p_anim) { - Ref<Animation>(p_anim)->disconnect(SceneStringNames::get_singleton()->tracks_changed, callable_mp(this, &AnimationPlayer::_animation_changed)); + update_configuration_warnings(); } -void AnimationPlayer::rename_animation(const StringName &p_name, const StringName &p_new_name) { - ERR_FAIL_COND(!animation_set.has(p_name)); - ERR_FAIL_COND(String(p_new_name).contains("/") || String(p_new_name).contains(":")); - ERR_FAIL_COND(animation_set.has(p_new_name)); +void AnimationPlayer::_animation_removed(const StringName &p_name, const StringName &p_library) { + StringName name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name)); - stop(); - AnimationData ad = animation_set[p_name]; - ad.name = p_new_name; - animation_set.erase(p_name); - animation_set[p_new_name] = ad; + if (!animation_set.has(name)) { + return; // No need to update because not the one from the library being used. + } + _animation_set_cache_update(); + + // Erase blends if needed + List<BlendKey> to_erase; + for (const KeyValue<BlendKey, float> &E : blend_times) { + BlendKey bk = E.key; + if (bk.from == name || bk.to == name) { + to_erase.push_back(bk); + } + } + + while (to_erase.size()) { + blend_times.erase(to_erase.front()->get()); + to_erase.pop_front(); + } + + update_configuration_warnings(); +} +void AnimationPlayer::_rename_animation(const StringName &p_from_name, const StringName &p_to_name) { + // Rename autoplay or blends if needed. List<BlendKey> to_erase; Map<BlendKey, float> to_insert; for (const KeyValue<BlendKey, float> &E : blend_times) { BlendKey bk = E.key; BlendKey new_bk = bk; bool erase = false; - if (bk.from == p_name) { - new_bk.from = p_new_name; + if (bk.from == p_from_name) { + new_bk.from = p_to_name; erase = true; } - if (bk.to == p_name) { - new_bk.to = p_new_name; + if (bk.to == p_from_name) { + new_bk.to = p_to_name; erase = true; } @@ -1239,12 +1302,184 @@ void AnimationPlayer::rename_animation(const StringName &p_name, const StringNam to_insert.erase(to_insert.front()); } - if (autoplay == p_name) { - autoplay = p_new_name; + if (autoplay == p_from_name) { + autoplay = p_to_name; } +} + +void AnimationPlayer::_animation_renamed(const StringName &p_name, const StringName &p_to_name, const StringName &p_library) { + StringName from_name = p_library == StringName() ? p_name : StringName(String(p_library) + "/" + String(p_name)); + StringName to_name = p_library == StringName() ? p_to_name : StringName(String(p_library) + "/" + String(p_to_name)); + + if (!animation_set.has(from_name)) { + return; // No need to update because not the one from the library being used. + } + _animation_set_cache_update(); + + _rename_animation(from_name, to_name); + update_configuration_warnings(); +} + +Error AnimationPlayer::add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library) { + ERR_FAIL_COND_V(p_animation_library.is_null(), ERR_INVALID_PARAMETER); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_V_MSG(String(p_name).contains("/") || String(p_name).contains(":") || String(p_name).contains(",") || String(p_name).contains("["), ERR_INVALID_PARAMETER, "Invalid animation name: " + String(p_name) + "."); +#endif + + int insert_pos = 0; + + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + ERR_FAIL_COND_V_MSG(animation_libraries[i].name == p_name, ERR_ALREADY_EXISTS, "Can't add animation library twice with name: " + String(p_name)); + ERR_FAIL_COND_V_MSG(animation_libraries[i].library == p_animation_library, ERR_ALREADY_EXISTS, "Can't add animation library twice (adding as '" + p_name.operator String() + "', exists as '" + animation_libraries[i].name.operator String() + "'."); + + if (animation_libraries[i].name.operator String() >= p_name.operator String()) { + break; + } + + insert_pos++; + } + + AnimationLibraryData ald; + ald.name = p_name; + ald.library = p_animation_library; + + animation_libraries.insert(insert_pos, ald); + + ald.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added), varray(p_name)); + ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added), varray(p_name)); + ald.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed), varray(p_name)); + + _animation_set_cache_update(); + + notify_property_list_changed(); + + update_configuration_warnings(); + return OK; +} + +void AnimationPlayer::remove_animation_library(const StringName &p_name) { + int at_pos = -1; + + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + if (animation_libraries[i].name == p_name) { + at_pos = i; + break; + } + } + + ERR_FAIL_COND(at_pos == -1); + + animation_libraries[at_pos].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added)); + animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added)); + animation_libraries[at_pos].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed)); + + stop(); + + for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[at_pos].library->animations) { + _unref_anim(K.value); + } + + animation_libraries.remove_at(at_pos); + _animation_set_cache_update(); - clear_caches(); notify_property_list_changed(); + update_configuration_warnings(); +} + +void AnimationPlayer::_ref_anim(const Ref<Animation> &p_anim) { + Ref<Animation>(p_anim)->connect(SceneStringNames::get_singleton()->tracks_changed, callable_mp(this, &AnimationPlayer::_animation_changed), varray(), CONNECT_REFERENCE_COUNTED); +} + +void AnimationPlayer::_unref_anim(const Ref<Animation> &p_anim) { + Ref<Animation>(p_anim)->disconnect(SceneStringNames::get_singleton()->tracks_changed, callable_mp(this, &AnimationPlayer::_animation_changed)); +} + +void AnimationPlayer::rename_animation_library(const StringName &p_name, const StringName &p_new_name) { + if (p_name == p_new_name) { + return; + } +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(String(p_new_name).contains("/") || String(p_new_name).contains(":") || String(p_new_name).contains(",") || String(p_new_name).contains("["), "Invalid animation library name: " + String(p_new_name) + "."); +#endif + + bool found = false; + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + ERR_FAIL_COND_MSG(animation_libraries[i].name == p_new_name, "Can't rename animation library to another existing name: " + String(p_new_name)); + if (animation_libraries[i].name == p_name) { + found = true; + animation_libraries[i].name = p_new_name; + // rename connections + animation_libraries[i].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added)); + animation_libraries[i].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added)); + animation_libraries[i].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed)); + + animation_libraries[i].library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added), varray(p_new_name)); + animation_libraries[i].library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added), varray(p_new_name)); + animation_libraries[i].library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed), varray(p_new_name)); + + for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) { + StringName old_name = p_name == StringName() ? K.key : StringName(String(p_name) + "/" + String(K.key)); + StringName new_name = p_new_name == StringName() ? K.key : StringName(String(p_new_name) + "/" + String(K.key)); + _rename_animation(old_name, new_name); + } + } + } + + ERR_FAIL_COND(!found); + + stop(); + + animation_libraries.sort(); // Must keep alphabetical order. + + _animation_set_cache_update(); // Update cache. + + notify_property_list_changed(); +} + +bool AnimationPlayer::has_animation_library(const StringName &p_name) const { + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + if (animation_libraries[i].name == p_name) { + return true; + } + } + + return false; +} + +Ref<AnimationLibrary> AnimationPlayer::get_animation_library(const StringName &p_name) const { + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + if (animation_libraries[i].name == p_name) { + return animation_libraries[i].library; + } + } + ERR_FAIL_V(Ref<AnimationLibrary>()); +} + +TypedArray<StringName> AnimationPlayer::_get_animation_library_list() const { + TypedArray<StringName> ret; + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + ret.push_back(animation_libraries[i].name); + } + return ret; +} + +void AnimationPlayer::get_animation_library_list(List<StringName> *p_libraries) const { + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + p_libraries->push_back(animation_libraries[i].name); + } +} + +TypedArray<String> AnimationPlayer::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); + + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) { + if (animation_set.has(K.key) && animation_set[K.key].animation_library != animation_libraries[i].name) { + warnings.push_back(vformat(RTR("Animation '%s' in library '%s' is unused because another animation with the same name exists in library '%s'."), K.key, animation_libraries[i].name, animation_set[K.key].animation_library)); + } + } + } + return warnings; } bool AnimationPlayer::has_animation(const StringName &p_name) const { @@ -1585,7 +1820,16 @@ StringName AnimationPlayer::find_animation(const Ref<Animation> &p_animation) co } } - return ""; + return StringName(); +} + +StringName AnimationPlayer::find_animation_library(const Ref<Animation> &p_animation) const { + for (const KeyValue<StringName, AnimationData> &E : animation_set) { + if (E.value.animation == p_animation) { + return E.value.animation_library; + } + } + return StringName(); } void AnimationPlayer::set_autoplay(const String &p_name) { @@ -1764,7 +2008,10 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) { AnimationPlayer *aux_player = memnew(AnimationPlayer); EditorNode::get_singleton()->add_child(aux_player); - aux_player->add_animation(SceneStringNames::get_singleton()->RESET, reset_anim); + Ref<AnimationLibrary> al; + al.instantiate(); + al->add_animation(SceneStringNames::get_singleton()->RESET, reset_anim); + aux_player->add_animation_library("default", al); aux_player->set_assigned_animation(SceneStringNames::get_singleton()->RESET); // Forcing the use of the original root because the scene where original player belongs may be not the active one Node *root = get_node(get_root()); @@ -1792,9 +2039,13 @@ bool AnimationPlayer::can_apply_reset() const { #endif // TOOLS_ENABLED void AnimationPlayer::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_animation", "name", "animation"), &AnimationPlayer::add_animation); - ClassDB::bind_method(D_METHOD("remove_animation", "name"), &AnimationPlayer::remove_animation); - ClassDB::bind_method(D_METHOD("rename_animation", "name", "newname"), &AnimationPlayer::rename_animation); + ClassDB::bind_method(D_METHOD("add_animation_library", "name", "library"), &AnimationPlayer::add_animation_library); + ClassDB::bind_method(D_METHOD("remove_animation_library", "name"), &AnimationPlayer::remove_animation_library); + ClassDB::bind_method(D_METHOD("rename_animation_library", "name", "newname"), &AnimationPlayer::rename_animation_library); + ClassDB::bind_method(D_METHOD("has_animation_library", "name"), &AnimationPlayer::has_animation_library); + ClassDB::bind_method(D_METHOD("get_animation_library", "name"), &AnimationPlayer::get_animation_library); + ClassDB::bind_method(D_METHOD("get_animation_library_list"), &AnimationPlayer::_get_animation_library_list); + ClassDB::bind_method(D_METHOD("has_animation", "name"), &AnimationPlayer::has_animation); ClassDB::bind_method(D_METHOD("get_animation", "name"), &AnimationPlayer::get_animation); ClassDB::bind_method(D_METHOD("get_animation_list"), &AnimationPlayer::_get_animation_list); @@ -1838,6 +2089,7 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_root"), &AnimationPlayer::get_root); ClassDB::bind_method(D_METHOD("find_animation", "animation"), &AnimationPlayer::find_animation); + ClassDB::bind_method(D_METHOD("find_animation_library", "animation"), &AnimationPlayer::find_animation_library); ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationPlayer::clear_caches); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index a68f6b9d5b..1d450175ad 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -36,6 +36,7 @@ #include "scene/3d/node_3d.h" #include "scene/3d/skeleton_3d.h" #include "scene/resources/animation.h" +#include "scene/resources/animation_library.h" #ifdef TOOLS_ENABLED class AnimatedValuesBackup : public RefCounted { @@ -184,9 +185,20 @@ private: StringName next; Vector<TrackNodeCache *> node_cache; Ref<Animation> animation; + StringName animation_library; + uint64_t last_update = 0; }; Map<StringName, AnimationData> animation_set; + + struct AnimationLibraryData { + StringName name; + Ref<AnimationLibrary> library; + bool operator<(const AnimationLibraryData &p_data) const { return name.operator String() < p_data.name.operator String(); } + }; + + LocalVector<AnimationLibraryData> animation_libraries; + struct BlendKey { StringName from; StringName to; @@ -261,6 +273,15 @@ private: bool playing = false; + uint64_t animation_set_update_pass = 1; + void _animation_set_cache_update(); + void _animation_added(const StringName &p_name, const StringName &p_library); + void _animation_removed(const StringName &p_name, const StringName &p_library); + void _animation_renamed(const StringName &p_name, const StringName &p_to_name, const StringName &p_library); + void _rename_animation(const StringName &p_from_name, const StringName &p_to_name); + + TypedArray<StringName> _get_animation_library_list() const; + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -272,13 +293,18 @@ protected: public: StringName find_animation(const Ref<Animation> &p_animation) const; + StringName find_animation_library(const Ref<Animation> &p_animation) const; + + Error add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library); + void remove_animation_library(const StringName &p_name); + void rename_animation_library(const StringName &p_name, const StringName &p_new_name); + Ref<AnimationLibrary> get_animation_library(const StringName &p_name) const; + void get_animation_library_list(List<StringName> *p_animations) const; + bool has_animation_library(const StringName &p_name) const; - Error add_animation(const StringName &p_name, const Ref<Animation> &p_animation); - void remove_animation(const StringName &p_name); - void rename_animation(const StringName &p_name, const StringName &p_new_name); - bool has_animation(const StringName &p_name) const; Ref<Animation> get_animation(const StringName &p_name) const; void get_animation_list(List<StringName> *p_animations) const; + bool has_animation(const StringName &p_name) const; void set_blend_time(const StringName &p_animation1, const StringName &p_animation2, float p_time); float get_blend_time(const StringName &p_animation1, const StringName &p_animation2) const; @@ -340,6 +366,8 @@ public: bool can_apply_reset() const; #endif + TypedArray<String> get_configuration_warnings() const override; + AnimationPlayer(); ~AnimationPlayer(); }; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 5e74658470..c953dbf4c3 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -798,7 +798,6 @@ void FileDialog::set_access(Access p_access) { if (access == p_access) { return; } - memdelete(dir_access); switch (p_access) { case ACCESS_FILESYSTEM: { dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); @@ -1091,5 +1090,4 @@ FileDialog::~FileDialog() { if (unregister_func) { unregister_func(this); } - memdelete(dir_access); } diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index b41a08c6c7..2e326d2949 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -82,7 +82,7 @@ private: OptionButton *filter = nullptr; AcceptDialog *mkdirerr = nullptr; AcceptDialog *exterr = nullptr; - DirAccess *dir_access = nullptr; + Ref<DirAccess> dir_access; ConfirmationDialog *confirm_save = nullptr; Label *message = nullptr; diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 1394b4192f..e39791642a 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -696,7 +696,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); int type = gn->get_connection_output_type(j); - if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_output_hotzone(gn, j, mpos, port_size)) { + if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_output_hotzone(gn, j, mpos, port_size)) { connecting_target = true; connecting_to = pos; connecting_target_to = gn->get_name(); @@ -708,7 +708,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); int type = gn->get_connection_input_type(j); - if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_input_hotzone(gn, j, mpos, port_size)) { + if ((type == connecting_type || valid_connection_types.has(ConnType(connecting_type, type))) && is_in_input_hotzone(gn, j, mpos, port_size)) { connecting_target = true; connecting_to = pos; connecting_target_to = gn->get_name(); @@ -1568,26 +1568,17 @@ void GraphEdit::_update_zoom_label() { } void GraphEdit::add_valid_connection_type(int p_type, int p_with_type) { - ConnType ct; - ct.type_a = p_type; - ct.type_b = p_with_type; - + ConnType ct(p_type, p_with_type); valid_connection_types.insert(ct); } void GraphEdit::remove_valid_connection_type(int p_type, int p_with_type) { - ConnType ct; - ct.type_a = p_type; - ct.type_b = p_with_type; - + ConnType ct(p_type, p_with_type); valid_connection_types.erase(ct); } bool GraphEdit::is_valid_connection_type(int p_type, int p_with_type) const { - ConnType ct; - ct.type_a = p_type; - ct.type_b = p_with_type; - + ConnType ct(p_type, p_with_type); return valid_connection_types.has(ct); } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 1e8a149e11..307696c44a 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -203,16 +203,18 @@ void OptionButton::pressed() { } void OptionButton::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id) { + bool first_selectable = !has_selectable_items(); popup->add_icon_radio_check_item(p_icon, p_label, p_id); - if (popup->get_item_count() == 1) { - select(0); + if (first_selectable) { + select(get_item_count() - 1); } } void OptionButton::add_item(const String &p_label, int p_id) { + bool first_selectable = !has_selectable_items(); popup->add_radio_check_item(p_label, p_id); - if (popup->get_item_count() == 1) { - select(0); + if (first_selectable) { + select(get_item_count() - 1); } } @@ -280,6 +282,9 @@ bool OptionButton::is_item_disabled(int p_idx) const { return popup->is_item_disabled(p_idx); } +bool OptionButton::is_item_separator(int p_idx) const { + return popup->is_item_separator(p_idx); +} void OptionButton::set_item_count(int p_count) { ERR_FAIL_COND(p_count < 0); @@ -299,12 +304,37 @@ void OptionButton::set_item_count(int p_count) { notify_property_list_changed(); } +bool OptionButton::has_selectable_items() const { + for (int i = 0; i < get_item_count(); i++) { + if (!is_item_disabled(i) && !is_item_separator(i)) { + return true; + } + } + return false; +} +int OptionButton::get_selectable_item(bool p_from_last) const { + if (!p_from_last) { + for (int i = 0; i < get_item_count(); i++) { + if (!is_item_disabled(i) && !is_item_separator(i)) { + return i; + } + } + } else { + for (int i = get_item_count() - 1; i >= 0; i++) { + if (!is_item_disabled(i) && !is_item_separator(i)) { + return i; + } + } + } + return -1; +} + int OptionButton::get_item_count() const { return popup->get_item_count(); } -void OptionButton::add_separator() { - popup->add_separator(); +void OptionButton::add_separator(const String &p_text) { + popup->add_separator(p_text); } void OptionButton::clear() { @@ -407,7 +437,8 @@ void OptionButton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_metadata", "idx"), &OptionButton::get_item_metadata); ClassDB::bind_method(D_METHOD("get_item_tooltip", "idx"), &OptionButton::get_item_tooltip); ClassDB::bind_method(D_METHOD("is_item_disabled", "idx"), &OptionButton::is_item_disabled); - ClassDB::bind_method(D_METHOD("add_separator"), &OptionButton::add_separator); + ClassDB::bind_method(D_METHOD("is_item_separator", "idx"), &OptionButton::is_item_separator); + ClassDB::bind_method(D_METHOD("add_separator", "text"), &OptionButton::add_separator, DEFVAL(String())); ClassDB::bind_method(D_METHOD("clear"), &OptionButton::clear); ClassDB::bind_method(D_METHOD("select", "idx"), &OptionButton::select); ClassDB::bind_method(D_METHOD("get_selected"), &OptionButton::get_selected); @@ -420,6 +451,8 @@ void OptionButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_item_count", "count"), &OptionButton::set_item_count); ClassDB::bind_method(D_METHOD("get_item_count"), &OptionButton::get_item_count); + ClassDB::bind_method(D_METHOD("has_selectable_items"), &OptionButton::has_selectable_items); + ClassDB::bind_method(D_METHOD("get_selectable_item", "from_last"), &OptionButton::get_selectable_item, DEFVAL(false)); // "selected" property must come after "item_count", otherwise GH-10213 occurs. ADD_ARRAY_COUNT("Items", "item_count", "set_item_count", "get_item_count", "popup/item_"); diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index 921b76c52a..7896132626 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -77,12 +77,16 @@ public: int get_item_index(int p_id) const; Variant get_item_metadata(int p_idx) const; bool is_item_disabled(int p_idx) const; + bool is_item_separator(int p_idx) const; String get_item_tooltip(int p_idx) const; + bool has_selectable_items() const; + int get_selectable_item(bool p_from_last = false) const; + void set_item_count(int p_count); int get_item_count() const; - void add_separator(); + void add_separator(const String &p_text = ""); void clear(); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 981766e5eb..8e26fae8c2 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1909,6 +1909,10 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { vscroll->set_value(vscroll->get_max()); handled = true; } + if (k->is_action("ui_text_select_all")) { + select_all(); + handled = true; + } if (k->is_action("ui_copy")) { selection_copy(); handled = true; @@ -4196,6 +4200,44 @@ void RichTextLabel::selection_copy() { } } +void RichTextLabel::select_all() { + if (!selection.enabled) { + return; + } + + Item *it = main; + Item *from_item = nullptr; + Item *to_item = nullptr; + + while (it) { + if (it->type != ITEM_FRAME) { + if (from_item == nullptr) { + from_item = it; + } else { + to_item = it; + } + } + it = _get_next_item(it, true); + } + + ItemFrame *from_frame = nullptr; + int from_line = 0; + _find_frame(from_item, &from_frame, &from_line); + ItemFrame *to_frame = nullptr; + int to_line = 0; + _find_frame(to_item, &to_frame, &to_line); + selection.from_line = from_line; + selection.from_frame = from_frame; + selection.from_char = 0; + selection.from_item = from_item; + selection.to_line = to_line; + selection.to_frame = to_frame; + selection.to_char = to_frame->lines[to_line].char_count; + selection.to_item = to_item; + selection.active = true; + update(); +} + bool RichTextLabel::is_selection_enabled() const { return selection.enabled; } @@ -4491,6 +4533,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_selection_from"), &RichTextLabel::get_selection_from); ClassDB::bind_method(D_METHOD("get_selection_to"), &RichTextLabel::get_selection_to); + ClassDB::bind_method(D_METHOD("select_all"), &RichTextLabel::select_all); ClassDB::bind_method(D_METHOD("get_selected_text"), &RichTextLabel::get_selected_text); ClassDB::bind_method(D_METHOD("deselect"), &RichTextLabel::deselect); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index b710413987..9ee182c668 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -584,6 +584,7 @@ public: int get_selection_from() const; int get_selection_to() const; String get_selected_text() const; + void select_all(); void selection_copy(); void set_deselect_on_focus_loss_enabled(const bool p_enabled); bool is_deselect_on_focus_loss_enabled() const; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 86969e3ef4..ff23e44cb7 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1944,44 +1944,45 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { return; } - // SELECT ALL, SELECT WORD UNDER CARET, CUT, COPY, PASTE. - - if (k->is_action("ui_text_select_all", true)) { - select_all(); - accept_event(); - return; - } - if (k->is_action("ui_text_select_word_under_caret", true)) { - select_word_under_caret(); - accept_event(); - return; - } - if (k->is_action("ui_cut", true)) { - cut(); - accept_event(); - return; - } - if (k->is_action("ui_copy", true)) { - copy(); - accept_event(); - return; - } - if (k->is_action("ui_paste", true)) { - paste(); - accept_event(); - return; - } + if (is_shortcut_keys_enabled()) { + // SELECT ALL, SELECT WORD UNDER CARET, CUT, COPY, PASTE. + if (k->is_action("ui_text_select_all", true)) { + select_all(); + accept_event(); + return; + } + if (k->is_action("ui_text_select_word_under_caret", true)) { + select_word_under_caret(); + accept_event(); + return; + } + if (k->is_action("ui_cut", true)) { + cut(); + accept_event(); + return; + } + if (k->is_action("ui_copy", true)) { + copy(); + accept_event(); + return; + } + if (k->is_action("ui_paste", true)) { + paste(); + accept_event(); + return; + } - // UNDO/REDO. - if (k->is_action("ui_undo", true)) { - undo(); - accept_event(); - return; - } - if (k->is_action("ui_redo", true)) { - redo(); - accept_event(); - return; + // UNDO/REDO. + if (k->is_action("ui_undo", true)) { + undo(); + accept_event(); + return; + } + if (k->is_action("ui_redo", true)) { + redo(); + accept_event(); + return; + } } // MISC. diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index ccd24ed2cf..24cd485e1b 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -101,6 +101,7 @@ void TreeItem::_change_tree(Tree *p_tree) { if (tree->popup_edited_item == this) { tree->popup_edited_item = nullptr; + tree->popup_pressing_edited_item = nullptr; tree->pressing_for_editor = false; } @@ -2670,8 +2671,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int } click_handled = true; - popup_edited_item = p_item; - popup_edited_item_col = col; + popup_pressing_edited_item = p_item; + popup_pressing_edited_item_column = col; pressing_item_rect = Rect2(get_global_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs) - cache.offset, Size2(col_width, item_h)); pressing_for_editor_text = editor_text; @@ -3206,10 +3207,16 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { update(); } - if (pressing_for_editor && popup_edited_item && (popup_edited_item->get_cell_mode(popup_edited_item_col) == TreeItem::CELL_MODE_RANGE)) { - //range drag + if (pressing_for_editor && popup_pressing_edited_item && (popup_pressing_edited_item->get_cell_mode(popup_pressing_edited_item_column) == TreeItem::CELL_MODE_RANGE)) { + /* This needs to happen now, because the popup can be closed when pressing another item, and must remain the popup edited item until it actually closes */ + popup_edited_item = popup_pressing_edited_item; + popup_edited_item_col = popup_pressing_edited_item_column; + + popup_pressing_edited_item = nullptr; + popup_pressing_edited_item_column = -1; if (!range_drag_enabled) { + //range drag Vector2 cpos = mm->get_position(); if (rtl) { cpos.x = get_size().width - cpos.x; @@ -3994,6 +4001,7 @@ void Tree::clear() { selected_item = nullptr; edited_item = nullptr; popup_edited_item = nullptr; + popup_pressing_edited_item = nullptr; update(); }; @@ -4309,12 +4317,16 @@ int Tree::get_pressed_button() const { return pressed_button; } -Rect2 Tree::get_item_rect(TreeItem *p_item, int p_column) const { +Rect2 Tree::get_item_rect(TreeItem *p_item, int p_column, int p_button) const { ERR_FAIL_NULL_V(p_item, Rect2()); ERR_FAIL_COND_V(p_item->tree != this, Rect2()); if (p_column != -1) { ERR_FAIL_INDEX_V(p_column, columns.size(), Rect2()); } + if (p_button != -1) { + ERR_FAIL_COND_V(p_column == -1, Rect2()); // pass a column if you want to pass a button + ERR_FAIL_INDEX_V(p_button, p_item->cells[p_column].buttons.size(), Rect2()); + } int ofs = get_item_offset(p_item); int height = compute_item_height(p_item); @@ -4332,6 +4344,19 @@ Rect2 Tree::get_item_rect(TreeItem *p_item, int p_column) const { } r.position.x = accum; r.size.x = get_column_width(p_column); + if (p_button != -1) { + const TreeItem::Cell &c = p_item->cells[p_column]; + Vector2 ofst = Vector2(r.position.x + r.size.x, r.position.y); + for (int j = c.buttons.size() - 1; j >= 0; j--) { + Ref<Texture2D> b = c.buttons[j].texture; + Size2 size = b->get_size() + cache.button_pressed->get_minimum_size(); + ofst.x -= size.x; + + if (j == p_button) { + return Rect2(ofst, size); + } + } + } } return r; @@ -4870,7 +4895,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_edited_column"), &Tree::get_edited_column); ClassDB::bind_method(D_METHOD("edit_selected"), &Tree::edit_selected); ClassDB::bind_method(D_METHOD("get_custom_popup_rect"), &Tree::get_custom_popup_rect); - ClassDB::bind_method(D_METHOD("get_item_area_rect", "item", "column"), &Tree::get_item_rect, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("get_item_area_rect", "item", "column", "button_index"), &Tree::get_item_rect, DEFVAL(-1), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_item_at_position", "position"), &Tree::get_item_at_position); ClassDB::bind_method(D_METHOD("get_column_at_position", "position"), &Tree::get_column_at_position); ClassDB::bind_method(D_METHOD("get_drop_section_at_position", "position"), &Tree::get_drop_section_at_position); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 74ad4f94b8..b704495444 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -379,6 +379,9 @@ private: TreeItem *selected_item = nullptr; TreeItem *edited_item = nullptr; + TreeItem *popup_pressing_edited_item = nullptr; // Candidate. + int popup_pressing_edited_item_column = -1; + TreeItem *drop_mode_over = nullptr; int drop_mode_section = 0; @@ -673,7 +676,7 @@ public: Rect2 get_custom_popup_rect() const; int get_item_offset(TreeItem *p_item) const; - Rect2 get_item_rect(TreeItem *p_item, int p_column = -1) const; + Rect2 get_item_rect(TreeItem *p_item, int p_column = -1, int p_button = -1) const; bool edit_selected(); bool is_editing(); diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 15d36d8230..f5fe87c808 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -883,9 +883,6 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent); ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled); - ClassDB::bind_method(D_METHOD("_set_on_top", "on_top"), &CanvasItem::_set_on_top); - ClassDB::bind_method(D_METHOD("_is_on_top"), &CanvasItem::_is_on_top); - ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width"), &CanvasItem::draw_line, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("draw_dashed_line", "from", "to", "color", "width", "dash"), &CanvasItem::draw_dashed_line, DEFVAL(1.0), DEFVAL(2.0)); ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false)); @@ -959,7 +956,6 @@ void CanvasItem::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_on_top", "_is_on_top"); //compatibility ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children"); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask"); diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index dbc833aa5b..95fae0fda7 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -120,9 +120,6 @@ private: void _notify_transform(CanvasItem *p_node); - void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); } - bool _is_on_top() const { return !is_draw_behind_parent_enabled(); } - static CanvasItem *current_item_drawn; friend class Viewport; void _update_texture_repeat_changed(bool p_propagate); diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 2d5814c954..43cdbc7f1d 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -197,10 +197,7 @@ void HTTPRequest::cancel_request() { thread.wait_to_finish(); } - if (file) { - memdelete(file); - file = nullptr; - } + file = Ref<FileAccess>(); client->close(); body.clear(); got_response = false; @@ -365,7 +362,7 @@ bool HTTPRequest::_update_connection() { if (!download_to_file.is_empty()) { file = FileAccess::open(download_to_file, FileAccess::WRITE); - if (!file) { + if (file.is_null()) { call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray()); return true; } @@ -381,7 +378,7 @@ bool HTTPRequest::_update_connection() { if (chunk.size()) { downloaded.add(chunk.size()); - if (file) { + if (file.is_valid()) { const uint8_t *r = chunk.ptr(); file->store_buffer(r, chunk.size()); if (file->get_error() != OK) { @@ -642,9 +639,3 @@ HTTPRequest::HTTPRequest() { timer->connect("timeout", callable_mp(this, &HTTPRequest::_timeout)); add_child(timer); } - -HTTPRequest::~HTTPRequest() { - if (file) { - memdelete(file); - } -} diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 8b3441f7d7..49b4b1b30c 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -84,7 +84,7 @@ private: String download_to_file; - FileAccess *file = nullptr; + Ref<FileAccess> file; int body_len = -1; SafeNumeric<int> downloaded; @@ -158,7 +158,6 @@ public: void set_https_proxy(const String &p_host, int p_port); HTTPRequest(); - ~HTTPRequest(); }; VARIANT_ENUM_CAST(HTTPRequest::Result); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index d005633bb5..151239c9e7 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1262,7 +1262,7 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) { void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { if (p_function == "change_scene") { - DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); List<String> directories; directories.push_back(dir_access->get_current_dir()); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 2faa107fb4..9a7ed1a0ec 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -981,7 +981,7 @@ void Window::_window_input_text(const String &p_text) { } void Window::_window_drop_files(const Vector<String> &p_files) { - emit_signal(SNAME("files_dropped"), p_files, current_screen); + emit_signal(SNAME("files_dropped"), p_files); } Viewport *Window::get_parent_viewport() const { @@ -1079,6 +1079,7 @@ void Window::popup_centered(const Size2i &p_minsize) { void Window::popup_centered_ratio(float p_ratio) { ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND_MSG(window_id == DisplayServer::MAIN_WINDOW_ID, "Can't popup the main window."); + ERR_FAIL_COND_MSG(p_ratio <= 0.0 || p_ratio > 1.0, "Ratio must be between 0.0 and 1.0!"); Rect2 parent_rect; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 032f43d9b9..127e734e6c 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -139,6 +139,7 @@ #include "scene/multiplayer/scene_cache_interface.h" #include "scene/multiplayer/scene_replication_interface.h" #include "scene/multiplayer/scene_rpc_interface.h" +#include "scene/resources/animation_library.h" #include "scene/resources/audio_stream_sample.h" #include "scene/resources/bit_map.h" #include "scene/resources/box_shape_3d.h" @@ -834,6 +835,7 @@ void register_scene_types() { GDREGISTER_CLASS(CompressedTexture2DArray); GDREGISTER_CLASS(Animation); + GDREGISTER_CLASS(AnimationLibrary); GDREGISTER_CLASS(FontData); GDREGISTER_CLASS(Font); GDREGISTER_CLASS(Curve); @@ -896,18 +898,16 @@ void register_scene_types() { #ifndef DISABLE_DEPRECATED // Dropped in 4.0, near approximation. ClassDB::add_compatibility_class("AnimationTreePlayer", "AnimationTree"); - ClassDB::add_compatibility_class("AStar", "AStar3D"); + ClassDB::add_compatibility_class("BakedLightmap", "LightmapGI"); + ClassDB::add_compatibility_class("BakedLightmapData", "LightmapGIData"); ClassDB::add_compatibility_class("BitmapFont", "Font"); ClassDB::add_compatibility_class("DynamicFont", "Font"); ClassDB::add_compatibility_class("DynamicFontData", "FontData"); - ClassDB::add_compatibility_class("ToolButton", "Button"); ClassDB::add_compatibility_class("Navigation3D", "Node3D"); ClassDB::add_compatibility_class("Navigation2D", "Node2D"); + ClassDB::add_compatibility_class("OpenSimplexNoise", "FastNoiseLite"); + ClassDB::add_compatibility_class("ToolButton", "Button"); ClassDB::add_compatibility_class("YSort", "Node2D"); - ClassDB::add_compatibility_class("GIProbe", "VoxelGI"); - ClassDB::add_compatibility_class("GIProbeData", "VoxelGIData"); - ClassDB::add_compatibility_class("BakedLightmap", "LightmapGI"); - ClassDB::add_compatibility_class("BakedLightmapData", "LightmapGIData"); // Portal and room occlusion was replaced by raster occlusion (OccluderInstance3D node). ClassDB::add_compatibility_class("Portal", "Node3D"); ClassDB::add_compatibility_class("Room", "Node3D"); @@ -928,6 +928,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("ARVROrigin", "XROrigin3D"); ClassDB::add_compatibility_class("ARVRPositionalTracker", "XRPositionalTracker"); ClassDB::add_compatibility_class("ARVRServer", "XRServer"); + ClassDB::add_compatibility_class("AStar", "AStar3D"); ClassDB::add_compatibility_class("BoneAttachment", "BoneAttachment3D"); ClassDB::add_compatibility_class("BoxShape", "BoxShape3D"); ClassDB::add_compatibility_class("Camera", "Camera3D"); @@ -955,6 +956,8 @@ void register_scene_types() { ClassDB::add_compatibility_class("EditorSpatialGizmo", "EditorNode3DGizmo"); ClassDB::add_compatibility_class("EditorSpatialGizmoPlugin", "EditorNode3DGizmoPlugin"); ClassDB::add_compatibility_class("Generic6DOFJoint", "Generic6DOFJoint3D"); + ClassDB::add_compatibility_class("GIProbe", "VoxelGI"); + ClassDB::add_compatibility_class("GIProbeData", "VoxelGIData"); ClassDB::add_compatibility_class("GradientTexture", "GradientTexture1D"); ClassDB::add_compatibility_class("HeightMapShape", "HeightMapShape3D"); ClassDB::add_compatibility_class("HingeJoint", "HingeJoint3D"); diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp new file mode 100644 index 0000000000..f7b8c6a648 --- /dev/null +++ b/scene/resources/animation_library.cpp @@ -0,0 +1,134 @@ +/*************************************************************************/ +/* animation_library.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "animation_library.h" + +Error AnimationLibrary::add_animation(const StringName &p_name, const Ref<Animation> &p_animation) { + ERR_FAIL_COND_V_MSG(String(p_name).contains("/") || String(p_name).contains(":") || String(p_name).contains(",") || String(p_name).contains("["), ERR_INVALID_PARAMETER, "Invalid animation name: " + String(p_name) + "."); + ERR_FAIL_COND_V(p_animation.is_null(), ERR_INVALID_PARAMETER); + + if (animations.has(p_name)) { + animations.erase(p_name); + emit_signal(SNAME("animation_removed"), p_name); + } + + animations.insert(p_name, p_animation); + emit_signal(SNAME("animation_added"), p_name); + notify_property_list_changed(); + return OK; +} + +void AnimationLibrary::remove_animation(const StringName &p_name) { + ERR_FAIL_COND(!animations.has(p_name)); + + animations.erase(p_name); + emit_signal(SNAME("animation_removed"), p_name); + notify_property_list_changed(); +} + +void AnimationLibrary::rename_animation(const StringName &p_name, const StringName &p_new_name) { + ERR_FAIL_COND(!animations.has(p_name)); + ERR_FAIL_COND_MSG(String(p_name).contains("/") || String(p_name).contains(":") || String(p_name).contains(",") || String(p_name).contains("["), "Invalid animation name: " + String(p_name) + "."); + ERR_FAIL_COND(animations.has(p_new_name)); + + animations.insert(p_new_name, animations[p_name]); + animations.erase(p_name); + emit_signal(SNAME("animation_renamed"), p_name, p_new_name); +} + +bool AnimationLibrary::has_animation(const StringName &p_name) const { + return animations.has(p_name); +} + +Ref<Animation> AnimationLibrary::get_animation(const StringName &p_name) const { + ERR_FAIL_COND_V(!animations.has(p_name), Ref<Animation>()); + + return animations[p_name]; +} + +TypedArray<StringName> AnimationLibrary::_get_animation_list() const { + TypedArray<StringName> ret; + List<StringName> names; + get_animation_list(&names); + for (const StringName &K : names) { + ret.push_back(K); + } + return ret; +} + +void AnimationLibrary::get_animation_list(List<StringName> *p_animations) const { + List<StringName> anims; + + for (const KeyValue<StringName, Ref<Animation>> &E : animations) { + anims.push_back(E.key); + } + + anims.sort_custom<StringName::AlphCompare>(); + + for (const StringName &E : anims) { + p_animations->push_back(E); + } +} + +void AnimationLibrary::_set_data(const Dictionary &p_data) { + animations.clear(); + List<Variant> keys; + p_data.get_key_list(&keys); + for (const Variant &K : keys) { + add_animation(K, p_data[K]); + } +} + +Dictionary AnimationLibrary::_get_data() const { + Dictionary ret; + for (const KeyValue<StringName, Ref<Animation>> &K : animations) { + ret[K.key] = K.value; + } + return ret; +} + +void AnimationLibrary::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_animation", "name", "animation"), &AnimationLibrary::add_animation); + ClassDB::bind_method(D_METHOD("remove_animation", "name"), &AnimationLibrary::remove_animation); + ClassDB::bind_method(D_METHOD("rename_animation", "name", "newname"), &AnimationLibrary::rename_animation); + ClassDB::bind_method(D_METHOD("has_animation", "name"), &AnimationLibrary::has_animation); + ClassDB::bind_method(D_METHOD("get_animation", "name"), &AnimationLibrary::get_animation); + ClassDB::bind_method(D_METHOD("get_animation_list"), &AnimationLibrary::_get_animation_list); + + ClassDB::bind_method(D_METHOD("_set_data", "data"), &AnimationLibrary::_set_data); + ClassDB::bind_method(D_METHOD("_get_data"), &AnimationLibrary::_get_data); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "_set_data", "_get_data"); + ADD_SIGNAL(MethodInfo("animation_added", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation"))); + ADD_SIGNAL(MethodInfo("animation_removed", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation"))); + ADD_SIGNAL(MethodInfo("animation_renamed", PropertyInfo(Variant::OBJECT, "name", PROPERTY_HINT_RESOURCE_TYPE, "Animation"), PropertyInfo(Variant::OBJECT, "to_name", PROPERTY_HINT_RESOURCE_TYPE, "Animation"))); +} +AnimationLibrary::AnimationLibrary() { +} diff --git a/tests/core/templates/test_oa_hash_map.h b/scene/resources/animation_library.h index d4b72af2ac..69ac5a97d2 100644 --- a/tests/core/templates/test_oa_hash_map.h +++ b/scene/resources/animation_library.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* test_oa_hash_map.h */ +/* animation_library.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,35 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef TEST_OA_HASH_MAP_H -#define TEST_OA_HASH_MAP_H +#ifndef ANIMATION_LIBRARY_H +#define ANIMATION_LIBRARY_H -class MainLoop; +#include "core/variant/typed_array.h" +#include "scene/resources/animation.h" -namespace TestOAHashMap { +class AnimationLibrary : public Resource { + GDCLASS(AnimationLibrary, Resource) -MainLoop *test(); -} + void _set_data(const Dictionary &p_data); + Dictionary _get_data() const; -#endif // TEST_OA_HASH_MAP_H + TypedArray<StringName> _get_animation_list() const; + + friend class AnimationPlayer; //for faster access + Map<StringName, Ref<Animation>> animations; + +protected: + static void _bind_methods(); + +public: + Error add_animation(const StringName &p_name, const Ref<Animation> &p_animation); + void remove_animation(const StringName &p_name); + void rename_animation(const StringName &p_name, const StringName &p_new_name); + bool has_animation(const StringName &p_name) const; + Ref<Animation> get_animation(const StringName &p_name) const; + void get_animation_list(List<StringName> *p_animations) const; + + AnimationLibrary(); +}; + +#endif // ANIMATIONLIBRARY_H diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp index 56786ac4b1..30c222bdff 100644 --- a/scene/resources/audio_stream_sample.cpp +++ b/scene/resources/audio_stream_sample.cpp @@ -556,9 +556,9 @@ Error AudioStreamSample::save_to_wav(const String &p_path) { file_path += ".wav"; } - FileAccessRef file = FileAccess::open(file_path, FileAccess::WRITE); //Overrides existing file if present + Ref<FileAccess> file = FileAccess::open(file_path, FileAccess::WRITE); //Overrides existing file if present - ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE); + ERR_FAIL_COND_V(file.is_null(), ERR_FILE_CANT_WRITE); // Create WAV Header file->store_string("RIFF"); //ChunkID @@ -596,8 +596,6 @@ Error AudioStreamSample::save_to_wav(const String &p_path) { break; } - file->close(); - return OK; } diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 6e6ee7d3ac..efbe9c93f7 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -740,8 +740,8 @@ Error FontData::load_bitmap_font(const String &p_path) { hinting = TextServer::HINTING_NONE; oversampling = 1.0f; - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_CREATE, vformat(RTR("Cannot open font from file: %s."), p_path)); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_CREATE, vformat(RTR("Cannot open font from file: %s."), p_path)); int base_size = 16; int height = 0; diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 781e219f1f..40edc5f198 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -270,6 +270,10 @@ PrimitiveMesh::~PrimitiveMesh() { */ void CapsuleMesh::_create_mesh_array(Array &p_arr) const { + create_mesh_array(p_arr, radius, height, radial_segments, rings); +} + +void CapsuleMesh::create_mesh_array(Array &p_arr, const float radius, const float height, const int radial_segments, const int rings) { int i, j, prevrow, thisrow, point; float x, y, z, u, v, w; float onethird = 1.0 / 3.0; @@ -481,6 +485,10 @@ CapsuleMesh::CapsuleMesh() {} */ void BoxMesh::_create_mesh_array(Array &p_arr) const { + BoxMesh::create_mesh_array(p_arr, size, subdivide_w, subdivide_h, subdivide_d); +} + +void BoxMesh::create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w, int subdivide_h, int subdivide_d) { int i, j, prevrow, thisrow, point; float x, y, z; float onethird = 1.0 / 3.0; @@ -732,6 +740,10 @@ BoxMesh::BoxMesh() {} */ void CylinderMesh::_create_mesh_array(Array &p_arr) const { + create_mesh_array(p_arr, top_radius, bottom_radius, height, radial_segments, rings); +} + +void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments, int rings) { int i, j, prevrow, thisrow, point; float x, y, z, u, v, radius; @@ -1431,6 +1443,10 @@ Vector3 QuadMesh::get_center_offset() const { */ void SphereMesh::_create_mesh_array(Array &p_arr) const { + create_mesh_array(p_arr, radius, height, radial_segments, rings, is_hemisphere); +} + +void SphereMesh::create_mesh_array(Array &p_arr, float radius, float height, int radial_segments, int rings, bool is_hemisphere) { int i, j, prevrow, thisrow, point; float x, y, z; diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index eef5eb3f7d..8cd05c1740 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -117,6 +117,8 @@ protected: virtual void _create_mesh_array(Array &p_arr) const override; public: + static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 8); + void set_radius(const float p_radius); float get_radius() const; @@ -149,6 +151,8 @@ protected: virtual void _create_mesh_array(Array &p_arr) const override; public: + static void create_mesh_array(Array &p_arr, Vector3 size, int subdivide_w = 0, int subdivide_h = 0, int subdivide_d = 0); + void set_size(const Vector3 &p_size); Vector3 get_size() const; @@ -183,6 +187,8 @@ protected: virtual void _create_mesh_array(Array &p_arr) const override; public: + static void create_mesh_array(Array &p_arr, float top_radius, float bottom_radius, float height, int radial_segments = 64, int rings = 4); + void set_top_radius(const float p_radius); float get_top_radius() const; @@ -314,6 +320,8 @@ protected: virtual void _create_mesh_array(Array &p_arr) const override; public: + static void create_mesh_array(Array &p_arr, float radius, float height, int radial_segments = 64, int rings = 32, bool is_hemisphere = false); + void set_radius(const float p_radius); float get_radius() const; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index ed19b362eb..ce7007f257 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -738,11 +738,7 @@ void ResourceLoaderText::set_translation_remapped(bool p_remapped) { ResourceLoaderText::ResourceLoaderText() {} -ResourceLoaderText::~ResourceLoaderText() { - memdelete(f); -} - -void ResourceLoaderText::get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types) { +void ResourceLoaderText::get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types) { open(p_f); ignore_resource_parsing = true; ERR_FAIL_COND(error != OK); @@ -798,13 +794,13 @@ void ResourceLoaderText::get_dependencies(FileAccess *p_f, List<String> *p_depen } } -Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_path, const Map<String, String> &p_map) { +Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const Map<String, String> &p_map) { open(p_f, true); ERR_FAIL_COND_V(error != OK, error); ignore_resource_parsing = true; //FileAccess - FileAccess *fw = nullptr; + Ref<FileAccess> fw; String base_path = local_path.get_base_dir(); @@ -814,23 +810,20 @@ Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_p Error err = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp); if (err != OK) { - if (fw) { - memdelete(fw); - } error = ERR_FILE_CORRUPT; ERR_FAIL_V(error); } if (next_tag.name != "ext_resource") { //nothing was done - if (!fw) { + if (fw.is_null()) { return OK; } break; } else { - if (!fw) { + if (fw.is_null()) { fw = FileAccess::open(p_path + ".depren", FileAccess::WRITE); if (is_scene) { fw->store_line("[gd_scene load_steps=" + itos(resources_total) + " format=" + itos(FORMAT_VERSION) + "]\n"); @@ -840,7 +833,6 @@ Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_p } if (!next_tag.fields.has("path") || !next_tag.fields.has("id") || !next_tag.fields.has("type")) { - memdelete(fw); error = ERR_FILE_CORRUPT; ERR_FAIL_V(error); } @@ -898,24 +890,22 @@ Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_p fw->store_8(c); c = f->get_8(); } - f->close(); + f = Ref<FileAccess>(); bool all_ok = fw->get_error() == OK; - memdelete(fw); - if (!all_ok) { return ERR_CANT_CREATE; } - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES); da->remove(p_path); da->rename(p_path + ".depren", p_path); return OK; } -void ResourceLoaderText::open(FileAccess *p_f, bool p_skip_first_tag) { +void ResourceLoaderText::open(Ref<FileAccess> p_f, bool p_skip_first_tag) { error = OK; lines = 1; @@ -992,23 +982,23 @@ void ResourceLoaderText::open(FileAccess *p_f, bool p_skip_first_tag) { rp.userdata = this; } -static void bs_save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len = false) { +static void bs_save_unicode_string(Ref<FileAccess> p_f, const String &p_string, bool p_bit_on_len = false) { CharString utf8 = p_string.utf8(); if (p_bit_on_len) { - f->store_32((utf8.length() + 1) | 0x80000000); + p_f->store_32((utf8.length() + 1) | 0x80000000); } else { - f->store_32(utf8.length() + 1); + p_f->store_32(utf8.length() + 1); } - f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); + p_f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1); } -Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) { +Error ResourceLoaderText::save_as_binary(Ref<FileAccess> p_f, const String &p_path) { if (error) { return error; } - FileAccessRef wf = FileAccess::open(p_path, FileAccess::WRITE); - if (!wf) { + Ref<FileAccess> wf = FileAccess::open(p_path, FileAccess::WRITE); + if (wf.is_null()) { return ERR_CANT_OPEN; } @@ -1023,7 +1013,7 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) static const int save_format_version = 3; //use format version 3 for saving wf->store_32(save_format_version); - bs_save_unicode_string(wf.f, is_scene ? "PackedScene" : resource_type); + bs_save_unicode_string(wf, is_scene ? "PackedScene" : resource_type); wf->store_64(0); //offset to import metadata, this is no longer used wf->store_32(ResourceFormatSaverBinaryInstance::FORMAT_FLAG_NAMED_SCENE_IDS | ResourceFormatSaverBinaryInstance::FORMAT_FLAG_UIDS); @@ -1078,8 +1068,8 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) uid = ResourceUID::get_singleton()->text_to_id(uidt); } - bs_save_unicode_string(wf.f, type); - bs_save_unicode_string(wf.f, path); + bs_save_unicode_string(wf, type); + bs_save_unicode_string(wf, path); wf->store_64(uid); int lindex = dummy_read.external_resources.size(); @@ -1108,8 +1098,8 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) wf->store_32(0); //zero sub resources, still parsing them String temp_file = p_path + ".temp"; - FileAccessRef wf2 = FileAccess::open(temp_file, FileAccess::WRITE); - if (!wf2) { + Ref<FileAccess> wf2 = FileAccess::open(temp_file, FileAccess::WRITE); + if (wf2.is_null()) { return ERR_CANT_OPEN; } @@ -1246,8 +1236,6 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) wf2->seek_end(); } - wf2->close(); - uint64_t offset_from = wf->get_position(); wf->seek(sub_res_count_pos); //plus one because the saved one wf->store_32(local_offsets.size()); @@ -1262,18 +1250,16 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) Vector<uint8_t> data = FileAccess::get_file_as_array(temp_file); wf->store_buffer(data.ptr(), data.size()); { - DirAccessRef dar = DirAccess::open(temp_file.get_base_dir()); + Ref<DirAccess> dar = DirAccess::open(temp_file.get_base_dir()); dar->remove(temp_file); } wf->store_buffer((const uint8_t *)"RSRC", 4); //magic at end - wf->close(); - return OK; } -String ResourceLoaderText::recognize(FileAccess *p_f) { +String ResourceLoaderText::recognize(Ref<FileAccess> p_f) { error = OK; lines = 1; @@ -1317,7 +1303,7 @@ String ResourceLoaderText::recognize(FileAccess *p_f) { return tag.fields["type"]; } -ResourceUID::ID ResourceLoaderText::get_uid(FileAccess *p_f) { +ResourceUID::ID ResourceLoaderText::get_uid(Ref<FileAccess> p_f) { error = OK; lines = 1; @@ -1352,7 +1338,7 @@ RES ResourceFormatLoaderText::load(const String &p_path, const String &p_origina Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot open file '" + p_path + "'."); @@ -1407,8 +1393,8 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const { // ...for anything else must test... - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { return ""; //could not read } @@ -1426,8 +1412,8 @@ ResourceUID::ID ResourceFormatLoaderText::get_resource_uid(const String &p_path) return ResourceUID::INVALID_ID; } - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { return ResourceUID::INVALID_ID; //could not read } @@ -1438,8 +1424,8 @@ ResourceUID::ID ResourceFormatLoaderText::get_resource_uid(const String &p_path) } void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { ERR_FAIL(); } @@ -1450,8 +1436,8 @@ void ResourceFormatLoaderText::get_dependencies(const String &p_path, List<Strin } Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const Map<String, String> &p_map) { - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + if (f.is_null()) { ERR_FAIL_V(ERR_CANT_OPEN); } @@ -1465,7 +1451,7 @@ ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = nullptr; Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) { Error err; - FileAccess *f = FileAccess::open(p_src_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_src_path, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err != OK, ERR_CANT_OPEN, "Cannot open file '" + p_src_path + "'."); @@ -1603,9 +1589,9 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } Error err; - f = FileAccess::open(p_path, FileAccess::WRITE, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err, ERR_CANT_OPEN, "Cannot save file '" + p_path + "'."); - FileAccessRef _fref(f); + Ref<FileAccess> _fref(f); local_path = ProjectSettings::get_singleton()->localize_path(p_path); @@ -1942,12 +1928,9 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } if (f->get_error() != OK && f->get_error() != ERR_FILE_EOF) { - f->close(); return ERR_CANT_CREATE; } - f->close(); - return OK; } diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index 00919165b8..c6543e616d 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -43,7 +43,7 @@ class ResourceLoaderText { String res_path; String error_text; - FileAccess *f = nullptr; + Ref<FileAccess> f; VariantParser::StreamFile stream; @@ -120,15 +120,14 @@ public: int get_stage_count() const; void set_translation_remapped(bool p_remapped); - void open(FileAccess *p_f, bool p_skip_first_tag = false); - String recognize(FileAccess *p_f); - ResourceUID::ID get_uid(FileAccess *p_f); - void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types); - Error rename_dependencies(FileAccess *p_f, const String &p_path, const Map<String, String> &p_map); + void open(Ref<FileAccess> p_f, bool p_skip_first_tag = false); + String recognize(Ref<FileAccess> p_f); + ResourceUID::ID get_uid(Ref<FileAccess> p_f); + void get_dependencies(Ref<FileAccess> p_f, List<String> *p_dependencies, bool p_add_types); + Error rename_dependencies(Ref<FileAccess> p_f, const String &p_path, const Map<String, String> &p_map); - Error save_as_binary(FileAccess *p_f, const String &p_path); + Error save_as_binary(Ref<FileAccess> p_f, const String &p_path); ResourceLoaderText(); - ~ResourceLoaderText(); }; class ResourceFormatLoaderText : public ResourceFormatLoader { @@ -157,7 +156,6 @@ class ResourceFormatSaverTextInstance { bool relative_paths = false; bool bundle_resources = false; bool skip_editor = false; - FileAccess *f = nullptr; struct NonPersistentKey { //for resource properties generated on the fly RES base; diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index ce7fcb199d..25a9278e66 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -217,17 +217,14 @@ Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resourc String source = shader->get_code(); Error err; - FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); ERR_FAIL_COND_V_MSG(err, err, "Cannot save shader '" + p_path + "'."); file->store_string(source); if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { - memdelete(file); return ERR_CANT_CREATE; } - file->close(); - memdelete(file); return OK; } diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp index cbfee754e2..96a47c37c4 100644 --- a/scene/resources/text_file.cpp +++ b/scene/resources/text_file.cpp @@ -51,7 +51,7 @@ void TextFile::reload_from_file() { Error TextFile::load_text(const String &p_path) { Vector<uint8_t> sourcef; Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err); ERR_FAIL_COND_V_MSG(err, err, "Cannot open TextFile '" + p_path + "'."); @@ -59,8 +59,7 @@ Error TextFile::load_text(const String &p_path) { sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); uint64_t r = f->get_buffer(w, len); - f->close(); - memdelete(f); + ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); w[len] = 0; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 44da90de30..4c20e07976 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -646,7 +646,7 @@ PortableCompressedTexture2D::~PortableCompressedTexture2D() { ////////////////////////////////////////// -Ref<Image> CompressedTexture2D::load_image_from_file(FileAccess *f, int p_size_limit) { +Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_size_limit) { uint32_t data_format = f->get_32(); uint32_t w = f->get_16(); uint32_t h = f->get_16(); @@ -821,20 +821,18 @@ Error CompressedTexture2D::_load_data(const String &p_path, int &r_width, int &r ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER); - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); uint8_t header[4]; f->get_buffer(header, 4); if (header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != '2') { - memdelete(f); ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is corrupt (Bad header)."); } uint32_t version = f->get_32(); if (version > FORMAT_VERSION) { - memdelete(f); ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new."); } r_width = f->get_32(); @@ -867,8 +865,6 @@ Error CompressedTexture2D::_load_data(const String &p_path, int &r_width, int &r image = load_image_from_file(f, p_size_limit); - memdelete(f); - if (image.is_null() || image->is_empty()) { return ERR_CANT_OPEN; } @@ -1272,8 +1268,8 @@ Image::Format CompressedTexture3D::get_format() const { } Error CompressedTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) { - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); uint8_t header[4]; f->get_buffer(header, 4); @@ -3092,8 +3088,8 @@ Image::Format CompressedTextureLayered::get_format() const { Error CompressedTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit) { ERR_FAIL_COND_V(images.size() != 0, ERR_INVALID_PARAMETER); - FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); uint8_t header[4]; f->get_buffer(header, 4); diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 7e194fd21d..525e3ff979 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -253,7 +253,7 @@ protected: void _validate_property(PropertyInfo &property) const override; public: - static Ref<Image> load_image_from_file(FileAccess *p_file, int p_size_limit); + static Ref<Image> load_image_from_file(Ref<FileAccess> p_file, int p_size_limit); typedef void (*TextureFormatRequestCallback)(const Ref<CompressedTexture2D> &); typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<CompressedTexture2D> &, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel); diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index f38d800aa7..8ad2d42e5f 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -602,42 +602,119 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point Color *colors_ptr = colors.ptrw(); if (p_antialiased) { + float border_size = 2.0; + if (p_width < border_size) { + border_size = p_width; + } Color color2 = Color(1, 1, 1, 0); - PackedColorArray colors_top; - PackedVector2Array points_top; + PackedColorArray colors_begin; + PackedVector2Array points_begin; + + colors_begin.resize(4); + points_begin.resize(4); + + PackedColorArray colors_begin_left_corner; + PackedVector2Array points_begin_left_corner; + + colors_begin_left_corner.resize(4); + points_begin_left_corner.resize(4); + + PackedColorArray colors_begin_right_corner; + PackedVector2Array points_begin_right_corner; + + colors_begin_right_corner.resize(4); + points_begin_right_corner.resize(4); + + PackedColorArray colors_end; + PackedVector2Array points_end; + + colors_end.resize(4); + points_end.resize(4); + + PackedColorArray colors_end_left_corner; + PackedVector2Array points_end_left_corner; + + colors_end_left_corner.resize(4); + points_end_left_corner.resize(4); + + PackedColorArray colors_end_right_corner; + PackedVector2Array points_end_right_corner; + + colors_end_right_corner.resize(4); + points_end_right_corner.resize(4); + + PackedColorArray colors_left; + PackedVector2Array points_left; + + colors_left.resize(pc2); + points_left.resize(pc2); + + PackedColorArray colors_right; + PackedVector2Array points_right; - colors_top.resize(pc2); - points_top.resize(pc2); + colors_right.resize(pc2); + points_right.resize(pc2); - PackedColorArray colors_bottom; - PackedVector2Array points_bottom; + Item::CommandPolygon *pline_begin = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_begin); - colors_bottom.resize(pc2); - points_bottom.resize(pc2); + Item::CommandPolygon *pline_begin_left_corner = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_begin_left_corner); - Item::CommandPolygon *pline_top = canvas_item->alloc_command<Item::CommandPolygon>(); - ERR_FAIL_COND(!pline_top); + Item::CommandPolygon *pline_begin_right_corner = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_begin_right_corner); - Item::CommandPolygon *pline_bottom = canvas_item->alloc_command<Item::CommandPolygon>(); - ERR_FAIL_COND(!pline_bottom); + Item::CommandPolygon *pline_end = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_end); - //make three trianglestrip's for drawing the antialiased line... + Item::CommandPolygon *pline_end_left_corner = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_end_left_corner); - Vector2 *points_top_ptr = points_top.ptrw(); - Vector2 *points_bottom_ptr = points_bottom.ptrw(); + Item::CommandPolygon *pline_end_right_corner = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_end_right_corner); - Color *colors_top_ptr = colors_top.ptrw(); - Color *colors_bottom_ptr = colors_bottom.ptrw(); + Item::CommandPolygon *pline_left = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_left); + + Item::CommandPolygon *pline_right = canvas_item->alloc_command<Item::CommandPolygon>(); + ERR_FAIL_COND(!pline_right); + + // Makes nine triangle strips for drawing the antialiased line. + + Vector2 *points_begin_ptr = points_begin.ptrw(); + Vector2 *points_begin_left_corner_ptr = points_begin_left_corner.ptrw(); + Vector2 *points_begin_right_corner_ptr = points_begin_right_corner.ptrw(); + Vector2 *points_end_ptr = points_end.ptrw(); + Vector2 *points_end_left_corner_ptr = points_end_left_corner.ptrw(); + Vector2 *points_end_right_corner_ptr = points_end_right_corner.ptrw(); + Vector2 *points_left_ptr = points_left.ptrw(); + Vector2 *points_right_ptr = points_right.ptrw(); + + Color *colors_begin_ptr = colors_begin.ptrw(); + Color *colors_begin_left_corner_ptr = colors_begin_left_corner.ptrw(); + Color *colors_begin_right_corner_ptr = colors_begin_right_corner.ptrw(); + Color *colors_end_ptr = colors_end.ptrw(); + Color *colors_end_left_corner_ptr = colors_end_left_corner.ptrw(); + Color *colors_end_right_corner_ptr = colors_end_right_corner.ptrw(); + Color *colors_left_ptr = colors_left.ptrw(); + Color *colors_right_ptr = colors_right.ptrw(); for (int i = 0, j = 0; i < pc; i++, j += 2) { + bool is_begin = i == 0; + bool is_end = i == pc - 1; + Vector2 t; - if (i == pc - 1) { + Vector2 end_border; + Vector2 begin_border; + if (is_end) { t = prev_t; + end_border = (p_points[i] - p_points[i - 1]).normalized() * border_size; } else { t = (p_points[i + 1] - p_points[i]).normalized().orthogonal(); - if (i == 0) { + if (is_begin) { prev_t = t; + begin_border = (p_points[i] - p_points[i + 1]).normalized() * border_size; } } @@ -645,17 +722,17 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point Vector2 dir = (t + prev_t).normalized(); Vector2 tangent = dir * p_width * 0.5; - Vector2 border = dir * 2.0; + Vector2 border = dir * border_size; Vector2 pos = p_points[i]; points_ptr[j] = pos + tangent; points_ptr[j2] = pos - tangent; - points_top_ptr[j] = pos + tangent + border; - points_top_ptr[j2] = pos + tangent; + points_left_ptr[j] = pos + tangent + border; + points_left_ptr[j2] = pos + tangent; - points_bottom_ptr[j] = pos - tangent; - points_bottom_ptr[j2] = pos - tangent - border; + points_right_ptr[j] = pos - tangent; + points_right_ptr[j2] = pos - tangent - border; if (i < p_colors.size()) { color = p_colors[i]; @@ -665,22 +742,104 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point colors_ptr[j] = color; colors_ptr[j2] = color; - colors_top_ptr[j] = color2; - colors_top_ptr[j2] = color; + colors_left_ptr[j] = color2; + colors_left_ptr[j2] = color; + + colors_right_ptr[j] = color; + colors_right_ptr[j2] = color2; + + if (is_begin) { + points_begin_ptr[0] = pos + tangent + begin_border; + points_begin_ptr[1] = pos - tangent + begin_border; + points_begin_ptr[2] = pos + tangent; + points_begin_ptr[3] = pos - tangent; + + colors_begin_ptr[0] = color2; + colors_begin_ptr[1] = color2; + colors_begin_ptr[2] = color; + colors_begin_ptr[3] = color; + + points_begin_left_corner_ptr[0] = pos - tangent - border; + points_begin_left_corner_ptr[1] = pos - tangent + begin_border - border; + points_begin_left_corner_ptr[2] = pos - tangent; + points_begin_left_corner_ptr[3] = pos - tangent + begin_border; + + colors_begin_left_corner_ptr[0] = color2; + colors_begin_left_corner_ptr[1] = color2; + colors_begin_left_corner_ptr[2] = color; + colors_begin_left_corner_ptr[3] = color2; + + points_begin_right_corner_ptr[0] = pos + tangent + begin_border; + points_begin_right_corner_ptr[1] = pos + tangent + begin_border + border; + points_begin_right_corner_ptr[2] = pos + tangent; + points_begin_right_corner_ptr[3] = pos + tangent + border; + + colors_begin_right_corner_ptr[0] = color2; + colors_begin_right_corner_ptr[1] = color2; + colors_begin_right_corner_ptr[2] = color; + colors_begin_right_corner_ptr[3] = color2; + } - colors_bottom_ptr[j] = color; - colors_bottom_ptr[j2] = color2; + if (is_end) { + points_end_ptr[0] = pos + tangent + end_border; + points_end_ptr[1] = pos - tangent + end_border; + points_end_ptr[2] = pos + tangent; + points_end_ptr[3] = pos - tangent; + + colors_end_ptr[0] = color2; + colors_end_ptr[1] = color2; + colors_end_ptr[2] = color; + colors_end_ptr[3] = color; + + points_end_left_corner_ptr[0] = pos - tangent - border; + points_end_left_corner_ptr[1] = pos - tangent + end_border - border; + points_end_left_corner_ptr[2] = pos - tangent; + points_end_left_corner_ptr[3] = pos - tangent + end_border; + + colors_end_left_corner_ptr[0] = color2; + colors_end_left_corner_ptr[1] = color2; + colors_end_left_corner_ptr[2] = color; + colors_end_left_corner_ptr[3] = color2; + + points_end_right_corner_ptr[0] = pos + tangent + end_border; + points_end_right_corner_ptr[1] = pos + tangent + end_border + border; + points_end_right_corner_ptr[2] = pos + tangent; + points_end_right_corner_ptr[3] = pos + tangent + border; + + colors_end_right_corner_ptr[0] = color2; + colors_end_right_corner_ptr[1] = color2; + colors_end_right_corner_ptr[2] = color; + colors_end_right_corner_ptr[3] = color2; + } prev_t = t; } - pline_top->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; - pline_top->polygon.create(indices, points_top, colors_top); + pline_begin->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_begin->polygon.create(indices, points_begin, colors_begin); + + pline_begin_left_corner->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_begin_left_corner->polygon.create(indices, points_begin_left_corner, colors_begin_left_corner); + + pline_begin_right_corner->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_begin_right_corner->polygon.create(indices, points_begin_right_corner, colors_begin_right_corner); + + pline_end->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_end->polygon.create(indices, points_end, colors_end); + + pline_end_left_corner->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_end_left_corner->polygon.create(indices, points_end_left_corner, colors_end_left_corner); + + pline_end_right_corner->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_end_right_corner->polygon.create(indices, points_end_right_corner, colors_end_right_corner); + + pline_left->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_left->polygon.create(indices, points_left, colors_left); - pline_bottom->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; - pline_bottom->polygon.create(indices, points_bottom, colors_bottom); + pline_right->primitive = RS::PRIMITIVE_TRIANGLE_STRIP; + pline_right->polygon.create(indices, points_right, colors_right); } else { - //make a trianglestrip for drawing the line... + // Makes a single triangle strip for drawing the line. for (int i = 0, j = 0; i < pc; i++, j += 2) { Vector2 t; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index e24d020a14..365bef896f 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -2273,7 +2273,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend texture = shadow_atlas_get_texture(p_render_data->shadow_atlas); } if (!texture.is_valid()) { - texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE); + texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH); } u.append_id(texture); uniforms.push_back(u); @@ -2285,7 +2285,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) { u.append_id(directional_shadow_get_texture()); } else { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE)); + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH)); } uniforms.push_back(u); } @@ -2342,7 +2342,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend u.binding = 9; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID dbt = rb ? render_buffers_get_back_depth_texture(p_render_data->render_buffers) : RID(); - RID texture = (dbt.is_valid()) ? dbt : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE); + RID texture = (dbt.is_valid()) ? dbt : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH); u.append_id(texture); uniforms.push_back(u); } @@ -2499,7 +2499,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te RD::Uniform u; u.binding = 4; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE); + RID texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH); u.append_id(texture); uniforms.push_back(u); } @@ -2509,7 +2509,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te RD::Uniform u; u.binding = 5; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - RID texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE); + RID texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH); u.append_id(texture); uniforms.push_back(u); } diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 2acce8bab7..99a7fe6280 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -824,6 +824,9 @@ void SceneShaderForwardClustered::set_default_specialization_constants(const Vec for (int k = 0; k < SHADER_VERSION_MAX; k++) { E->self()->pipelines[i][j][k].update_specialization_constants(default_specialization_constants); } + for (int k = 0; k < PIPELINE_COLOR_PASS_FLAG_COUNT; k++) { + E->self()->color_pipelines[i][j][k].update_specialization_constants(default_specialization_constants); + } } } } diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 156d535447..7272b2f8d0 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -350,7 +350,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ texture = shadow_atlas_get_texture(p_render_data->shadow_atlas); } if (!texture.is_valid()) { - texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE); + texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH); } u.append_id(texture); uniforms.push_back(u); @@ -362,7 +362,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) { u.append_id(directional_shadow_get_texture()); } else { - u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE)); + u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH)); } uniforms.push_back(u); } @@ -425,7 +425,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ u.binding = 9; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; RID dbt = rb ? render_buffers_get_back_depth_texture(p_render_data->render_buffers) : RID(); - RID texture = (dbt.is_valid()) ? dbt : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE); + RID texture = (dbt.is_valid()) ? dbt : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH); u.append_id(texture); uniforms.push_back(u); } diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 5b7c63b508..ba4796e19d 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -253,8 +253,8 @@ RendererCompositorRD::RendererCompositorRD() { if (shader_cache_dir.is_empty()) { shader_cache_dir = "user://"; } - DirAccessRef da = DirAccess::open(shader_cache_dir); - if (!da) { + Ref<DirAccess> da = DirAccess::open(shader_cache_dir); + if (da.is_null()) { ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir); } else { Error err = da->change_dir("shader_cache"); diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 73766d14d8..fdfecf2d2c 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -382,8 +382,8 @@ 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"; - FileAccessRef f = FileAccess::open(path, FileAccess::READ); - if (!f) { + Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ); + if (f.is_null()) { return false; } @@ -445,8 +445,8 @@ 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"; - FileAccessRef f = FileAccess::open(path, FileAccess::WRITE); - ERR_FAIL_COND(!f); + Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE); + ERR_FAIL_COND(f.is_null()); f->store_buffer((const uint8_t *)shader_file_header, 4); f->store_32(cache_file_version); //file version uint32_t variant_count = variant_defines.size(); @@ -456,8 +456,6 @@ void ShaderRD::_save_to_cache(Version *p_version) { f->store_32(p_version->variant_data[i].size()); //stage count f->store_buffer(p_version->variant_data[i].ptr(), p_version->variant_data[i].size()); } - - f->close(); } void ShaderRD::_compile_version(Version *p_version) { @@ -652,8 +650,8 @@ void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String base_sha256 = hash_build.as_string().sha256_text(); - DirAccessRef d = DirAccess::open(shader_cache_dir); - ERR_FAIL_COND(!d); + Ref<DirAccess> d = DirAccess::open(shader_cache_dir); + ERR_FAIL_COND(d.is_null()); if (d->change_dir(name) != OK) { Error err = d->make_dir(name); ERR_FAIL_COND(err != OK); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index a3ca7d3720..3379e1cb17 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -124,6 +124,26 @@ TextureStorage::TextureStorage() { default_rd_textures[DEFAULT_RD_TEXTURE_ANISO] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); } + { + RD::TextureFormat tf; + tf.format = RD::DATA_FORMAT_D16_UNORM; + tf.width = 4; + tf.height = 4; + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + tf.texture_type = RD::TEXTURE_TYPE_2D; + + Vector<uint8_t> sv; + sv.resize(16 * 2); + uint16_t *ptr = (uint16_t *)sv.ptrw(); + for (int i = 0; i < 16; i++) { + ptr[i] = Math::make_half_float(1.0f); + } + + Vector<Vector<uint8_t>> vpv; + vpv.push_back(sv); + default_rd_textures[DEFAULT_RD_TEXTURE_DEPTH] = RD::get_singleton()->texture_create(tf, RD::TextureView(), vpv); + } + for (int i = 0; i < 16; i++) { pv.set(i * 4 + 0, 0); pv.set(i * 4 + 1, 0); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h index 5d8d165a08..edff10b944 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h @@ -42,6 +42,7 @@ enum DefaultRDTexture { DEFAULT_RD_TEXTURE_BLACK, DEFAULT_RD_TEXTURE_NORMAL, DEFAULT_RD_TEXTURE_ANISO, + DEFAULT_RD_TEXTURE_DEPTH, DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER, DEFAULT_RD_TEXTURE_CUBEMAP_BLACK, DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK, diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 2f32e81f06..7e3fde6a1f 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -395,7 +395,7 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_get_range", "shaped"), &TextServer::shaped_text_get_range); ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks_adv", "shaped", "width", "start", "once", "break_flags"), &TextServer::shaped_text_get_line_breaks_adv, DEFVAL(0), DEFVAL(true), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks", "shaped", "width", "start", "break_flags"), &TextServer::shaped_text_get_line_breaks, DEFVAL(0), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); - ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped", "grapheme_flags"), &TextServer::shaped_text_get_word_breaks); + ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped", "grapheme_flags"), &TextServer::shaped_text_get_word_breaks, DEFVAL(GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION)); ClassDB::bind_method(D_METHOD("shaped_text_get_trim_pos", "shaped"), &TextServer::shaped_text_get_trim_pos); ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_pos", "shaped"), &TextServer::shaped_text_get_ellipsis_pos); @@ -979,6 +979,14 @@ TextServer::Direction TextServer::shaped_text_get_dominant_direction_in_range(co } } +_FORCE_INLINE_ void _push_range(Vector<Vector2> &r_vector, real_t p_start, real_t p_end) { + if (!r_vector.is_empty() && Math::is_equal_approx(r_vector[r_vector.size() - 1].y, p_start, (real_t)UNIT_EPSILON)) { + r_vector.write[r_vector.size() - 1].y = p_end; + } else { + r_vector.push_back(Vector2(p_start, p_end)); + } +} + Vector<Vector2> TextServer::shaped_text_get_selection(const RID &p_shaped, int64_t p_start, int64_t p_end) const { Vector<Vector2> ranges; @@ -1003,7 +1011,7 @@ Vector<Vector2> TextServer::shaped_text_get_selection(const RID &p_shaped, int64 for (int j = 0; j < glyphs[i].count; j++) { advance += glyphs[i + j].advance; } - ranges.push_back(Vector2(off, off + advance)); + _push_range(ranges, off, off + advance); } // Only start of grapheme is in selection range. if (glyphs[i].start >= start && glyphs[i].end > end) { @@ -1013,9 +1021,9 @@ Vector<Vector2> TextServer::shaped_text_get_selection(const RID &p_shaped, int64 } real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start); if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { - ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - end), off + advance)); + _push_range(ranges, off + char_adv * (glyphs[i].end - end), off + advance); } else { - ranges.push_back(Vector2(off, off + char_adv * (end - glyphs[i].start))); + _push_range(ranges, off, off + char_adv * (end - glyphs[i].start)); } } // Only end of grapheme is in selection range. @@ -1026,9 +1034,9 @@ Vector<Vector2> TextServer::shaped_text_get_selection(const RID &p_shaped, int64 } real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start); if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { - ranges.push_back(Vector2(off, off + char_adv * (glyphs[i].end - start))); + _push_range(ranges, off, off + char_adv * (glyphs[i].end - start)); } else { - ranges.push_back(Vector2(off + char_adv * (start - glyphs[i].start), off + advance)); + _push_range(ranges, off + char_adv * (start - glyphs[i].start), off + advance); } } // Selection range is within grapheme. @@ -1039,9 +1047,9 @@ Vector<Vector2> TextServer::shaped_text_get_selection(const RID &p_shaped, int64 } real_t char_adv = advance / (real_t)(glyphs[i].end - glyphs[i].start); if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { - ranges.push_back(Vector2(off + char_adv * (glyphs[i].end - end), off + char_adv * (glyphs[i].end - start))); + _push_range(ranges, off + char_adv * (glyphs[i].end - end), off + char_adv * (glyphs[i].end - start)); } else { - ranges.push_back(Vector2(off + char_adv * (start - glyphs[i].start), off + char_adv * (end - glyphs[i].start))); + _push_range(ranges, off + char_adv * (start - glyphs[i].start), off + char_adv * (end - glyphs[i].start)); } } } @@ -1050,25 +1058,6 @@ Vector<Vector2> TextServer::shaped_text_get_selection(const RID &p_shaped, int64 } } - // Merge intersecting ranges. - int i = 0; - while (i < ranges.size()) { - i++; - } - i = 0; - while (i < ranges.size()) { - int j = i + 1; - while (j < ranges.size()) { - if (Math::is_equal_approx(ranges[i].y, ranges[j].x, (real_t)UNIT_EPSILON)) { - ranges.write[i].y = ranges[j].y; - ranges.remove_at(j); - continue; - } - j++; - } - i++; - } - return ranges; } diff --git a/tests/SCsub b/tests/SCsub index 25b06f2312..c59ce69b92 100644 --- a/tests/SCsub +++ b/tests/SCsub @@ -18,11 +18,6 @@ if env_tests["platform"] == "windows": if env_tests.msvc: env_tests.Append(CCFLAGS=["/bigobj"]) -env_tests.add_source_files(env.tests_sources, "core/*.cpp") -env_tests.add_source_files(env.tests_sources, "core/math/*.cpp") -env_tests.add_source_files(env.tests_sources, "core/templates/*.cpp") -env_tests.add_source_files(env.tests_sources, "scene/*.cpp") -env_tests.add_source_files(env.tests_sources, "servers/*.cpp") env_tests.add_source_files(env.tests_sources, "*.cpp") lib = env_tests.add_library("tests", env.tests_sources) diff --git a/tests/core/io/test_config_file.h b/tests/core/io/test_config_file.h index 6e393c7a2d..355aca479e 100644 --- a/tests/core/io/test_config_file.h +++ b/tests/core/io/test_config_file.h @@ -155,7 +155,7 @@ antiAliasing=false "a=b"=7 )"); - FileAccessRef file = FileAccess::open(config_path, FileAccess::READ); + Ref<FileAccess> file = FileAccess::open(config_path, FileAccess::READ); CHECK_MESSAGE(file->get_as_utf8_string() == contents, "The saved configuration file should match the expected format."); } diff --git a/tests/core/io/test_file_access.h b/tests/core/io/test_file_access.h index eee57048cf..f0e1cceacf 100644 --- a/tests/core/io/test_file_access.h +++ b/tests/core/io/test_file_access.h @@ -38,7 +38,7 @@ namespace TestFileAccess { TEST_CASE("[FileAccess] CSV read") { - FileAccessRef f = FileAccess::open(TestUtils::get_data_path("translations.csv"), FileAccess::READ); + Ref<FileAccess> f = FileAccess::open(TestUtils::get_data_path("translations.csv"), FileAccess::READ); Vector<String> header = f->get_csv_line(); // Default delimiter: ",". REQUIRE(header.size() == 3); @@ -77,8 +77,6 @@ TEST_CASE("[FileAccess] CSV read") { CHECK(row5[0] == "What about"); CHECK(row5[1] == "tab separated"); CHECK(row5[2] == "lines, good?"); - - f->close(); } } // namespace TestFileAccess diff --git a/tests/core/io/test_image.h b/tests/core/io/test_image.h index dcf21dd7b0..1c778c3228 100644 --- a/tests/core/io/test_image.h +++ b/tests/core/io/test_image.h @@ -106,7 +106,7 @@ TEST_CASE("[Image] Saving and loading") { // Load BMP Ref<Image> image_bmp = memnew(Image()); - FileAccessRef f_bmp = FileAccess::open(TestUtils::get_data_path("images/icon.bmp"), FileAccess::READ, &err); + Ref<FileAccess> f_bmp = FileAccess::open(TestUtils::get_data_path("images/icon.bmp"), FileAccess::READ, &err); PackedByteArray data_bmp; data_bmp.resize(f_bmp->get_length() + 1); f_bmp->get_buffer(data_bmp.ptrw(), f_bmp->get_length()); @@ -116,7 +116,7 @@ TEST_CASE("[Image] Saving and loading") { // Load JPG Ref<Image> image_jpg = memnew(Image()); - FileAccessRef f_jpg = FileAccess::open(TestUtils::get_data_path("images/icon.jpg"), FileAccess::READ, &err); + Ref<FileAccess> f_jpg = FileAccess::open(TestUtils::get_data_path("images/icon.jpg"), FileAccess::READ, &err); PackedByteArray data_jpg; data_jpg.resize(f_jpg->get_length() + 1); f_jpg->get_buffer(data_jpg.ptrw(), f_jpg->get_length()); @@ -126,7 +126,7 @@ TEST_CASE("[Image] Saving and loading") { // Load WEBP Ref<Image> image_webp = memnew(Image()); - FileAccessRef f_webp = FileAccess::open(TestUtils::get_data_path("images/icon.webp"), FileAccess::READ, &err); + Ref<FileAccess> f_webp = FileAccess::open(TestUtils::get_data_path("images/icon.webp"), FileAccess::READ, &err); PackedByteArray data_webp; data_webp.resize(f_webp->get_length() + 1); f_webp->get_buffer(data_webp.ptrw(), f_webp->get_length()); @@ -136,7 +136,7 @@ TEST_CASE("[Image] Saving and loading") { // Load PNG Ref<Image> image_png = memnew(Image()); - FileAccessRef f_png = FileAccess::open(TestUtils::get_data_path("images/icon.png"), FileAccess::READ, &err); + Ref<FileAccess> f_png = FileAccess::open(TestUtils::get_data_path("images/icon.png"), FileAccess::READ, &err); PackedByteArray data_png; data_png.resize(f_png->get_length() + 1); f_png->get_buffer(data_png.ptrw(), f_png->get_length()); @@ -146,7 +146,7 @@ TEST_CASE("[Image] Saving and loading") { // Load TGA Ref<Image> image_tga = memnew(Image()); - FileAccessRef f_tga = FileAccess::open(TestUtils::get_data_path("images/icon.tga"), FileAccess::READ, &err); + Ref<FileAccess> f_tga = FileAccess::open(TestUtils::get_data_path("images/icon.tga"), FileAccess::READ, &err); PackedByteArray data_tga; data_tga.resize(f_tga->get_length() + 1); f_tga->get_buffer(data_tga.ptrw(), f_tga->get_length()); diff --git a/tests/core/io/test_pck_packer.h b/tests/core/io/test_pck_packer.h index 95adca6d68..d21fbdaf50 100644 --- a/tests/core/io/test_pck_packer.h +++ b/tests/core/io/test_pck_packer.h @@ -52,7 +52,7 @@ TEST_CASE("[PCKPacker] Pack an empty PCK file") { "Flushing the PCK should return an OK error code."); Error err; - FileAccessRef f = FileAccess::open(output_pck_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(output_pck_path, FileAccess::READ, &err); CHECK_MESSAGE( err == OK, "The generated empty PCK file should be opened successfully."); @@ -106,7 +106,7 @@ TEST_CASE("[PCKPacker] Pack a PCK file with some files and directories") { "Flushing the PCK should return an OK error code."); Error err; - FileAccessRef f = FileAccess::open(output_pck_path, FileAccess::READ, &err); + Ref<FileAccess> f = FileAccess::open(output_pck_path, FileAccess::READ, &err); CHECK_MESSAGE( err == OK, "The generated non-empty PCK file should be opened successfully."); diff --git a/tests/core/math/test_math.cpp b/tests/core/math/test_math.cpp deleted file mode 100644 index 4182455b7a..0000000000 --- a/tests/core/math/test_math.cpp +++ /dev/null @@ -1,690 +0,0 @@ -/*************************************************************************/ -/* test_math.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "test_math.h" - -#include "core/math/camera_matrix.h" -#include "core/math/delaunay_3d.h" -#include "core/math/geometry_2d.h" -#include "core/os/main_loop.h" -#include "core/os/os.h" - -namespace TestMath { - -class GetClassAndNamespace { - String code; - int idx; - int line; - String error_str; - bool error; - Variant value; - - String class_name; - - enum Token { - TK_BRACKET_OPEN, - TK_BRACKET_CLOSE, - TK_CURLY_BRACKET_OPEN, - TK_CURLY_BRACKET_CLOSE, - TK_PERIOD, - TK_COLON, - TK_COMMA, - TK_SYMBOL, - TK_IDENTIFIER, - TK_STRING, - TK_NUMBER, - TK_EOF, - TK_ERROR - }; - - Token get_token() { - while (true) { - switch (code[idx]) { - case '\n': { - line++; - idx++; - break; - }; - case 0: { - return TK_EOF; - - } break; - case '{': { - idx++; - return TK_CURLY_BRACKET_OPEN; - }; - case '}': { - idx++; - return TK_CURLY_BRACKET_CLOSE; - }; - case '[': { - idx++; - return TK_BRACKET_OPEN; - }; - case ']': { - idx++; - return TK_BRACKET_CLOSE; - }; - case ':': { - idx++; - return TK_COLON; - }; - case ',': { - idx++; - return TK_COMMA; - }; - case '.': { - idx++; - return TK_PERIOD; - }; - case '#': { - //compiler directive - while (code[idx] != '\n' && code[idx] != 0) { - idx++; - } - continue; - } break; - case '/': { - switch (code[idx + 1]) { - case '*': { // block comment - - idx += 2; - while (true) { - if (code[idx] == 0) { - error_str = "Unterminated comment"; - error = true; - return TK_ERROR; - } else if (code[idx] == '*' && code[idx + 1] == '/') { - idx += 2; - break; - } else if (code[idx] == '\n') { - line++; - } - - idx++; - } - - } break; - case '/': { // line comment skip - - while (code[idx] != '\n' && code[idx] != 0) { - idx++; - } - - } break; - default: { - value = "/"; - idx++; - return TK_SYMBOL; - } - } - - continue; // a comment - } break; - case '\'': - case '"': { - char32_t begin_str = code[idx]; - idx++; - String tk_string = String(); - while (true) { - if (code[idx] == 0) { - error_str = "Unterminated String"; - error = true; - return TK_ERROR; - } else if (code[idx] == begin_str) { - idx++; - break; - } else if (code[idx] == '\\') { - //escaped characters... - idx++; - char32_t next = code[idx]; - if (next == 0) { - error_str = "Unterminated String"; - error = true; - return TK_ERROR; - } - char32_t res = 0; - - switch (next) { - case 'b': - res = 8; - break; - case 't': - res = 9; - break; - case 'n': - res = 10; - break; - case 'f': - res = 12; - break; - case 'r': - res = 13; - break; - case '\"': - res = '\"'; - break; - case '\\': - res = '\\'; - break; - default: { - res = next; - } break; - } - - tk_string += res; - - } else { - if (code[idx] == '\n') { - line++; - } - tk_string += code[idx]; - } - idx++; - } - - value = tk_string; - - return TK_STRING; - - } break; - default: { - if (code[idx] <= 32) { - idx++; - break; - } - - if ((code[idx] >= 33 && code[idx] <= 47) || (code[idx] >= 58 && code[idx] <= 64) || (code[idx] >= 91 && code[idx] <= 96) || (code[idx] >= 123 && code[idx] <= 127)) { - value = String::chr(code[idx]); - idx++; - return TK_SYMBOL; - } - - if (code[idx] == '-' || is_digit(code[idx])) { - //a number - const char32_t *rptr; - double number = String::to_float(&code[idx], &rptr); - idx += (rptr - &code[idx]); - value = number; - return TK_NUMBER; - - } else if (is_ascii_char(code[idx]) || code[idx] > 127) { - String id; - - while (is_ascii_char(code[idx]) || code[idx] > 127) { - id += code[idx]; - idx++; - } - - value = id; - return TK_IDENTIFIER; - } else { - error_str = "Unexpected character."; - error = true; - return TK_ERROR; - } - } - } - } - } - -public: - Error parse(const String &p_code, const String &p_known_class_name = String()) { - code = p_code; - idx = 0; - line = 0; - error_str = String(); - error = false; - value = Variant(); - class_name = String(); - - bool use_next_class = false; - Token tk = get_token(); - - Map<int, String> namespace_stack; - int curly_stack = 0; - - while (!error || tk != TK_EOF) { - if (tk == TK_BRACKET_OPEN) { - tk = get_token(); - if (tk == TK_IDENTIFIER && String(value) == "ScriptClass") { - if (get_token() == TK_BRACKET_CLOSE) { - use_next_class = true; - } - } - } else if (tk == TK_IDENTIFIER && String(value) == "class") { - tk = get_token(); - if (tk == TK_IDENTIFIER) { - String name = value; - if (use_next_class || p_known_class_name == name) { - for (const KeyValue<int, String> &E : namespace_stack) { - class_name += E.value + "."; - } - class_name += String(value); - break; - } - } - - } else if (tk == TK_IDENTIFIER && String(value) == "namespace") { - String name; - int at_level = curly_stack; - while (true) { - tk = get_token(); - if (tk == TK_IDENTIFIER) { - name += String(value); - } - - tk = get_token(); - if (tk == TK_PERIOD) { - name += "."; - } else if (tk == TK_CURLY_BRACKET_OPEN) { - curly_stack++; - break; - } else { - break; //whatever else - } - } - - if (!name.is_empty()) { - namespace_stack[at_level] = name; - } - - } else if (tk == TK_CURLY_BRACKET_OPEN) { - curly_stack++; - } else if (tk == TK_CURLY_BRACKET_CLOSE) { - curly_stack--; - if (namespace_stack.has(curly_stack)) { - namespace_stack.erase(curly_stack); - } - } - - tk = get_token(); - } - - if (error) { - return ERR_PARSE_ERROR; - } - - return OK; - } - - String get_error() { - return error_str; - } - - String get_class() { - return class_name; - } -}; - -void test_vec(Plane p_vec) { - CameraMatrix cm; - cm.set_perspective(45, 1, 0, 100); - Plane v0 = cm.xform4(p_vec); - - print_line("out: " + v0); - v0.normal.z = (v0.d / 100.0 * 2.0 - 1.0) * v0.d; - print_line("out_F: " + v0); -} - -uint32_t ihash(uint32_t a) { - a = (a + 0x7ed55d16) + (a << 12); - a = (a ^ 0xc761c23c) ^ (a >> 19); - a = (a + 0x165667b1) + (a << 5); - a = (a + 0xd3a2646c) ^ (a << 9); - a = (a + 0xfd7046c5) + (a << 3); - a = (a ^ 0xb55a4f09) ^ (a >> 16); - return a; -} - -uint32_t ihash2(uint32_t a) { - a = (a ^ 61) ^ (a >> 16); - a = a + (a << 3); - a = a ^ (a >> 4); - a = a * 0x27d4eb2d; - a = a ^ (a >> 15); - return a; -} - -uint32_t ihash3(uint32_t a) { - a = (a + 0x479ab41d) + (a << 8); - a = (a ^ 0xe4aa10ce) ^ (a >> 5); - a = (a + 0x9942f0a6) - (a << 14); - a = (a ^ 0x5aedd67d) ^ (a >> 3); - a = (a + 0x17bea992) + (a << 7); - return a; -} - -MainLoop *test() { - { - Vector<Vector3> points; - points.push_back(Vector3(0, 0, 0)); - points.push_back(Vector3(0, 0, 1)); - points.push_back(Vector3(0, 1, 0)); - points.push_back(Vector3(0, 1, 1)); - points.push_back(Vector3(1, 1, 0)); - points.push_back(Vector3(1, 0, 0)); - points.push_back(Vector3(1, 0, 1)); - points.push_back(Vector3(1, 1, 1)); - - for (int i = 0; i < 800; i++) { - points.push_back(Vector3(Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0, Math::randf() * 2.0 - 1.0) * Vector3(25, 30, 33)); - } - - Vector<Delaunay3D::OutputSimplex> os = Delaunay3D::tetrahedralize(points); - print_line("simplices in the end: " + itos(os.size())); - for (int i = 0; i < os.size(); i++) { - print_line("Simplex " + itos(i) + ": "); - print_line(points[os[i].points[0]]); - print_line(points[os[i].points[1]]); - print_line(points[os[i].points[2]]); - print_line(points[os[i].points[3]]); - } - - { - FileAccessRef f = FileAccess::open("res://bsp.obj", FileAccess::WRITE); - for (int i = 0; i < os.size(); i++) { - f->store_line("o Simplex" + itos(i)); - for (int j = 0; j < 4; j++) { - f->store_line(vformat("v %f %f %f", points[os[i].points[j]].x, points[os[i].points[j]].y, points[os[i].points[j]].z)); - } - static const int face_order[4][3] = { - { 1, 2, 3 }, - { 1, 3, 4 }, - { 1, 2, 4 }, - { 2, 3, 4 } - }; - - for (int j = 0; j < 4; j++) { - f->store_line(vformat("f %d %d %d", 4 * i + face_order[j][0], 4 * i + face_order[j][1], 4 * i + face_order[j][2])); - } - } - f->close(); - } - - return nullptr; - } - - { - float r = 1; - float g = 0.5; - float b = 0.1; - - const float pow2to9 = 512.0f; - const float B = 15.0f; - const float N = 9.0f; - - float sharedexp = 65408.000f; - - float cRed = MAX(0.0f, MIN(sharedexp, r)); - float cGreen = MAX(0.0f, MIN(sharedexp, g)); - float cBlue = MAX(0.0f, MIN(sharedexp, b)); - - float cMax = MAX(cRed, MAX(cGreen, cBlue)); - - float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math_LN2)) + 1.0f + B; - - float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f); - - float exps = expp + 1.0f; - - if (0.0 <= sMax && sMax < pow2to9) { - exps = expp; - } - - float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); - float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); - float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); - - print_line("R: " + rtos(sRed) + " G: " + rtos(sGreen) + " B: " + rtos(sBlue) + " EXP: " + rtos(exps)); - - uint32_t rgbe = (Math::fast_ftoi(sRed) & 0x1FF) | ((Math::fast_ftoi(sGreen) & 0x1FF) << 9) | ((Math::fast_ftoi(sBlue) & 0x1FF) << 18) | ((Math::fast_ftoi(exps) & 0x1F) << 27); - - float rb = rgbe & 0x1ff; - float gb = (rgbe >> 9) & 0x1ff; - float bb = (rgbe >> 18) & 0x1ff; - float eb = (rgbe >> 27); - float mb = Math::pow(2.0, eb - 15.0 - 9.0); - float rd = rb * mb; - float gd = gb * mb; - float bd = bb * mb; - - print_line("RGBE: " + Color(rd, gd, bd)); - } - - Vector<int> ints; - ints.resize(20); - - { - int *w; - w = ints.ptrw(); - for (int i = 0; i < ints.size(); i++) { - w[i] = i; - } - } - - Vector<int> posho = ints; - - { - const int *r = posho.ptr(); - for (int i = 0; i < posho.size(); i++) { - print_line(itos(i) + " : " + itos(r[i])); - } - } - - List<String> cmdlargs = OS::get_singleton()->get_cmdline_args(); - - if (cmdlargs.is_empty()) { - //try editor! - return nullptr; - } - - String test = cmdlargs.back()->get(); - if (test == "math") { - // Not a file name but the test name, abort. - // FIXME: This test is ugly as heck, needs fixing :) - return nullptr; - } - - FileAccess *fa = FileAccess::open(test, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!fa, nullptr, "Could not open file: " + test); - - Vector<uint8_t> buf; - uint64_t flen = fa->get_length(); - buf.resize(fa->get_length() + 1); - fa->get_buffer(buf.ptrw(), flen); - buf.write[flen] = 0; - - String code; - code.parse_utf8((const char *)&buf[0]); - - GetClassAndNamespace getclass; - if (getclass.parse(code)) { - print_line("Parse error: " + getclass.get_error()); - } else { - print_line("Found class: " + getclass.get_class()); - } - - { - Vector<int> hashes; - List<StringName> tl; - ClassDB::get_class_list(&tl); - - for (const StringName &E : tl) { - Vector<uint8_t> m5b = E.operator String().md5_buffer(); - hashes.push_back(hashes.size()); - } - - for (int i = nearest_shift(hashes.size()); i < 20; i++) { - bool success = true; - for (int s = 0; s < 10000; s++) { - Set<uint32_t> existing; - success = true; - - for (int j = 0; j < hashes.size(); j++) { - uint32_t eh = ihash2(ihash3(hashes[j] + ihash(s) + s)) & ((1 << i) - 1); - if (existing.has(eh)) { - success = false; - break; - } - existing.insert(eh); - } - - if (success) { - print_line("success at " + itos(i) + "/" + itos(nearest_shift(hashes.size())) + " shift " + itos(s)); - break; - } - } - if (success) { - break; - } - } - - print_line("DONE"); - } - - { - print_line("NUM: " + itos(-128)); - } - - { - Vector3 v(1, 2, 3); - v.normalize(); - real_t a = 0.3; - - Basis m(v, a); - - Vector3 v2(7, 3, 1); - v2.normalize(); - real_t a2 = 0.8; - - Basis m2(v2, a2); - - Quaternion q = m; - Quaternion q2 = m2; - - Basis m3 = m.inverse() * m2; - Quaternion q3 = (q.inverse() * q2); //.normalized(); - - print_line(Quaternion(m3)); - print_line(q3); - - print_line("before v: " + v + " a: " + rtos(a)); - q.get_axis_angle(v, a); - print_line("after v: " + v + " a: " + rtos(a)); - } - - String ret; - - List<String> args; - args.push_back("-l"); - Error err = OS::get_singleton()->execute("/bin/ls", args, &ret); - print_line("error: " + itos(err)); - print_line(ret); - - Basis m3; - m3.rotate(Vector3(1, 0, 0), 0.2); - m3.rotate(Vector3(0, 1, 0), 1.77); - m3.rotate(Vector3(0, 0, 1), 212); - Basis m32; - m32.set_euler(m3.get_euler()); - print_line("ELEULEEEEEEEEEEEEEEEEEER: " + m3.get_euler() + " vs " + m32.get_euler()); - - { - Dictionary d; - d["momo"] = 1; - Dictionary b = d; - b["44"] = 4; - } - - print_line("inters: " + rtos(Geometry2D::segment_intersects_circle(Vector2(-5, 0), Vector2(-2, 0), Vector2(), 1.0))); - - print_line("cross: " + Vector3(1, 2, 3).cross(Vector3(4, 5, 7))); - print_line("dot: " + rtos(Vector3(1, 2, 3).dot(Vector3(4, 5, 7)))); - print_line("abs: " + Vector3(-1, 2, -3).abs()); - print_line("distance_to: " + rtos(Vector3(1, 2, 3).distance_to(Vector3(4, 5, 7)))); - print_line("distance_squared_to: " + rtos(Vector3(1, 2, 3).distance_squared_to(Vector3(4, 5, 7)))); - print_line("plus: " + (Vector3(1, 2, 3) + Vector3(Vector3(4, 5, 7)))); - print_line("minus: " + (Vector3(1, 2, 3) - Vector3(Vector3(4, 5, 7)))); - print_line("mul: " + (Vector3(1, 2, 3) * Vector3(Vector3(4, 5, 7)))); - print_line("div: " + (Vector3(1, 2, 3) / Vector3(Vector3(4, 5, 7)))); - print_line("mul scalar: " + (Vector3(1, 2, 3) * 2.0)); - print_line("premul scalar: " + (2.0 * Vector3(1, 2, 3))); - print_line("div scalar: " + (Vector3(1, 2, 3) / 3.0)); - print_line("length: " + rtos(Vector3(1, 2, 3).length())); - print_line("length squared: " + rtos(Vector3(1, 2, 3).length_squared())); - print_line("normalized: " + Vector3(1, 2, 3).normalized()); - print_line("inverse: " + Vector3(1, 2, 3).inverse()); - - { - Vector3 v(4, 5, 7); - v.normalize(); - print_line("normalize: " + v); - } - - { - Vector3 v(4, 5, 7); - v += Vector3(1, 2, 3); - print_line("+=: " + v); - } - - { - Vector3 v(4, 5, 7); - v -= Vector3(1, 2, 3); - print_line("-=: " + v); - } - - { - Vector3 v(4, 5, 7); - v *= Vector3(1, 2, 3); - print_line("*=: " + v); - } - - { - Vector3 v(4, 5, 7); - v /= Vector3(1, 2, 3); - print_line("/=: " + v); - } - - { - Vector3 v(4, 5, 7); - v *= 2.0; - print_line("scalar *=: " + v); - } - - { - Vector3 v(4, 5, 7); - v /= 2.0; - print_line("scalar /=: " + v); - } - - return nullptr; -} -} // namespace TestMath diff --git a/tests/core/math/test_math.h b/tests/core/math/test_math.h deleted file mode 100644 index a8aa8f6847..0000000000 --- a/tests/core/math/test_math.h +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************/ -/* test_math.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TEST_MATH_H -#define TEST_MATH_H - -class MainLoop; - -namespace TestMath { - -MainLoop *test(); -} - -#endif diff --git a/tests/core/templates/test_oa_hash_map.cpp b/tests/core/templates/test_oa_hash_map.cpp deleted file mode 100644 index 87bf9feb83..0000000000 --- a/tests/core/templates/test_oa_hash_map.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/*************************************************************************/ -/* test_oa_hash_map.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "test_oa_hash_map.h" - -#include "core/os/os.h" -#include "core/templates/oa_hash_map.h" - -namespace TestOAHashMap { - -struct CountedItem { - static int count; - - int id = -1; - bool destroyed = false; - - CountedItem() { - count++; - } - - CountedItem(int p_id) : - id(p_id) { - count++; - } - - CountedItem(const CountedItem &p_other) : - id(p_other.id) { - count++; - } - - void operator=(const CountedItem &p_other) { - id = p_other.id; - count++; - } - - ~CountedItem() { - CRASH_COND(destroyed); - count--; - destroyed = true; - } -}; - -int CountedItem::count; - -MainLoop *test() { - OS::get_singleton()->print("\n\n\nHello from test\n"); - - // test element tracking. - { - OAHashMap<int, int> map; - - map.set(42, 1337); - map.set(1337, 21); - map.set(42, 11880); - - int value = 0; - map.lookup(42, value); - - OS::get_singleton()->print("capacity %d\n", map.get_capacity()); - OS::get_singleton()->print("elements %d\n", map.get_num_elements()); - - OS::get_singleton()->print("map[42] = %d\n", value); - } - - // rehashing and deletion - { - OAHashMap<int, int> map; - - for (int i = 0; i < 500; i++) { - map.set(i, i * 2); - } - - for (int i = 0; i < 500; i += 2) { - map.remove(i); - } - - uint32_t num_elems = 0; - for (int i = 0; i < 500; i++) { - int tmp; - if (map.lookup(i, tmp) && tmp == i * 2) { - num_elems++; - } - } - - OS::get_singleton()->print("elements %d == %d.\n", map.get_num_elements(), num_elems); - } - - // iteration - { - OAHashMap<String, int> map; - - map.set("Hello", 1); - map.set("World", 2); - map.set("Godot rocks", 42); - - for (OAHashMap<String, int>::Iterator it = map.iter(); it.valid; it = map.next_iter(it)) { - OS::get_singleton()->print("map[\"%s\"] = %d\n", it.key->utf8().get_data(), *it.value); - } - } - - // stress test / test for issue #22928 - { - OAHashMap<int, int> map; - int dummy = 0; - const int N = 1000; - uint32_t *keys = new uint32_t[N]; - - Math::seed(0); - - // insert a couple of random keys (with a dummy value, which is ignored) - for (int i = 0; i < N; i++) { - keys[i] = Math::rand(); - map.set(keys[i], dummy); - - if (!map.lookup(keys[i], dummy)) { - OS::get_singleton()->print("could not find 0x%X despite it was just inserted!\n", unsigned(keys[i])); - } - } - - // check whether the keys are still present - for (int i = 0; i < N; i++) { - if (!map.lookup(keys[i], dummy)) { - OS::get_singleton()->print("could not find 0x%X despite it has been inserted previously! (not checking the other keys, breaking...)\n", unsigned(keys[i])); - break; - } - } - - delete[] keys; - } - - // regression test / test for issue related to #31402 - { - OS::get_singleton()->print("test for issue #31402 started...\n"); - - const int num_test_values = 12; - int test_values[num_test_values] = { 0, 24, 48, 72, 96, 120, 144, 168, 192, 216, 240, 264 }; - - int dummy = 0; - OAHashMap<int, int> map; - map.clear(); - - for (int i = 0; i < num_test_values; ++i) { - map.set(test_values[i], dummy); - } - - OS::get_singleton()->print("test for issue #31402 passed.\n"); - } - - // test collision resolution, should not crash or run indefinitely - { - OAHashMap<int, int> map(4); - map.set(1, 1); - map.set(5, 1); - map.set(9, 1); - map.set(13, 1); - map.remove(5); - map.remove(9); - map.remove(13); - map.set(5, 1); - } - - // test memory management of items, should not crash or leak items - { - // Exercise different patterns of removal - for (int i = 0; i < 4; ++i) { - { - OAHashMap<String, CountedItem> map; - int id = 0; - for (int j = 0; j < 100; ++j) { - map.insert(itos(j), CountedItem(id)); - } - if (i <= 1) { - for (int j = 0; j < 100; ++j) { - map.remove(itos(j)); - } - } - if (i % 2 == 0) { - map.clear(); - } - } - - if (CountedItem::count != 0) { - OS::get_singleton()->print("%d != 0 (not performing the other test sub-cases, breaking...)\n", CountedItem::count); - break; - } - } - } - - // Test map with 0 capacity. - { - OAHashMap<int, String> original_map(0); - original_map.set(1, "1"); - OS::get_singleton()->print("OAHashMap 0 capacity initialization passed.\n"); - } - - // Test copy constructor. - { - OAHashMap<int, String> original_map; - original_map.set(1, "1"); - original_map.set(2, "2"); - original_map.set(3, "3"); - original_map.set(4, "4"); - original_map.set(5, "5"); - - OAHashMap<int, String> map_copy(original_map); - - bool pass = true; - for ( - OAHashMap<int, String>::Iterator it = original_map.iter(); - it.valid; - it = original_map.next_iter(it)) { - if (map_copy.lookup_ptr(*it.key) == nullptr) { - pass = false; - } - if (*it.value != *map_copy.lookup_ptr(*it.key)) { - pass = false; - } - } - if (pass) { - OS::get_singleton()->print("OAHashMap copy constructor test passed.\n"); - } else { - OS::get_singleton()->print("OAHashMap copy constructor test FAILED.\n"); - } - - map_copy.set(1, "Random String"); - if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) { - OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test FAILED.\n"); - } else { - OS::get_singleton()->print("OAHashMap copy constructor, atomic copy test passed.\n"); - } - } - - // Test assign operator. - { - OAHashMap<int, String> original_map; - original_map.set(1, "1"); - original_map.set(2, "2"); - original_map.set(3, "3"); - original_map.set(4, "4"); - original_map.set(5, "5"); - - OAHashMap<int, String> map_copy(100000); - map_copy.set(1, "Just a string."); - map_copy = original_map; - - bool pass = true; - for ( - OAHashMap<int, String>::Iterator it = map_copy.iter(); - it.valid; - it = map_copy.next_iter(it)) { - if (original_map.lookup_ptr(*it.key) == nullptr) { - pass = false; - } - if (*it.value != *original_map.lookup_ptr(*it.key)) { - pass = false; - } - } - if (pass) { - OS::get_singleton()->print("OAHashMap assign operation test passed.\n"); - } else { - OS::get_singleton()->print("OAHashMap assign operation test FAILED.\n"); - } - - map_copy.set(1, "Random String"); - if (*map_copy.lookup_ptr(1) == *original_map.lookup_ptr(1)) { - OS::get_singleton()->print("OAHashMap assign operation atomic copy test FAILED.\n"); - } else { - OS::get_singleton()->print("OAHashMap assign operation atomic copy test passed.\n"); - } - } - - return nullptr; -} -} // namespace TestOAHashMap diff --git a/tests/scene/test_gui.cpp b/tests/scene/test_gui.cpp deleted file mode 100644 index cd5624b70c..0000000000 --- a/tests/scene/test_gui.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/*************************************************************************/ -/* test_gui.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef _3D_DISABLED - -#include "test_gui.h" - -#include "scene/gui/button.h" -#include "scene/gui/label.h" -#include "scene/gui/line_edit.h" -#include "scene/gui/menu_button.h" -#include "scene/gui/option_button.h" -#include "scene/gui/panel.h" -#include "scene/gui/progress_bar.h" -#include "scene/gui/rich_text_label.h" -#include "scene/gui/scroll_bar.h" -#include "scene/gui/spin_box.h" -#include "scene/gui/tab_container.h" -#include "scene/gui/tree.h" - -namespace TestGUI { - -class TestMainLoop : public SceneTree { -public: - virtual void request_quit() { - quit(); - } - virtual void initialize() { - SceneTree::initialize(); - - Panel *frame = memnew(Panel); - frame->set_anchor(SIDE_RIGHT, Control::ANCHOR_END); - frame->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END); - frame->set_end(Point2(0, 0)); - - Ref<Theme> t = memnew(Theme); - frame->set_theme(t); - - get_root()->add_child(frame); - - Label *label = memnew(Label); - - label->set_position(Point2(80, 90)); - label->set_size(Point2(170, 80)); - label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_FILL); - label->set_text("There was once upon a time a beautiful unicorn that loved to play with little girls..."); - - frame->add_child(label); - - Button *button = memnew(Button); - - button->set_position(Point2(20, 20)); - button->set_size(Point2(1, 1)); - button->set_text("This is a biggie button"); - - frame->add_child(button); - - Tree *tree = memnew(Tree); - tree->set_columns(2); - - tree->set_position(Point2(230, 210)); - tree->set_size(Point2(150, 250)); - - TreeItem *item = tree->create_item(); - item->set_editable(0, true); - item->set_text(0, "root"); - item = tree->create_item(tree->get_root()); - item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - item->set_editable(0, true); - item->set_text(0, "check"); - item->set_cell_mode(1, TreeItem::CELL_MODE_CHECK); - item->set_editable(1, true); - item->set_text(1, "check2"); - item = tree->create_item(tree->get_root()); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0, true); - item->set_range_config(0, 0, 20, 0.1); - item->set_range(0, 2); - item->add_button(0, Theme::get_default()->get_icon("folder", "FileDialog")); - item->set_cell_mode(1, TreeItem::CELL_MODE_RANGE); - item->set_editable(1, true); - item->set_range_config(1, 0, 20, 0.1); - item->set_range(1, 3); - - item = tree->create_item(tree->get_root()); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0, true); - item->set_text(0, "Have,Many,Several,Options!"); - item->set_range(0, 2); - - item = tree->create_item(item); - item->set_editable(0, true); - item->set_text(0, "Gershwin!"); - - frame->add_child(tree); - - LineEdit *line_edit = memnew(LineEdit); - - line_edit->set_position(Point2(30, 190)); - line_edit->set_size(Point2(180, 1)); - - frame->add_child(line_edit); - - HScrollBar *hscroll = memnew(HScrollBar); - - hscroll->set_position(Point2(30, 290)); - hscroll->set_size(Point2(180, 1)); - hscroll->set_max(10); - hscroll->set_page(4); - - frame->add_child(hscroll); - - SpinBox *spin = memnew(SpinBox); - - spin->set_position(Point2(30, 260)); - spin->set_size(Point2(120, 1)); - - frame->add_child(spin); - hscroll->share(spin); - - ProgressBar *progress = memnew(ProgressBar); - - progress->set_position(Point2(30, 330)); - progress->set_size(Point2(120, 1)); - - frame->add_child(progress); - hscroll->share(progress); - - MenuButton *menu_button = memnew(MenuButton); - - menu_button->set_text("I'm a menu!"); - menu_button->set_position(Point2(30, 380)); - menu_button->set_size(Point2(1, 1)); - - frame->add_child(menu_button); - - PopupMenu *popup = menu_button->get_popup(); - - popup->add_item("Hello, testing"); - popup->add_item("My Dearest"); - popup->add_separator(); - popup->add_item("Popup"); - popup->add_check_item("Check Popup"); - popup->set_item_checked(4, true); - popup->add_separator(); - popup->add_radio_check_item("Option A"); - popup->set_item_checked(6, true); - popup->add_radio_check_item("Option B"); - - OptionButton *options = memnew(OptionButton); - - options->add_item("Hello, testing"); - options->add_item("My Dearest"); - - options->set_position(Point2(230, 180)); - options->set_size(Point2(1, 1)); - - frame->add_child(options); - - RichTextLabel *richtext = memnew(RichTextLabel); - - richtext->set_position(Point2(600, 210)); - richtext->set_size(Point2(180, 250)); - richtext->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -20); - - frame->add_child(richtext); - - richtext->add_text("Hello, My Friends!\n\nWelcome to the amazing world of "); - - richtext->add_newline(); - richtext->add_newline(); - - richtext->push_color(Color(1, 0.5, 0.5)); - richtext->add_text("leprechauns"); - richtext->pop(); - - richtext->add_text(" and "); - richtext->push_color(Color(0, 1.0, 0.5)); - richtext->add_text("faeries.\n"); - richtext->pop(); - richtext->add_text("In this new episode, we will attempt to "); - richtext->push_font(richtext->get_theme_font(SNAME("mono_font"), SNAME("Fonts"))); - richtext->push_color(Color(0.7, 0.5, 1.0)); - richtext->add_text("deliver something nice"); - richtext->pop(); - richtext->pop(); - richtext->add_text(" to all the viewers! Unfortunately, I need to "); - richtext->push_underline(); - richtext->add_text("keep writing a lot of text"); - richtext->pop(); - richtext->add_text(" so the label control overflows and the scrollbar appears.\n"); - richtext->push_meta("http://www.scrollingcapabilities.xz"); - richtext->add_text("This allows to test for the scrolling capabilities "); - richtext->pop(); - richtext->add_text("of the rich text label for huge text (not like this text will really be huge but, you know).\nAs long as it is so long that it will work nicely for a test/demo, then it's welcomed in my book...\nChanging subject, the day is cloudy today and I'm wondering if I'll get che chance to travel somewhere nice. Sometimes, watching the clouds from satellite images may give a nice insight about how pressure zones in our planet work, although it also makes it pretty obvious to see why most weather forecasts get it wrong so often.\nClouds are so difficult to predict!\nBut it's pretty cool how our civilization has adapted to having water falling from the sky each time it rains..."); - - TabContainer *tabc = memnew(TabContainer); - - Control *ctl = memnew(Control); - ctl->set_name("tab 1"); - tabc->add_child(ctl); - - ctl = memnew(Control); - ctl->set_name("tab 2"); - tabc->add_child(ctl); - label = memnew(Label); - label->set_text("Some Label"); - label->set_position(Point2(20, 20)); - ctl->add_child(label); - - ctl = memnew(Control); - ctl->set_name("tab 3"); - button = memnew(Button); - button->set_text("Some Button"); - button->set_position(Point2(30, 50)); - ctl->add_child(button); - - tabc->add_child(ctl); - - frame->add_child(tabc); - - tabc->set_position(Point2(400, 210)); - tabc->set_size(Point2(180, 250)); - } -}; - -MainLoop *test() { - return memnew(TestMainLoop); -} -} // namespace TestGUI - -#endif // _3D_DISABLED diff --git a/tests/servers/test_physics_2d.cpp b/tests/servers/test_physics_2d.cpp deleted file mode 100644 index 138412ec09..0000000000 --- a/tests/servers/test_physics_2d.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/*************************************************************************/ -/* test_physics_2d.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "test_physics_2d.h" - -#include "core/os/main_loop.h" -#include "servers/physics_server_2d.h" -#include "servers/rendering_server.h" - -static const unsigned char convex_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0xaa, 0x69, 0x71, 0xde, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf9, 0x43, 0xbb, 0x7f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xdb, 0x6, 0xa, 0x3, 0x13, 0x31, 0x66, 0xa7, 0xac, 0x79, 0x0, 0x0, 0x4, 0xef, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0x9b, 0xdd, 0x4e, 0x2a, 0x57, 0x14, 0xc7, 0xf7, 0x1e, 0xc0, 0x19, 0x38, 0x32, 0x80, 0xa, 0x6a, 0xda, 0x18, 0xa3, 0xc6, 0x47, 0x50, 0x7b, 0xa1, 0xd9, 0x36, 0x27, 0x7e, 0x44, 0xed, 0x45, 0x4d, 0x93, 0x3e, 0x40, 0x1f, 0x64, 0x90, 0xf4, 0x1, 0xbc, 0xf0, 0xc2, 0x9c, 0x57, 0x30, 0x4d, 0xbc, 0xa8, 0x6d, 0xc, 0x69, 0x26, 0xb5, 0x68, 0x8b, 0x35, 0x7e, 0x20, 0xb4, 0xf5, 0x14, 0xbf, 0x51, 0x3c, 0x52, 0xe, 0xc, 0xe, 0xc8, 0xf0, 0xb1, 0x7a, 0x51, 0x3d, 0xb1, 0x9e, 0x19, 0x1c, 0x54, 0x70, 0x1c, 0xdc, 0x9, 0x17, 0x64, 0x8, 0xc9, 0xff, 0xb7, 0xd6, 0x7f, 0xcd, 0x3f, 0x2b, 0xd9, 0x8, 0xbd, 0x9c, 0xda, 0x3e, 0xf8, 0x31, 0xff, 0xc, 0x0, 0x8, 0x42, 0x88, 0x9c, 0x9f, 0x9f, 0xbf, 0xa, 0x87, 0xc3, 0xad, 0x7d, 0x7d, 0x7d, 0x7f, 0x23, 0x84, 0x78, 0x8c, 0x31, 0xaf, 0x55, 0x0, 0xc6, 0xc7, 0x14, 0x1e, 0x8f, 0xc7, 0xbf, 0x38, 0x3c, 0x3c, 0x6c, 0x9b, 0x9f, 0x9f, 0x6f, 0xb8, 0x82, 0x9b, 0xee, 0xe8, 0xe8, 0xf8, 0x12, 0x0, 0xbe, 0xd3, 0x2a, 0x8, 0xfc, 0x50, 0xd1, 0xf9, 0x7c, 0x9e, 0x8a, 0x46, 0xa3, 0x5f, 0x9d, 0x9e, 0x9e, 0x7e, 0xb2, 0xb0, 0xb0, 0x60, 0xe5, 0x79, 0x1e, 0xf1, 0xfc, 0x7f, 0x3a, 0x9, 0x21, 0x88, 0x10, 0x82, 0x26, 0x26, 0x26, 0xde, 0x77, 0x75, 0x75, 0x85, 0x59, 0x96, 0xfd, 0x5e, 0x6b, 0x20, 0xf0, 0x7d, 0x85, 0x4b, 0x92, 0xf4, 0xfa, 0xe0, 0xe0, 0xe0, 0xd3, 0xb9, 0xb9, 0xb9, 0x46, 0x49, 0x92, 0xea, 0x6f, 0xa, 0xbf, 0x7d, 0x8, 0x21, 0x68, 0x70, 0x70, 0xb0, 0x38, 0x39, 0x39, 0x79, 0xd6, 0xd9, 0xd9, 0xb9, 0xcf, 0x30, 0xcc, 0xa2, 0xd6, 0xad, 0x21, 0x2b, 0x1c, 0x0, 0x38, 0x41, 0x10, 0xfc, 0xdb, 0xdb, 0xdb, 0x27, 0x1e, 0x8f, 0x27, 0x4b, 0x8, 0x1, 0x84, 0x90, 0xea, 0xf, 0x21, 0x4, 0x3c, 0x1e, 0x4f, 0x76, 0x67, 0x67, 0x67, 0x3f, 0x9f, 0xcf, 0xff, 0x7c, 0x5, 0xf3, 0xd9, 0x0, 0xe0, 0x2, 0x81, 0xc0, 0xa9, 0xdb, 0xed, 0x2e, 0x94, 0x2b, 0x5c, 0xe, 0xc4, 0xca, 0xca, 0x8a, 0x18, 0x8d, 0x46, 0x3, 0x0, 0xc0, 0x69, 0x1e, 0x4, 0x0, 0x90, 0x48, 0x24, 0x12, 0xe4, 0x38, 0xee, 0x41, 0xc2, 0x6f, 0x43, 0xe0, 0x38, 0xe, 0xfc, 0x7e, 0xbf, 0x10, 0x8b, 0xc5, 0xd6, 0x35, 0xd, 0x22, 0x9b, 0xcd, 0x7a, 0x96, 0x97, 0x97, 0x33, 0xf, 0xad, 0x7c, 0x29, 0x10, 0x9b, 0x9b, 0x9b, 0xef, 0x2e, 0x2e, 0x2e, 0x7e, 0xd5, 0x1c, 0x8, 0x0, 0x20, 0xe1, 0x70, 0x38, 0xfc, 0x98, 0xd5, 0x57, 0x2, 0xe1, 0x76, 0xbb, 0xf3, 0xa1, 0x50, 0xe8, 0x38, 0x9b, 0xcd, 0xfe, 0xa2, 0x9, 0x8, 0x0, 0x40, 0x2e, 0x2f, 0x2f, 0x7d, 0x4b, 0x4b, 0x4b, 0xb9, 0x4a, 0x54, 0x5f, 0x9, 0xc4, 0xd2, 0xd2, 0x92, 0xb4, 0xb7, 0xb7, 0xf7, 0x36, 0x97, 0xcb, 0x4d, 0x3d, 0x29, 0x8, 0x0, 0xe0, 0x42, 0xa1, 0xd0, 0x71, 0xb5, 0xc4, 0xdf, 0xb6, 0xc5, 0x93, 0xe, 0x4a, 0x0, 0x20, 0xa9, 0x54, 0xea, 0x37, 0xb7, 0xdb, 0x5d, 0xa8, 0xa6, 0x78, 0x39, 0x10, 0x6b, 0x6b, 0x6b, 0xf1, 0x64, 0x32, 0xb9, 0x5a, 0x55, 0x10, 0x0, 0xc0, 0x6d, 0x6c, 0x6c, 0x9c, 0x57, 0xbb, 0xfa, 0x25, 0x40, 0x14, 0x3, 0x81, 0x40, 0x34, 0x93, 0xc9, 0x2c, 0x57, 0x1c, 0x4, 0x0, 0x90, 0x58, 0x2c, 0xb6, 0x5e, 0xe9, 0xc1, 0x77, 0x1f, 0x10, 0x53, 0x53, 0x53, 0x52, 0xc5, 0x83, 0x14, 0x0, 0x70, 0x7e, 0xbf, 0x5f, 0xd0, 0x42, 0xf5, 0x95, 0x40, 0xf8, 0x7c, 0xbe, 0xcb, 0xa3, 0xa3, 0xa3, 0x3f, 0x1e, 0xbd, 0x1b, 0x0, 0x80, 0x1c, 0x1f, 0x1f, 0x87, 0xb4, 0x56, 0xfd, 0xaa, 0x5, 0x29, 0x51, 0x14, 0xbf, 0xf5, 0xf9, 0x7c, 0x97, 0x5a, 0xad, 0xbe, 0x12, 0x88, 0xf5, 0xf5, 0xf5, 0xd8, 0x83, 0x83, 0x54, 0xb5, 0x42, 0x8f, 0x66, 0x83, 0x94, 0xd6, 0xbd, 0x5f, 0xce, 0x7c, 0x38, 0x3c, 0x3c, 0xfc, 0xb3, 0x50, 0x28, 0xb8, 0xcb, 0x2, 0x1, 0x0, 0xdc, 0xf4, 0xf4, 0xf4, 0xfe, 0x73, 0x15, 0x2f, 0x17, 0xa4, 0x22, 0x91, 0x48, 0x50, 0xb5, 0x2d, 0x0, 0x80, 0x9b, 0x99, 0x99, 0x79, 0xfb, 0xdc, 0x1, 0xc8, 0x5, 0xa9, 0x44, 0x22, 0xf1, 0xfb, 0x9d, 0x10, 0x0, 0x80, 0x9b, 0x9d, 0x9d, 0xd, 0xea, 0x5, 0xc0, 0xad, 0xfd, 0x43, 0x1a, 0x0, 0xb8, 0xdb, 0x9a, 0xa9, 0x8f, 0xb6, 0xa4, 0x46, 0xa3, 0xa4, 0xb7, 0xd5, 0x37, 0xcf, 0xf3, 0x68, 0x75, 0x75, 0xf5, 0x4c, 0xee, 0x99, 0x1c, 0x80, 0x9c, 0x1e, 0xf7, 0xff, 0x16, 0x8b, 0x45, 0x50, 0x5, 0xa0, 0xb7, 0xb7, 0xb7, 0x85, 0x10, 0xa2, 0x2b, 0xf1, 0x84, 0x10, 0xd4, 0xdf, 0xdf, 0x6f, 0x57, 0x3, 0x80, 0x37, 0x18, 0xc, 0x5, 0x3d, 0x2, 0xa0, 0x69, 0x3a, 0x8b, 0x10, 0xe2, 0x4b, 0x2, 0xc0, 0x18, 0xf3, 0xc1, 0x60, 0x70, 0x47, 0x8f, 0x16, 0x38, 0x3a, 0x3a, 0x5a, 0x93, 0x5b, 0xc3, 0x7f, 0x64, 0x81, 0xba, 0xba, 0x3a, 0x49, 0x8f, 0x0, 0x1a, 0x1a, 0x1a, 0xd4, 0xcd, 0x0, 0x93, 0xc9, 0xa4, 0xcb, 0x21, 0xe8, 0x74, 0x3a, 0xd5, 0x1, 0xa0, 0x69, 0x5a, 0x77, 0x1d, 0x80, 0x31, 0x2e, 0x38, 0x9d, 0x4e, 0xb1, 0x66, 0x1, 0x30, 0xc, 0x23, 0x28, 0x3d, 0x93, 0x9b, 0x1, 0xb9, 0x9a, 0x6, 0x60, 0x36, 0x9b, 0x75, 0xd7, 0x1, 0x4a, 0x21, 0xa8, 0x26, 0x0, 0x94, 0xa, 0x41, 0xb2, 0x0, 0x18, 0x86, 0xc9, 0xe9, 0xd, 0x80, 0x52, 0x8, 0x92, 0x5, 0x60, 0xb1, 0x58, 0x74, 0x67, 0x1, 0xa5, 0x10, 0xa4, 0x4, 0x40, 0x77, 0x43, 0xd0, 0xe1, 0x70, 0xa8, 0x9f, 0x1, 0x14, 0x45, 0x1, 0x45, 0x51, 0x79, 0x3d, 0x1, 0x68, 0x6e, 0x6e, 0x4e, 0xaa, 0x6, 0x80, 0x10, 0x42, 0x6, 0x83, 0x41, 0x37, 0x36, 0x28, 0x15, 0x82, 0x6a, 0x2, 0x0, 0x4d, 0xd3, 0xa9, 0x52, 0xcf, 0x95, 0x0, 0xe8, 0x66, 0xe, 0x98, 0xcd, 0x66, 0xa1, 0x6c, 0x0, 0x7a, 0x5a, 0x8b, 0x59, 0x2c, 0x96, 0x64, 0xcd, 0x2, 0xb8, 0x2b, 0x4, 0xe9, 0xde, 0x2, 0x77, 0x85, 0xa0, 0x9a, 0xb0, 0x40, 0xa9, 0x10, 0xa4, 0x8, 0xc0, 0x64, 0x32, 0xe9, 0x6, 0x40, 0xa9, 0x10, 0x54, 0xaa, 0x3, 0x74, 0xf3, 0x16, 0x70, 0xb9, 0x5c, 0xe5, 0x3, 0xe8, 0xe9, 0xe9, 0x69, 0xd5, 0xc3, 0x66, 0x18, 0x63, 0x5c, 0x68, 0x6a, 0x6a, 0x12, 0xcb, 0x5, 0xa0, 0x9b, 0xd5, 0x38, 0x4d, 0xd3, 0x29, 0x8a, 0xa2, 0xa0, 0x2c, 0x0, 0x18, 0x63, 0x3e, 0x14, 0xa, 0xfd, 0x55, 0xb, 0x21, 0x48, 0xd1, 0x2, 0x7a, 0x59, 0x8d, 0xdf, 0x1b, 0x80, 0x1e, 0x56, 0xe3, 0x84, 0x10, 0x34, 0x30, 0x30, 0x60, 0xbb, 0xeb, 0x77, 0x46, 0x5, 0xef, 0x48, 0xcf, 0x4d, 0xec, 0x8d, 0x99, 0x5, 0xf5, 0xf5, 0xf5, 0xef, 0x46, 0x47, 0x47, 0xb, 0x2e, 0x97, 0xeb, 0xbc, 0x54, 0x8, 0x52, 0x4, 0xc0, 0x30, 0x8c, 0xf4, 0x5c, 0x4, 0x9b, 0x4c, 0xa6, 0xf4, 0xf8, 0xf8, 0xb8, 0xc8, 0xb2, 0x6c, 0x32, 0x9d, 0x4e, 0xff, 0xd4, 0xdd, 0xdd, 0x7d, 0x66, 0x34, 0x1a, 0x8b, 0xd7, 0x3, 0xfd, 0xae, 0x5b, 0x29, 0xb2, 0x57, 0x66, 0xb6, 0xb6, 0xb6, 0xde, 0xc4, 0xe3, 0xf1, 0x6f, 0xae, 0xaf, 0xc1, 0x28, 0x5d, 0x85, 0x79, 0x2, 0xc1, 0x60, 0xb5, 0x5a, 0xa3, 0xa3, 0xa3, 0xa3, 0x45, 0xab, 0xd5, 0x9a, 0x2a, 0x16, 0x8b, 0x8b, 0x6d, 0x6d, 0x6d, 0xef, 0xd5, 0x8a, 0x55, 0xd, 0x20, 0x91, 0x48, 0xbc, 0x3e, 0x38, 0x38, 0xf8, 0xda, 0x6e, 0xb7, 0xf7, 0x5f, 0x5c, 0x5c, 0xd4, 0x7b, 0xbd, 0xde, 0xbc, 0x20, 0x8, 0xcd, 0x85, 0x42, 0x81, 0xfe, 0xf0, 0xae, 0xac, 0x10, 0x98, 0x9b, 0xd5, 0xc5, 0x18, 0x17, 0x59, 0x96, 0x3d, 0x1d, 0x19, 0x19, 0x1, 0x96, 0x65, 0x5, 0x8a, 0xa2, 0x7e, 0x6c, 0x69, 0x69, 0x49, 0x3d, 0x44, 0xb0, 0x2a, 0x0, 0x1f, 0xcc, 0x74, 0x75, 0x41, 0xea, 0xfa, 0x7b, 0x32, 0x99, 0x64, 0x76, 0x77, 0x77, 0x5d, 0xe, 0x87, 0xa3, 0x5f, 0x14, 0xc5, 0x57, 0x57, 0x60, 0x5a, 0x8b, 0xc5, 0xa2, 0xf1, 0xbe, 0x50, 0x6e, 0xa, 0x66, 0x18, 0x26, 0x31, 0x36, 0x36, 0x96, 0x65, 0x59, 0x36, 0x29, 0x49, 0x92, 0xb7, 0xbd, 0xbd, 0xfd, 0x9f, 0x72, 0xda, 0xf9, 0xd1, 0x1, 0xa8, 0x1, 0x93, 0xcf, 0xe7, 0xa9, 0x93, 0x93, 0x13, 0x1b, 0x4d, 0xd3, 0x9f, 0xb, 0x82, 0x60, 0xf5, 0x7a, 0xbd, 0xd9, 0x54, 0x2a, 0xe5, 0xcc, 0x64, 0x32, 0xe, 0xb9, 0x6e, 0xb9, 0x16, 0x8c, 0x31, 0x2e, 0xda, 0x6c, 0xb6, 0xc8, 0xd0, 0xd0, 0x10, 0x65, 0xb3, 0xd9, 0x92, 0x95, 0xa8, 0x6e, 0xc5, 0x0, 0xa8, 0xe9, 0x96, 0x68, 0x34, 0x6a, 0xdd, 0xdf, 0xdf, 0x6f, 0x76, 0xb9, 0x5c, 0x9f, 0x89, 0xa2, 0x58, 0xbf, 0xb8, 0xb8, 0x8, 0x26, 0x93, 0x29, 0x3b, 0x3c, 0x3c, 0x8c, 0xed, 0x76, 0x7b, 0xd2, 0x68, 0x34, 0xfe, 0xd0, 0xd8, 0xd8, 0x98, 0xae, 0xb6, 0xe0, 0x8a, 0x1, 0x50, 0xb, 0xe6, 0xa9, 0x5, 0xbf, 0x9c, 0x97, 0xf3, 0xff, 0xf3, 0x2f, 0x6a, 0x82, 0x7f, 0xf6, 0x4e, 0xca, 0x1b, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - -class TestPhysics2DMainLoop : public MainLoop { - GDCLASS(TestPhysics2DMainLoop, MainLoop); - - RID circle_img; - RID circle_shape; - RID space; - RID canvas; - RID ray; - RID ray_query; - Transform2D view_xform; - - Vector2 ray_from, ray_to; - - struct BodyShapeData { - RID image; - RID shape; - }; - - BodyShapeData body_shape_data[8]; - - void _create_body_shape_data() { - RenderingServer *vs = RenderingServer::get_singleton(); - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - - // SEGMENT - - { - Vector<uint8_t> pixels; - pixels.resize(32 * 2 * 2); - for (int i = 0; i < 2; i++) { - for (int j = 0; j < 32; j++) { - pixels.set(i * 32 * 2 + j * 2 + 0, (j == 0) ? 255 : 0); - pixels.set(i * 32 * 2 + j * 2 + 1, 255); - } - } - - Ref<Image> image = memnew(Image(32, 2, 0, Image::FORMAT_LA8, pixels)); - - body_shape_data[PhysicsServer2D::SHAPE_SEGMENT].image = vs->texture_2d_create(image); - - RID segment_shape = ps->segment_shape_create(); - Rect2 sg(Point2(-16, 0), Point2(16, 0)); - ps->shape_set_data(segment_shape, sg); - - body_shape_data[PhysicsServer2D::SHAPE_SEGMENT].shape = segment_shape; - } - - // CIRCLE - - { - Vector<uint8_t> pixels; - pixels.resize(32 * 32 * 2); - for (int i = 0; i < 32; i++) { - for (int j = 0; j < 32; j++) { - bool black = Vector2(i - 16, j - 16).length_squared() < 16 * 16; - - pixels.set(i * 32 * 2 + j * 2 + 0, (i == 16 || j == 16) ? 255 : 0); - pixels.set(i * 32 * 2 + j * 2 + 1, black ? 255 : 0); - } - } - - Ref<Image> image = memnew(Image(32, 32, 0, Image::FORMAT_LA8, pixels)); - - body_shape_data[PhysicsServer2D::SHAPE_CIRCLE].image = vs->texture_2d_create(image); - - RID circle_shape = ps->circle_shape_create(); - ps->shape_set_data(circle_shape, 16); - - body_shape_data[PhysicsServer2D::SHAPE_CIRCLE].shape = circle_shape; - } - - // BOX - - { - Vector<uint8_t> pixels; - pixels.resize(32 * 32 * 2); - for (int i = 0; i < 32; i++) { - for (int j = 0; j < 32; j++) { - bool black = i > 0 && i < 31 && j > 0 && j < 31; - - pixels.set(i * 32 * 2 + j * 2 + 0, black ? 0 : 255); - pixels.set(i * 32 * 2 + j * 2 + 1, 255); - } - } - - Ref<Image> image = memnew(Image(32, 32, 0, Image::FORMAT_LA8, pixels)); - - body_shape_data[PhysicsServer2D::SHAPE_RECTANGLE].image = vs->texture_2d_create(image); - - RID rectangle_shape = ps->rectangle_shape_create(); - ps->shape_set_data(rectangle_shape, Vector2(16, 16)); - - body_shape_data[PhysicsServer2D::SHAPE_RECTANGLE].shape = rectangle_shape; - } - - // CAPSULE - - { - Vector<uint8_t> pixels; - pixels.resize(32 * 64 * 2); - for (int i = 0; i < 64; i++) { - for (int j = 0; j < 32; j++) { - int si = i > 48 ? i - 32 : (i < 16 ? i : 16); - bool black = Vector2(si - 16, j - 16).length_squared() < 16 * 16; - - pixels.set(i * 32 * 2 + j * 2 + 0, (i == 16 || j == 16 || i == 48) ? 255 : 0); - pixels.set(i * 32 * 2 + j * 2 + 1, black ? 255 : 0); - } - } - - Ref<Image> image = memnew(Image(32, 64, 0, Image::FORMAT_LA8, pixels)); - - body_shape_data[PhysicsServer2D::SHAPE_CAPSULE].image = vs->texture_2d_create(image); - - RID capsule_shape = ps->capsule_shape_create(); - ps->shape_set_data(capsule_shape, Vector2(16, 32)); - - body_shape_data[PhysicsServer2D::SHAPE_CAPSULE].shape = capsule_shape; - } - - // CONVEX - - { - Ref<Image> image = memnew(Image(convex_png)); - - body_shape_data[PhysicsServer2D::SHAPE_CONVEX_POLYGON].image = vs->texture_2d_create(image); - - RID convex_polygon_shape = ps->convex_polygon_shape_create(); - - Vector<Vector2> arr; - Point2 sb(32, 32); - arr.push_back(Point2(20, 3) - sb); - arr.push_back(Point2(58, 23) - sb); - arr.push_back(Point2(55, 54) - sb); - arr.push_back(Point2(27, 60) - sb); - arr.push_back(Point2(5, 56) - sb); - arr.push_back(Point2(4, 20) - sb); - arr.push_back(Point2(11, 7) - sb); - ps->shape_set_data(convex_polygon_shape, arr); - - body_shape_data[PhysicsServer2D::SHAPE_CONVEX_POLYGON].shape = convex_polygon_shape; - } - } - - void _do_ray_query() { - // FIXME: Do something? - } - -protected: - void input_event(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb = p_event; - - if (mb.is_valid()) { - if (mb->is_pressed()) { - Point2 p = mb->get_position(); - - if (mb->get_button_index() == MouseButton::LEFT) { - ray_to = p; - _do_ray_query(); - } else if (mb->get_button_index() == MouseButton::RIGHT) { - ray_from = p; - _do_ray_query(); - } - } - } - - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid()) { - Point2 p = mm->get_position(); - - if ((mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) { - ray_to = p; - _do_ray_query(); - } else if ((mm->get_button_mask() & MouseButton::MASK_RIGHT) != MouseButton::NONE) { - ray_from = p; - _do_ray_query(); - } - } - } - - RID _add_body(PhysicsServer2D::ShapeType p_shape, const Transform2D &p_xform) { - RenderingServer *vs = RenderingServer::get_singleton(); - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - - RID body = ps->body_create(); - ps->body_add_shape(body, body_shape_data[p_shape].shape); - ps->body_set_space(body, space); - ps->body_set_continuous_collision_detection_mode(body, PhysicsServer2D::CCD_MODE_CAST_SHAPE); - ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, p_xform); - - RID sprite = vs->canvas_item_create(); - vs->canvas_item_set_parent(sprite, canvas); - vs->canvas_item_set_transform(sprite, p_xform); - Size2 imgsize(5, 5); - vs->canvas_item_add_texture_rect(sprite, Rect2(-imgsize / 2.0, imgsize), body_shape_data[p_shape].image); - - ps->body_set_force_integration_callback(body, callable_mp(this, &TestPhysics2DMainLoop::_body_moved), sprite); - - return body; - } - - void _add_world_boundary(const Vector2 &p_normal, real_t p_d) { - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - - Array arr; - arr.push_back(p_normal); - arr.push_back(p_d); - - RID world_boundary = ps->world_boundary_shape_create(); - ps->shape_set_data(world_boundary, arr); - - RID plane_body = ps->body_create(); - ps->body_set_mode(plane_body, PhysicsServer2D::BODY_MODE_STATIC); - ps->body_set_space(plane_body, space); - ps->body_add_shape(plane_body, world_boundary); - } - - void _add_concave(const Vector<Vector2> &p_points, const Transform2D &p_xform = Transform2D()) { - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - RenderingServer *vs = RenderingServer::get_singleton(); - - RID concave = ps->concave_polygon_shape_create(); - ps->shape_set_data(concave, p_points); - RID body = ps->body_create(); - ps->body_set_mode(body, PhysicsServer2D::BODY_MODE_STATIC); - ps->body_set_space(body, space); - ps->body_add_shape(body, concave); - ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, p_xform); - - RID sprite = vs->canvas_item_create(); - vs->canvas_item_set_parent(sprite, canvas); - vs->canvas_item_set_transform(sprite, p_xform); - for (int i = 0; i < p_points.size(); i += 2) { - vs->canvas_item_add_line(sprite, p_points[i], p_points[i + 1], Color(0, 0, 0), 2); - } - } - - void _body_moved(Object *p_state, RID p_sprite) { - PhysicsDirectBodyState2D *state = (PhysicsDirectBodyState2D *)p_state; - RenderingServer::get_singleton()->canvas_item_set_transform(p_sprite, state->get_transform()); - } - - void _ray_query_callback(const RID &p_rid, ObjectID p_id, int p_shape, const Vector2 &p_point, const Vector2 &p_normal) { - Vector2 ray_end; - - if (p_rid.is_valid()) { - ray_end = p_point; - } else { - ray_end = ray_to; - } - - RenderingServer *vs = RenderingServer::get_singleton(); - - vs->canvas_item_clear(ray); - vs->canvas_item_add_line(ray, ray_from, ray_end, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2); - if (p_rid.is_valid()) { - vs->canvas_item_add_line(ray, ray_end, ray_end + p_normal * 20, p_rid.is_valid() ? Color(0, 1, 0.4) : Color(1, 0.4, 0), 2); - } - } - - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("_ray_query_callback"), &TestPhysics2DMainLoop::_ray_query_callback); - } - -public: - virtual void initialize() override { - RenderingServer *vs = RenderingServer::get_singleton(); - PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); - - space = ps->space_create(); - ps->space_set_active(space, true); - ps->set_active(true); - ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, Vector2(0, 1)); - ps->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, 980); - - { - RID vp = vs->viewport_create(); - canvas = vs->canvas_create(); - - Size2i screen_size = DisplayServer::get_singleton()->window_get_size(); - vs->viewport_attach_canvas(vp, canvas); - vs->viewport_set_size(vp, screen_size.x, screen_size.y); - vs->viewport_attach_to_screen(vp, Rect2(Vector2(), screen_size)); - vs->viewport_set_active(vp, true); - vs->viewport_set_canvas_transform(vp, canvas, view_xform); - } - - ray = vs->canvas_item_create(); - vs->canvas_item_set_parent(ray, canvas); - - for (int i = 0; i < 32; i++) { - PhysicsServer2D::ShapeType types[4] = { - PhysicsServer2D::SHAPE_CIRCLE, - PhysicsServer2D::SHAPE_CAPSULE, - PhysicsServer2D::SHAPE_RECTANGLE, - PhysicsServer2D::SHAPE_CONVEX_POLYGON, - - }; - - PhysicsServer2D::ShapeType type = types[i % 4]; - _add_body(type, Transform2D(i * 0.8, Point2(152 + i * 40, 100 - 40 * i))); - } - - Point2 prev; - - Vector<Point2> parr; - for (int i = 0; i < 30; i++) { - Point2 p(i * 60, Math::randf() * 70 + 340); - if (i > 0) { - parr.push_back(prev); - parr.push_back(p); - } - prev = p; - } - - _add_concave(parr); - } - - virtual bool process(double p_time) override { - return false; - } - virtual void finalize() override { - } - - TestPhysics2DMainLoop() {} -}; - -namespace TestPhysics2D { - -MainLoop *test() { - return memnew(TestPhysics2DMainLoop); -} -} // namespace TestPhysics2D diff --git a/tests/servers/test_physics_2d.h b/tests/servers/test_physics_2d.h deleted file mode 100644 index b6c47574cd..0000000000 --- a/tests/servers/test_physics_2d.h +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************/ -/* test_physics_2d.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TEST_PHYSICS_2D_H -#define TEST_PHYSICS_2D_H - -class MainLoop; - -namespace TestPhysics2D { - -MainLoop *test(); -} - -#endif // TEST_PHYSICS_2D_H diff --git a/tests/servers/test_physics_3d.cpp b/tests/servers/test_physics_3d.cpp deleted file mode 100644 index 3d38b9d901..0000000000 --- a/tests/servers/test_physics_3d.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/*************************************************************************/ -/* test_physics_3d.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "test_physics_3d.h" - -#include "core/math/convex_hull.h" -#include "core/math/geometry_3d.h" -#include "core/os/main_loop.h" -#include "servers/physics_server_3d.h" -#include "servers/rendering_server.h" - -class TestPhysics3DMainLoop : public MainLoop { - GDCLASS(TestPhysics3DMainLoop, MainLoop); - - enum { - LINK_COUNT = 20, - }; - - RID test_cube; - - RID plane; - RID sphere; - RID light; - RID camera; - RID mover; - RID scenario; - RID space; - - RID character; - - real_t ofs_x, ofs_y; - - Point2 joy_direction; - - List<RID> bodies; - Map<PhysicsServer3D::ShapeType, RID> type_shape_map; - Map<PhysicsServer3D::ShapeType, RID> type_mesh_map; - - void body_changed_transform(Object *p_state, RID p_visual_instance) { - PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; - RenderingServer *vs = RenderingServer::get_singleton(); - Transform3D t = state->get_transform(); - vs->instance_set_transform(p_visual_instance, t); - } - - bool quit; - -protected: - RID create_body(PhysicsServer3D::ShapeType p_shape, PhysicsServer3D::BodyMode p_body, const Transform3D p_location, bool p_active_default = true, const Transform3D &p_shape_xform = Transform3D()) { - RenderingServer *vs = RenderingServer::get_singleton(); - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - - RID mesh_instance = vs->instance_create2(type_mesh_map[p_shape], scenario); - RID body = ps->body_create(); - ps->body_set_mode(body, p_body); - ps->body_set_state(body, PhysicsServer3D::BODY_STATE_SLEEPING, !p_active_default); - ps->body_set_space(body, space); - ps->body_set_param(body, PhysicsServer3D::BODY_PARAM_BOUNCE, 0.0); - //todo set space - ps->body_add_shape(body, type_shape_map[p_shape]); - ps->body_set_force_integration_callback(body, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance); - - ps->body_set_state(body, PhysicsServer3D::BODY_STATE_TRANSFORM, p_location); - bodies.push_back(body); - - if (p_body == PhysicsServer3D::BODY_MODE_STATIC) { - vs->instance_set_transform(mesh_instance, p_location); - } - return body; - } - - RID create_world_boundary(const Plane &p_plane) { - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - - RID world_boundary_shape = ps->shape_create(PhysicsServer3D::SHAPE_WORLD_BOUNDARY); - ps->shape_set_data(world_boundary_shape, p_plane); - - RID b = ps->body_create(); - ps->body_set_mode(b, PhysicsServer3D::BODY_MODE_STATIC); - - ps->body_set_space(b, space); - ps->body_add_shape(b, world_boundary_shape); - return b; - } - - void configure_body(RID p_body, real_t p_mass, real_t p_friction, real_t p_bounce) { - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_MASS, p_mass); - ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_FRICTION, p_friction); - ps->body_set_param(p_body, PhysicsServer3D::BODY_PARAM_BOUNCE, p_bounce); - } - - void initialize_shapes() { - RenderingServer *vs = RenderingServer::get_singleton(); - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - - /* SPHERE SHAPE */ - RID sphere_mesh = vs->make_sphere_mesh(10, 20, 0.5); - type_mesh_map[PhysicsServer3D::SHAPE_SPHERE] = sphere_mesh; - - RID sphere_shape = ps->shape_create(PhysicsServer3D::SHAPE_SPHERE); - ps->shape_set_data(sphere_shape, 0.5); - type_shape_map[PhysicsServer3D::SHAPE_SPHERE] = sphere_shape; - - /* BOX SHAPE */ - - Vector<Plane> box_planes = Geometry3D::build_box_planes(Vector3(0.5, 0.5, 0.5)); - RID box_mesh = vs->mesh_create(); - Geometry3D::MeshData box_data = Geometry3D::build_convex_mesh(box_planes); - vs->mesh_add_surface_from_mesh_data(box_mesh, box_data); - type_mesh_map[PhysicsServer3D::SHAPE_BOX] = box_mesh; - - RID box_shape = ps->shape_create(PhysicsServer3D::SHAPE_BOX); - ps->shape_set_data(box_shape, Vector3(0.5, 0.5, 0.5)); - type_shape_map[PhysicsServer3D::SHAPE_BOX] = box_shape; - - /* CAPSULE SHAPE */ - - Vector<Plane> capsule_planes = Geometry3D::build_capsule_planes(0.5, 0.7, 12, Vector3::AXIS_Z); - - RID capsule_mesh = vs->mesh_create(); - Geometry3D::MeshData capsule_data = Geometry3D::build_convex_mesh(capsule_planes); - vs->mesh_add_surface_from_mesh_data(capsule_mesh, capsule_data); - - type_mesh_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_mesh; - - RID capsule_shape = ps->shape_create(PhysicsServer3D::SHAPE_CAPSULE); - Dictionary capsule_params; - capsule_params["radius"] = 0.5; - capsule_params["height"] = 1.4; - ps->shape_set_data(capsule_shape, capsule_params); - type_shape_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_shape; - - /* CONVEX SHAPE */ - - Vector<Plane> convex_planes = Geometry3D::build_cylinder_planes(0.5, 0.7, 5, Vector3::AXIS_Z); - - RID convex_mesh = vs->mesh_create(); - Geometry3D::MeshData convex_data = Geometry3D::build_convex_mesh(convex_planes); - ConvexHullComputer::convex_hull(convex_data.vertices, convex_data); - vs->mesh_add_surface_from_mesh_data(convex_mesh, convex_data); - - type_mesh_map[PhysicsServer3D::SHAPE_CONVEX_POLYGON] = convex_mesh; - - RID convex_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON); - ps->shape_set_data(convex_shape, convex_data.vertices); - type_shape_map[PhysicsServer3D::SHAPE_CONVEX_POLYGON] = convex_shape; - } - - void make_trimesh(Vector<Vector3> p_faces, const Transform3D &p_xform = Transform3D()) { - RenderingServer *vs = RenderingServer::get_singleton(); - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - RID trimesh_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON); - Dictionary trimesh_params; - trimesh_params["faces"] = p_faces; - trimesh_params["backface_collision"] = false; - ps->shape_set_data(trimesh_shape, trimesh_params); - Vector<Vector3> normals; // for drawing - for (int i = 0; i < p_faces.size() / 3; i++) { - Plane p(p_faces[i * 3 + 0], p_faces[i * 3 + 1], p_faces[i * 3 + 2]); - normals.push_back(p.normal); - normals.push_back(p.normal); - normals.push_back(p.normal); - } - - RID trimesh_mesh = vs->mesh_create(); - Array d; - d.resize(RS::ARRAY_MAX); - d[RS::ARRAY_VERTEX] = p_faces; - d[RS::ARRAY_NORMAL] = normals; - vs->mesh_add_surface_from_arrays(trimesh_mesh, RS::PRIMITIVE_TRIANGLES, d); - - RID triins = vs->instance_create2(trimesh_mesh, scenario); - - RID tribody = ps->body_create(); - ps->body_set_mode(tribody, PhysicsServer3D::BODY_MODE_STATIC); - ps->body_set_space(tribody, space); - //todo set space - ps->body_add_shape(tribody, trimesh_shape); - Transform3D tritrans = p_xform; - ps->body_set_state(tribody, PhysicsServer3D::BODY_STATE_TRANSFORM, tritrans); - vs->instance_set_transform(triins, tritrans); - } - - void make_grid(int p_width, int p_height, real_t p_cellsize, real_t p_cellheight, const Transform3D &p_xform = Transform3D()) { - Vector<Vector<real_t>> grid; - - grid.resize(p_width); - - for (int i = 0; i < p_width; i++) { - grid.write[i].resize(p_height); - - for (int j = 0; j < p_height; j++) { - grid.write[i].write[j] = 1.0 + Math::random(-p_cellheight, p_cellheight); - } - } - - Vector<Vector3> faces; - - for (int i = 1; i < p_width; i++) { - for (int j = 1; j < p_height; j++) { -#define MAKE_VERTEX(m_x, m_z) \ - faces.push_back(Vector3((m_x - p_width / 2) * p_cellsize, grid[m_x][m_z], (m_z - p_height / 2) * p_cellsize)) - - MAKE_VERTEX(i, j - 1); - MAKE_VERTEX(i, j); - MAKE_VERTEX(i - 1, j); - - MAKE_VERTEX(i - 1, j - 1); - MAKE_VERTEX(i, j - 1); - MAKE_VERTEX(i - 1, j); - } - } - - make_trimesh(faces, p_xform); - } - -public: - virtual void input_event(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseMotion> mm = p_event; - if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_MIDDLE) != MouseButton::NONE) { - ofs_y -= mm->get_relative().y / 200.0; - ofs_x += mm->get_relative().x / 200.0; - } - - if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) { - real_t y = -mm->get_relative().y / 20.0; - real_t x = mm->get_relative().x / 20.0; - - if (mover.is_valid()) { - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - Transform3D t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); - t.origin += Vector3(x, y, 0); - - ps->body_set_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM, t); - } - } - } - - virtual void request_quit() { - quit = true; - } - virtual void initialize() override { - ofs_x = ofs_y = 0; - initialize_shapes(); - - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - space = ps->space_create(); - ps->space_set_active(space, true); - - RenderingServer *vs = RenderingServer::get_singleton(); - - /* LIGHT */ - RID lightaux = vs->directional_light_create(); - scenario = vs->scenario_create(); - vs->light_set_shadow(lightaux, true); - light = vs->instance_create2(lightaux, scenario); - Transform3D t; - t.rotate(Vector3(1.0, 0, 0), 0.6); - vs->instance_set_transform(light, t); - - /* CAMERA */ - - camera = vs->camera_create(); - - RID viewport = vs->viewport_create(); - Size2i screen_size = DisplayServer::get_singleton()->window_get_size(); - vs->viewport_set_size(viewport, screen_size.x, screen_size.y); - vs->viewport_attach_to_screen(viewport, Rect2(Vector2(), screen_size)); - vs->viewport_set_active(viewport, true); - vs->viewport_attach_camera(viewport, camera); - vs->viewport_set_scenario(viewport, scenario); - - vs->camera_set_perspective(camera, 60, 0.1, 40.0); - vs->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 9, 12))); - - Transform3D gxf; - gxf.basis.scale(Vector3(1.4, 0.4, 1.4)); - gxf.origin = Vector3(-2, 1, -2); - make_grid(5, 5, 2.5, 1, gxf); - test_fall(); - quit = false; - } - virtual bool physics_process(double p_time) override { - if (mover.is_valid()) { - static real_t joy_speed = 10; - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - Transform3D t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); - t.origin += Vector3(joy_speed * joy_direction.x * p_time, -joy_speed * joy_direction.y * p_time, 0); - ps->body_set_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM, t); - }; - - Transform3D cameratr; - cameratr.rotate(Vector3(0, 1, 0), ofs_x); - cameratr.rotate(Vector3(1, 0, 0), -ofs_y); - cameratr.translate(Vector3(0, 2, 8)); - RenderingServer *vs = RenderingServer::get_singleton(); - vs->camera_set_transform(camera, cameratr); - - return quit; - } - virtual void finalize() override { - } - - void test_joint() { - } - - void test_hinge() { - } - - void test_character() { - RenderingServer *vs = RenderingServer::get_singleton(); - PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - - Vector<Plane> capsule_planes = Geometry3D::build_capsule_planes(0.5, 1, 12, 5, Vector3::AXIS_Y); - - RID capsule_mesh = vs->mesh_create(); - Geometry3D::MeshData capsule_data = Geometry3D::build_convex_mesh(capsule_planes); - vs->mesh_add_surface_from_mesh_data(capsule_mesh, capsule_data); - type_mesh_map[PhysicsServer3D::SHAPE_CAPSULE] = capsule_mesh; - - RID capsule_shape = ps->shape_create(PhysicsServer3D::SHAPE_CAPSULE); - Dictionary capsule_params; - capsule_params["radius"] = 0.5; - capsule_params["height"] = 1; - Transform3D shape_xform; - shape_xform.rotate(Vector3(1, 0, 0), Math_PI / 2.0); - //shape_xform.origin=Vector3(1,1,1); - ps->shape_set_data(capsule_shape, capsule_params); - - RID mesh_instance = vs->instance_create2(capsule_mesh, scenario); - character = ps->body_create(); - ps->body_set_mode(character, PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR); - ps->body_set_space(character, space); - //todo add space - ps->body_add_shape(character, capsule_shape); - ps->body_set_force_integration_callback(character, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance); - - ps->body_set_state(character, PhysicsServer3D::BODY_STATE_TRANSFORM, Transform3D(Basis(), Vector3(-2, 5, -2))); - bodies.push_back(character); - } - - void test_fall() { - for (int i = 0; i < 35; i++) { - static const PhysicsServer3D::ShapeType shape_idx[] = { - PhysicsServer3D::SHAPE_CAPSULE, - PhysicsServer3D::SHAPE_BOX, - PhysicsServer3D::SHAPE_SPHERE, - PhysicsServer3D::SHAPE_CONVEX_POLYGON - }; - - PhysicsServer3D::ShapeType type = shape_idx[i % 4]; - - Transform3D t; - - t.origin = Vector3(0.0 * i, 3.5 + 1.1 * i, 0.7 + 0.0 * i); - t.basis.rotate(Vector3(0.2, -1, 0), Math_PI / 2 * 0.6); - - create_body(type, PhysicsServer3D::BODY_MODE_DYNAMIC, t); - } - - create_world_boundary(Plane(Vector3(0, 1, 0), -1)); - } - - void test_activate() { - create_body(PhysicsServer3D::SHAPE_BOX, PhysicsServer3D::BODY_MODE_DYNAMIC, Transform3D(Basis(), Vector3(0, 2, 0)), true); - create_world_boundary(Plane(Vector3(0, 1, 0), -1)); - } - - virtual bool process(double p_time) override { - return false; - } - - TestPhysics3DMainLoop() { - } -}; - -namespace TestPhysics3D { - -MainLoop *test() { - return memnew(TestPhysics3DMainLoop); -} -} // namespace TestPhysics3D diff --git a/tests/servers/test_physics_3d.h b/tests/servers/test_physics_3d.h deleted file mode 100644 index f618d0fb4f..0000000000 --- a/tests/servers/test_physics_3d.h +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************/ -/* test_physics_3d.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TEST_PHYSICS_H -#define TEST_PHYSICS_H - -class MainLoop; - -namespace TestPhysics3D { - -MainLoop *test(); -} - -#endif diff --git a/tests/servers/test_render.cpp b/tests/servers/test_render.cpp deleted file mode 100644 index 44403e3724..0000000000 --- a/tests/servers/test_render.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/*************************************************************************/ -/* test_render.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "test_render.h" - -#include "core/math/convex_hull.h" -#include "core/os/main_loop.h" -#include "servers/rendering_server.h" - -#define OBJECT_COUNT 50 - -namespace TestRender { - -class TestMainLoop : public MainLoop { - RID test_cube; - RID instance; - RID camera; - RID viewport; - RID light; - RID scenario; - - struct InstanceInfo { - RID instance; - Transform3D base; - Vector3 rot_axis; - }; - - List<InstanceInfo> instances; - - float ofs; - bool quit; - -protected: -public: - virtual void input_event(const Ref<InputEvent> &p_event) { - if (p_event->is_pressed()) { - quit = true; - } - } - - virtual void init() { - print_line("INITIALIZING TEST RENDER"); - RenderingServer *vs = RenderingServer::get_singleton(); - test_cube = vs->get_test_cube(); - scenario = vs->scenario_create(); - - Vector<Vector3> vts; - - /* - Vector<Plane> sp = Geometry3D::build_sphere_planes(2,5,5); - Geometry3D::MeshData md2 = Geometry3D::build_convex_mesh(sp); - vts=md2.vertices; -*/ - /* - - static const int s = 20; - for(int i=0;i<s;i++) { - Basis rot(Vector3(0,1,0),i*Math_PI/s); - - for(int j=0;j<s;j++) { - Vector3 v; - v.x=Math::sin(j*Math_PI*2/s); - v.y=Math::cos(j*Math_PI*2/s); - - vts.push_back( rot.xform(v*2 ) ); - } - }*/ - /*for(int i=0;i<100;i++) { - vts.push_back( Vector3(Math::randf()*2-1.0,Math::randf()*2-1.0,Math::randf()*2-1.0).normalized()*2); - }*/ - /* - vts.push_back(Vector3(0,0,1)); - vts.push_back(Vector3(0,0,-1)); - vts.push_back(Vector3(0,1,0)); - vts.push_back(Vector3(0,-1,0)); - vts.push_back(Vector3(1,0,0)); - vts.push_back(Vector3(-1,0,0));*/ - - vts.push_back(Vector3(1, 1, 1)); - vts.push_back(Vector3(1, -1, 1)); - vts.push_back(Vector3(-1, 1, 1)); - vts.push_back(Vector3(-1, -1, 1)); - vts.push_back(Vector3(1, 1, -1)); - vts.push_back(Vector3(1, -1, -1)); - vts.push_back(Vector3(-1, 1, -1)); - vts.push_back(Vector3(-1, -1, -1)); - - Geometry3D::MeshData md; - Error err = ConvexHullComputer::convex_hull(vts, md); - print_line("ERR: " + itos(err)); - test_cube = vs->mesh_create(); - vs->mesh_add_surface_from_mesh_data(test_cube, md); - //vs->scenario_set_debug(scenario,RS::SCENARIO_DEBUG_WIREFRAME); - - /* - RID sm = vs->shader_create(); - //vs->shader_set_fragment_code(sm,"OUT_ALPHA=mod(TIME,1);"); - //vs->shader_set_vertex_code(sm,"OUT_VERTEX=IN_VERTEX*mod(TIME,1);"); - vs->shader_set_fragment_code(sm,"OUT_DIFFUSE=vec3(1,0,1);OUT_GLOW=abs(sin(TIME));"); - RID tcmat = vs->mesh_surface_get_material(test_cube,0); - vs->material_set_shader(tcmat,sm); - */ - - List<String> cmdline = OS::get_singleton()->get_cmdline_args(); - int object_count = OBJECT_COUNT; - if (cmdline.size() > 0 && cmdline[cmdline.size() - 1].to_int()) { - object_count = cmdline[cmdline.size() - 1].to_int(); - }; - - for (int i = 0; i < object_count; i++) { - InstanceInfo ii; - - ii.instance = vs->instance_create2(test_cube, scenario); - - ii.base.translate(Math::random(-20, 20), Math::random(-20, 20), Math::random(-20, 18)); - ii.base.rotate(Vector3(0, 1, 0), Math::randf() * Math_PI); - ii.base.rotate(Vector3(1, 0, 0), Math::randf() * Math_PI); - vs->instance_set_transform(ii.instance, ii.base); - - ii.rot_axis = Vector3(Math::random(-1, 1), Math::random(-1, 1), Math::random(-1, 1)).normalized(); - - instances.push_back(ii); - } - - camera = vs->camera_create(); - - // vs->camera_set_perspective( camera, 60.0,0.1, 100.0 ); - - viewport = vs->viewport_create(); - Size2i screen_size = DisplayServer::get_singleton()->window_get_size(); - vs->viewport_set_size(viewport, screen_size.x, screen_size.y); - vs->viewport_attach_to_screen(viewport, Rect2(Vector2(), screen_size)); - vs->viewport_set_active(viewport, true); - vs->viewport_attach_camera(viewport, camera); - vs->viewport_set_scenario(viewport, scenario); - vs->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 3, 30))); - vs->camera_set_perspective(camera, 60, 0.1, 1000); - - /* - RID lightaux = vs->light_create( RenderingServer::LIGHT_OMNI ); - vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_RADIUS, 80 ); - vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_ATTENUATION, 1 ); - vs->light_set_var( lightaux, RenderingServer::LIGHT_VAR_ENERGY, 1.5 ); - light = vs->instance_create( lightaux ); - */ - RID lightaux; - - lightaux = vs->directional_light_create(); - //vs->light_set_color( lightaux, RenderingServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) ); - vs->light_set_color(lightaux, Color(1.0, 1.0, 1.0)); - //vs->light_set_shadow( lightaux, true ); - light = vs->instance_create2(lightaux, scenario); - Transform3D lla; - //lla.set_look_at(Vector3(),Vector3(1, -1, 1)); - lla.basis = Basis::looking_at(Vector3(0.0, -0.836026, -0.548690)); - - vs->instance_set_transform(light, lla); - - lightaux = vs->omni_light_create(); - //vs->light_set_color( lightaux, RenderingServer::LIGHT_COLOR_AMBIENT, Color(0.0,0.0,1.0) ); - vs->light_set_color(lightaux, Color(1.0, 1.0, 0.0)); - vs->light_set_param(lightaux, RenderingServer::LIGHT_PARAM_RANGE, 4); - vs->light_set_param(lightaux, RenderingServer::LIGHT_PARAM_ENERGY, 8); - //vs->light_set_shadow( lightaux, true ); - //light = vs->instance_create( lightaux ); - - ofs = 0; - quit = false; - } - virtual bool iteration(double p_time) { - RenderingServer *vs = RenderingServer::get_singleton(); - //Transform3D t; - //t.rotate(Vector3(0, 1, 0), ofs); - //t.translate(Vector3(0,0,20 )); - //vs->camera_set_transform(camera, t); - - ofs += p_time * 0.05; - - //return quit; - - for (const InstanceInfo &E : instances) { - Transform3D pre(Basis(E.rot_axis, ofs), Vector3()); - vs->instance_set_transform(E.instance, pre * E.base); - /* - if( !E->next() ) { - vs->free( E.instance ); - instances.erase(E ); - }*/ - } - - return quit; - } - - virtual bool idle(double p_time) { - return quit; - } - - virtual void finish() { - } -}; - -MainLoop *test() { - return memnew(TestMainLoop); -} -} // namespace TestRender diff --git a/tests/servers/test_render.h b/tests/servers/test_render.h deleted file mode 100644 index d5a3e01ee5..0000000000 --- a/tests/servers/test_render.h +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************/ -/* test_render.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TEST_RENDER_H -#define TEST_RENDER_H - -class MainLoop; - -namespace TestRender { - -MainLoop *test(); -} - -#endif // TEST_RENDER_H diff --git a/tests/servers/test_shader_lang.cpp b/tests/servers/test_shader_lang.cpp deleted file mode 100644 index 06e28212d2..0000000000 --- a/tests/servers/test_shader_lang.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/*************************************************************************/ -/* test_shader_lang.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "test_shader_lang.h" - -#include "core/os/main_loop.h" -#include "core/os/os.h" -#include "servers/rendering/shader_language.h" - -typedef ShaderLanguage SL; - -namespace TestShaderLang { - -static String _mktab(int p_level) { - String tb; - for (int i = 0; i < p_level; i++) { - tb += "\t"; - } - - return tb; -} - -static String _typestr(SL::DataType p_type) { - return ShaderLanguage::get_datatype_name(p_type); -} - -static String _prestr(SL::DataPrecision p_pres) { - switch (p_pres) { - case SL::PRECISION_LOWP: - return "lowp "; - case SL::PRECISION_MEDIUMP: - return "mediump "; - case SL::PRECISION_HIGHP: - return "highp "; - case SL::PRECISION_DEFAULT: - return ""; - } - return ""; -} - -static String _opstr(SL::Operator p_op) { - return ShaderLanguage::get_operator_text(p_op); -} - -static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) { - switch (p_type) { - case SL::TYPE_BOOL: - return p_values[0].boolean ? "true" : "false"; - case SL::TYPE_BVEC2: - return String() + "bvec2(" + (p_values[0].boolean ? "true" : "false") + (p_values[1].boolean ? "true" : "false") + ")"; - case SL::TYPE_BVEC3: - return String() + "bvec3(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + ")"; - case SL::TYPE_BVEC4: - return String() + "bvec4(" + (p_values[0].boolean ? "true" : "false") + "," + (p_values[1].boolean ? "true" : "false") + "," + (p_values[2].boolean ? "true" : "false") + "," + (p_values[3].boolean ? "true" : "false") + ")"; - case SL::TYPE_INT: - return rtos(p_values[0].sint); - case SL::TYPE_IVEC2: - return String() + "ivec2(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + ")"; - case SL::TYPE_IVEC3: - return String() + "ivec3(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + ")"; - case SL::TYPE_IVEC4: - return String() + "ivec4(" + rtos(p_values[0].sint) + "," + rtos(p_values[1].sint) + "," + rtos(p_values[2].sint) + "," + rtos(p_values[3].sint) + ")"; - case SL::TYPE_UINT: - return rtos(p_values[0].real); - case SL::TYPE_UVEC2: - return String() + "uvec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; - case SL::TYPE_UVEC3: - return String() + "uvec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; - case SL::TYPE_UVEC4: - return String() + "uvec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; - case SL::TYPE_FLOAT: - return rtos(p_values[0].real); - case SL::TYPE_VEC2: - return String() + "vec2(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + ")"; - case SL::TYPE_VEC3: - return String() + "vec3(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + ")"; - case SL::TYPE_VEC4: - return String() + "vec4(" + rtos(p_values[0].real) + "," + rtos(p_values[1].real) + "," + rtos(p_values[2].real) + "," + rtos(p_values[3].real) + ")"; - default: - ERR_FAIL_V(String()); - } -} - -static String dump_node_code(SL::Node *p_node, int p_level) { - String code; - - switch (p_node->type) { - case SL::Node::TYPE_SHADER: { - SL::ShaderNode *pnode = (SL::ShaderNode *)p_node; - - for (const KeyValue<StringName, SL::ShaderNode::Uniform> &E : pnode->uniforms) { - String ucode = "uniform "; - ucode += _prestr(E.value.precision); - ucode += _typestr(E.value.type); - ucode += " " + String(E.key); - if (E.value.array_size > 0) { - ucode += "["; - ucode += itos(E.value.array_size); - ucode += "]"; - } else { - if (E.value.default_value.size()) { - ucode += " = " + get_constant_text(E.value.type, E.value.default_value); - } - - static const char *hint_name[SL::ShaderNode::Uniform::HINT_MAX] = { - "", - "color", - "range", - "albedo", - "normal", - "black", - "white" - }; - - if (E.value.hint) { - ucode += " : " + String(hint_name[E.value.hint]); - } - } - - code += ucode + "\n"; - } - - for (const KeyValue<StringName, SL::ShaderNode::Varying> &E : pnode->varyings) { - String vcode = "varying "; - vcode += _prestr(E.value.precision); - vcode += _typestr(E.value.type); - vcode += " " + String(E.key); - - code += vcode + "\n"; - } - for (int i = 0; i < pnode->functions.size(); i++) { - SL::FunctionNode *fnode = pnode->functions[i].function; - - String header; - header = _typestr(fnode->return_type) + " " + fnode->name + "("; - for (int j = 0; j < fnode->arguments.size(); j++) { - if (j > 0) { - header += ", "; - } - header += _prestr(fnode->arguments[j].precision) + _typestr(fnode->arguments[j].type) + " " + fnode->arguments[j].name; - } - - header += ")\n"; - code += header; - code += dump_node_code(fnode->body, p_level + 1); - } - - //code+=dump_node_code(pnode->body,p_level); - } break; - case SL::Node::TYPE_STRUCT: { - } break; - case SL::Node::TYPE_FUNCTION: { - } break; - case SL::Node::TYPE_BLOCK: { - SL::BlockNode *bnode = (SL::BlockNode *)p_node; - - //variables - code += _mktab(p_level - 1) + "{\n"; - for (const KeyValue<StringName, SL::BlockNode::Variable> &E : bnode->variables) { - code += _mktab(p_level) + _prestr(E.value.precision) + _typestr(E.value.type) + " " + E.key + ";\n"; - } - - for (int i = 0; i < bnode->statements.size(); i++) { - String scode = dump_node_code(bnode->statements[i], p_level); - - if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW) { - code += scode; //use directly - } else { - code += _mktab(p_level) + scode + ";\n"; - } - } - code += _mktab(p_level - 1) + "}\n"; - - } break; - case SL::Node::TYPE_VARIABLE: { - SL::VariableNode *vnode = (SL::VariableNode *)p_node; - code = vnode->name; - - } break; - case SL::Node::TYPE_VARIABLE_DECLARATION: { - // FIXME: Implement - } break; - case SL::Node::TYPE_ARRAY: { - SL::ArrayNode *vnode = (SL::ArrayNode *)p_node; - code = vnode->name; - } break; - case SL::Node::TYPE_ARRAY_CONSTRUCT: { - // FIXME: Implement - } break; - case SL::Node::TYPE_CONSTANT: { - SL::ConstantNode *cnode = (SL::ConstantNode *)p_node; - return get_constant_text(cnode->datatype, cnode->values); - - } break; - case SL::Node::TYPE_OPERATOR: { - SL::OperatorNode *onode = (SL::OperatorNode *)p_node; - - switch (onode->op) { - case SL::OP_ASSIGN: - case SL::OP_ASSIGN_ADD: - case SL::OP_ASSIGN_SUB: - case SL::OP_ASSIGN_MUL: - case SL::OP_ASSIGN_DIV: - case SL::OP_ASSIGN_SHIFT_LEFT: - case SL::OP_ASSIGN_SHIFT_RIGHT: - case SL::OP_ASSIGN_MOD: - case SL::OP_ASSIGN_BIT_AND: - case SL::OP_ASSIGN_BIT_OR: - case SL::OP_ASSIGN_BIT_XOR: - code = dump_node_code(onode->arguments[0], p_level) + _opstr(onode->op) + dump_node_code(onode->arguments[1], p_level); - break; - case SL::OP_BIT_INVERT: - case SL::OP_NEGATE: - case SL::OP_NOT: - case SL::OP_DECREMENT: - case SL::OP_INCREMENT: - code = _opstr(onode->op) + dump_node_code(onode->arguments[0], p_level); - break; - case SL::OP_POST_DECREMENT: - case SL::OP_POST_INCREMENT: - code = dump_node_code(onode->arguments[0], p_level) + _opstr(onode->op); - break; - case SL::OP_CALL: - case SL::OP_CONSTRUCT: - code = dump_node_code(onode->arguments[0], p_level) + "("; - for (int i = 1; i < onode->arguments.size(); i++) { - if (i > 1) { - code += ", "; - } - code += dump_node_code(onode->arguments[i], p_level); - } - code += ")"; - break; - case SL::OP_EMPTY: - break; - default: { - code = "(" + dump_node_code(onode->arguments[0], p_level) + _opstr(onode->op) + dump_node_code(onode->arguments[1], p_level) + ")"; - break; - } - } - - } break; - case SL::Node::TYPE_CONTROL_FLOW: { - SL::ControlFlowNode *cfnode = (SL::ControlFlowNode *)p_node; - if (cfnode->flow_op == SL::FLOW_OP_IF) { - code += _mktab(p_level) + "if (" + dump_node_code(cfnode->expressions[0], p_level) + ")\n"; - code += dump_node_code(cfnode->blocks[0], p_level + 1); - if (cfnode->blocks.size() == 2) { - code += _mktab(p_level) + "else\n"; - code += dump_node_code(cfnode->blocks[1], p_level + 1); - } - - } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) { - if (cfnode->blocks.size()) { - code = "return " + dump_node_code(cfnode->blocks[0], p_level); - } else { - code = "return"; - } - } - - } break; - case SL::Node::TYPE_MEMBER: { - SL::MemberNode *mnode = (SL::MemberNode *)p_node; - code = dump_node_code(mnode->owner, p_level) + "." + mnode->name; - - } break; - } - - return code; -} - -static Error recreate_code(void *p_str, SL::ShaderNode *p_program) { - String *str = (String *)p_str; - - *str = dump_node_code(p_program, 0); - - return OK; -} - -MainLoop *test() { - List<String> cmdlargs = OS::get_singleton()->get_cmdline_args(); - - if (cmdlargs.is_empty()) { - //try editor! - print_line("usage: godot -test shader_lang <shader>"); - return nullptr; - } - - String test = cmdlargs.back()->get(); - - FileAccess *fa = FileAccess::open(test, FileAccess::READ); - - if (!fa) { - ERR_FAIL_V(nullptr); - } - - String code; - - while (true) { - char32_t c = fa->get_8(); - if (fa->eof_reached()) { - break; - } - code += c; - } - - SL sl; - print_line("tokens:\n\n" + sl.token_debug(code)); - - Map<StringName, SL::FunctionInfo> dt; - dt["fragment"].built_ins["ALBEDO"] = SL::TYPE_VEC3; - dt["fragment"].can_discard = true; - - Vector<SL::ModeInfo> rm; - rm.push_back({ "popo" }); - Set<String> types; - types.insert("spatial"); - - ShaderLanguage::ShaderCompileInfo info; - info.functions = dt; - info.render_modes = rm; - info.shader_types = types; - - Error err = sl.compile(code, info); - - if (err) { - print_line("Error at line: " + rtos(sl.get_error_line()) + ": " + sl.get_error_text()); - return nullptr; - } else { - String code2; - recreate_code(&code2, sl.get_shader()); - print_line("code:\n\n" + code2); - } - - return nullptr; -} -} // namespace TestShaderLang diff --git a/tests/servers/test_shader_lang.h b/tests/servers/test_shader_lang.h deleted file mode 100644 index 31e1bfbeea..0000000000 --- a/tests/servers/test_shader_lang.h +++ /dev/null @@ -1,41 +0,0 @@ -/*************************************************************************/ -/* test_shader_lang.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TEST_SHADER_LANG_H -#define TEST_SHADER_LANG_H - -class MainLoop; - -namespace TestShaderLang { - -MainLoop *test(); -} - -#endif // TEST_SHADER_LANG_H diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 830731abcd..344e2fa101 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -45,7 +45,6 @@ #include "tests/core/math/test_expression.h" #include "tests/core/math/test_geometry_2d.h" #include "tests/core/math/test_geometry_3d.h" -#include "tests/core/math/test_math.h" #include "tests/core/math/test_random_number_generator.h" #include "tests/core/math/test_rect2.h" #include "tests/core/math/test_rect2i.h" @@ -63,7 +62,6 @@ #include "tests/core/templates/test_list.h" #include "tests/core/templates/test_local_vector.h" #include "tests/core/templates/test_lru.h" -#include "tests/core/templates/test_oa_hash_map.h" #include "tests/core/templates/test_ordered_hash_map.h" #include "tests/core/templates/test_paged_array.h" #include "tests/core/templates/test_vector.h" @@ -77,12 +75,7 @@ #include "tests/scene/test_code_edit.h" #include "tests/scene/test_curve.h" #include "tests/scene/test_gradient.h" -#include "tests/scene/test_gui.h" #include "tests/scene/test_path_3d.h" -#include "tests/servers/test_physics_2d.h" -#include "tests/servers/test_physics_3d.h" -#include "tests/servers/test_render.h" -#include "tests/servers/test_shader_lang.h" #include "tests/servers/test_text_server.h" #include "tests/test_validate_testing.h" |