diff options
Diffstat (limited to 'core/io')
35 files changed, 631 insertions, 179 deletions
diff --git a/core/io/compression.cpp b/core/io/compression.cpp index a113f3b61b..b51e50150e 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -175,7 +175,9 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p } break; case MODE_ZSTD: { ZSTD_DCtx *dctx = ZSTD_createDCtx(); - if (zstd_long_distance_matching) ZSTD_DCtx_setMaxWindowSize(dctx, (size_t)1 << zstd_window_log_size); + if (zstd_long_distance_matching) { + ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, zstd_window_log_size); + } int ret = ZSTD_decompressDCtx(dctx, p_dst, p_dst_max_size, p_src, p_src_size); ZSTD_freeDCtx(dctx); return ret; @@ -189,4 +191,4 @@ int Compression::zlib_level = Z_DEFAULT_COMPRESSION; int Compression::gzip_level = Z_DEFAULT_COMPRESSION; int Compression::zstd_level = 3; bool Compression::zstd_long_distance_matching = false; -int Compression::zstd_window_log_size = 27; +int Compression::zstd_window_log_size = 27; // ZSTD_WINDOWLOG_LIMIT_DEFAULT diff --git a/core/io/file_access_buffered.h b/core/io/file_access_buffered.h index 756045a674..4065d77c58 100644 --- a/core/io/file_access_buffered.h +++ b/core/io/file_access_buffered.h @@ -31,8 +31,8 @@ #ifndef FILE_ACCESS_BUFFERED_H #define FILE_ACCESS_BUFFERED_H -#include "core/dvector.h" #include "core/os/file_access.h" +#include "core/pool_vector.h" #include "core/ustring.h" class FileAccessBuffered : public FileAccess { diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h index 5180f2344f..24b40cbce8 100644 --- a/core/io/file_access_buffered_fa.h +++ b/core/io/file_access_buffered_fa.h @@ -54,7 +54,7 @@ class FileAccessBufferedFA : public FileAccessBuffered { cache.offset = p_offset; cache.buffer.resize(p_size); - // on dvector + // on PoolVector //PoolVector<uint8_t>::Write write = cache.buffer.write(); //f.get_buffer(write.ptrw(), p_size); @@ -143,6 +143,14 @@ public: return f._get_modified_time(p_file); } + virtual uint32_t _get_unix_permissions(const String &p_file) { + return f._get_unix_permissions(p_file); + } + + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { + return f._set_unix_permissions(p_file, p_permissions); + } + FileAccessBufferedFA(){ }; diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index b268d5c710..6c4310a572 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -373,6 +373,19 @@ uint64_t FileAccessCompressed::_get_modified_time(const String &p_file) { return 0; } +uint32_t FileAccessCompressed::_get_unix_permissions(const String &p_file) { + if (f) + return f->_get_unix_permissions(p_file); + return 0; +} + +Error FileAccessCompressed::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + if (f) { + return f->_set_unix_permissions(p_file, p_permissions); + } + return FAILED; +} + FileAccessCompressed::FileAccessCompressed() : cmode(Compression::MODE_ZSTD), writing(false), diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index f408b1bc29..773fed6a3a 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -91,6 +91,8 @@ public: virtual bool file_exists(const String &p_name); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); FileAccessCompressed(); virtual ~FileAccessCompressed(); diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index 6ad68dd74d..3ff9fa569c 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -100,6 +100,7 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8 MD5Update(&md5, (uint8_t *)data.ptr(), data.size()); MD5Final(&md5); + ERR_EXPLAIN("The MD5 sum of the decrypted file does not match the expected value. It could be that the file is corrupt, or that the provided decryption key is invalid."); ERR_FAIL_COND_V(String::md5(md5.digest) != String::md5(md5d), ERR_FILE_CORRUPT); file = p_base; @@ -301,6 +302,16 @@ uint64_t FileAccessEncrypted::_get_modified_time(const String &p_file) { return 0; } +uint32_t FileAccessEncrypted::_get_unix_permissions(const String &p_file) { + + return 0; +} + +Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + + return FAILED; +} + FileAccessEncrypted::FileAccessEncrypted() { file = NULL; diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index e77d62a9f4..d779a150ac 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -79,6 +79,8 @@ public: virtual bool file_exists(const String &p_name); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); FileAccessEncrypted(); ~FileAccessEncrypted(); diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index 73952133c1..4db7811aaa 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -70,6 +70,8 @@ public: virtual bool file_exists(const String &p_name); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file) { return 0; } + virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } FileAccessMemory(); }; diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 501a21a50d..2572602e16 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -118,7 +118,10 @@ void FileAccessNetworkClient::_thread_func() { FileAccessNetwork *fa = NULL; if (response != FileAccessNetwork::RESPONSE_DATA) { - ERR_FAIL_COND(!accesses.has(id)); + if (!accesses.has(id)) { + unlock_mutex(); + ERR_FAIL_COND(!accesses.has(id)); + } } if (accesses.has(id)) @@ -497,6 +500,16 @@ uint64_t FileAccessNetwork::_get_modified_time(const String &p_file) { return exists_modtime; } +uint32_t FileAccessNetwork::_get_unix_permissions(const String &p_file) { + //could be implemented, not sure if worth it + return 0; +} + +Error FileAccessNetwork::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + + return FAILED; +} + void FileAccessNetwork::configure() { GLOBAL_DEF("network/remote_fs/page_size", 65536); diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index 5bbf7588c7..073b75a37b 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -159,6 +159,8 @@ public: virtual bool file_exists(const String &p_path); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); static void configure(); diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 43fedc5238..d38d09c6bb 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -272,7 +272,7 @@ int FileAccessPack::get_buffer(uint8_t *p_dst, int p_length) const { if (eof) return 0; - int64_t to_read = p_length; + uint64_t to_read = p_length; if (to_read + pos > pf.size) { eof = true; to_read = int64_t(pf.size) - int64_t(pos); @@ -490,6 +490,10 @@ size_t DirAccessPack::get_space_left() { return 0; } +String DirAccessPack::get_filesystem_type() const { + return "PCK"; +} + DirAccessPack::DirAccessPack() { current = PackedData::get_singleton()->root; diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 04610bed57..a21dd7d22d 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -142,6 +142,8 @@ class FileAccessPack : public FileAccess { 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; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } public: virtual void close(); @@ -221,6 +223,8 @@ public: size_t get_space_left(); + virtual String get_filesystem_type() const; + DirAccessPack(); ~DirAccessPack(); }; diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index 66b911e83c..be28c9a877 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -168,10 +168,10 @@ bool ZipArchive::try_open_pack(const String &p_path) { zlib_filefunc_def io; - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - if (!f) + FileAccess *fa = FileAccess::open(p_path, FileAccess::READ); + if (!fa) return false; - io.opaque = f; + io.opaque = fa; io.zopen_file = godot_open; io.zread_file = godot_read; io.zwrite_file = godot_write; diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index fc8f85c07b..217176c0af 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -112,6 +112,8 @@ public: virtual bool file_exists(const String &p_name); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file) { return 0; } // todo + virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; } + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; } FileAccessZip(const String &p_path, const PackedData::PackedFile &p_file); ~FileAccessZip(); diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index b3fd814870..ce2054db36 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -278,6 +278,7 @@ void HTTPClient::close() { body_size = -1; body_left = 0; chunk_left = 0; + chunk_trailer_part = 0; read_until_eof = false; response_num = 0; handshaking = false; @@ -421,16 +422,16 @@ Error HTTPClient::poll() { chunked = false; body_left = 0; chunk_left = 0; + chunk_trailer_part = false; read_until_eof = false; response_str.clear(); response_headers.clear(); response_num = RESPONSE_OK; - // Per the HTTP 1.1 spec, keep-alive is the default, but in practice - // it's safe to assume it only if the explicit header is found, allowing - // to handle body-up-to-EOF responses on naive servers; that's what Curl - // and browsers do - bool keep_alive = false; + // Per the HTTP 1.1 spec, keep-alive is the default. + // Not following that specification breaks standard implementations. + // Broken web servers should be fixed. + bool keep_alive = true; for (int i = 0; i < responses.size(); i++) { @@ -447,8 +448,8 @@ Error HTTPClient::poll() { if (encoding == "chunked") { chunked = true; } - } else if (s.begins_with("connection: keep-alive")) { - keep_alive = true; + } else if (s.begins_with("connection: close")) { + keep_alive = false; } if (i == 0 && responses[i].begins_with("HTTP")) { @@ -505,13 +506,37 @@ PoolByteArray HTTPClient::read_response_body_chunk() { ERR_FAIL_COND_V(status != STATUS_BODY, PoolByteArray()); + PoolByteArray ret; Error err = OK; if (chunked) { while (true) { - if (chunk_left == 0) { + if (chunk_trailer_part) { + // We need to consume the trailer part too or keep-alive will break + uint8_t b; + int rec = 0; + err = _get_http_data(&b, 1, rec); + + if (rec == 0) + break; + + chunk.push_back(b); + int cs = chunk.size(); + if ((cs >= 2 && chunk[cs - 2] == '\r' && chunk[cs - 1] == '\n')) { + if (cs == 2) { + // Finally over + chunk_trailer_part = false; + status = STATUS_CONNECTED; + chunk.clear(); + break; + } else { + // We do not process nor return the trailer data + chunk.clear(); + } + } + } else if (chunk_left == 0) { // Reading length uint8_t b; int rec = 0; @@ -525,7 +550,7 @@ PoolByteArray HTTPClient::read_response_body_chunk() { if (chunk.size() > 32) { ERR_PRINT("HTTP Invalid chunk hex len"); status = STATUS_CONNECTION_ERROR; - return PoolByteArray(); + break; } if (chunk.size() > 2 && chunk[chunk.size() - 2] == '\r' && chunk[chunk.size() - 1] == '\n') { @@ -543,22 +568,22 @@ PoolByteArray HTTPClient::read_response_body_chunk() { else { ERR_PRINT("HTTP Chunk len not in hex!!"); status = STATUS_CONNECTION_ERROR; - return PoolByteArray(); + break; } len <<= 4; len |= v; if (len > (1 << 24)) { ERR_PRINT("HTTP Chunk too big!! >16mb"); status = STATUS_CONNECTION_ERROR; - return PoolByteArray(); + break; } } if (len == 0) { // End reached! - status = STATUS_CONNECTED; + chunk_trailer_part = true; chunk.clear(); - return PoolByteArray(); + break; } chunk_left = len + 2; @@ -578,18 +603,13 @@ PoolByteArray HTTPClient::read_response_body_chunk() { if (chunk[chunk.size() - 2] != '\r' || chunk[chunk.size() - 1] != '\n') { ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)"); status = STATUS_CONNECTION_ERROR; - return PoolByteArray(); + break; } - PoolByteArray ret; ret.resize(chunk.size() - 2); - { - PoolByteArray::Write w = ret.write(); - copymem(w.ptr(), chunk.ptr(), chunk.size() - 2); - } + PoolByteArray::Write w = ret.write(); + copymem(w.ptr(), chunk.ptr(), chunk.size() - 2); chunk.clear(); - - return ret; } break; @@ -599,45 +619,26 @@ PoolByteArray HTTPClient::read_response_body_chunk() { } else { int to_read = !read_until_eof ? MIN(body_left, read_chunk_size) : read_chunk_size; - PoolByteArray ret; ret.resize(to_read); int _offset = 0; - while (read_until_eof || to_read > 0) { + while (to_read > 0) { int rec = 0; { PoolByteArray::Write w = ret.write(); err = _get_http_data(w.ptr() + _offset, to_read, rec); } - if (rec < 0) { - if (to_read > 0) // Ended up reading less - ret.resize(_offset); + if (rec <= 0) { // Ended up reading less + ret.resize(_offset); break; } else { _offset += rec; + to_read -= rec; if (!read_until_eof) { body_left -= rec; - to_read -= rec; - } else { - if (rec < to_read) { - ret.resize(_offset); - err = ERR_FILE_EOF; - break; - } - ret.resize(_offset + to_read); } } - } - if (!read_until_eof) { - if (body_left == 0) { - status = STATUS_CONNECTED; - } - return ret; - } else { - if (err == ERR_FILE_EOF) { - err = OK; // EOF is expected here - close(); - return ret; - } + if (err != OK) + break; } } @@ -652,12 +653,12 @@ PoolByteArray HTTPClient::read_response_body_chunk() { status = STATUS_CONNECTION_ERROR; } - } else if (body_left == 0 && !chunked) { + } else if (body_left == 0 && !chunked && !read_until_eof) { status = STATUS_CONNECTED; } - return PoolByteArray(); + return ret; } HTTPClient::Status HTTPClient::get_status() const { @@ -719,6 +720,7 @@ HTTPClient::HTTPClient() { body_left = 0; read_until_eof = false; chunk_left = 0; + chunk_trailer_part = false; response_num = 0; ssl = false; blocking = false; diff --git a/core/io/http_client.h b/core/io/http_client.h index 1ad44d5f01..85ee1959a2 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -172,6 +172,7 @@ private: bool chunked; Vector<uint8_t> chunk; int chunk_left; + bool chunk_trailer_part; int body_size; int body_left; bool read_until_eof; diff --git a/core/io/logger.cpp b/core/io/logger.cpp index eeb82bfce4..9175f6a262 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -39,7 +39,7 @@ // va_copy, otherwise you have to use the internal version (__va_copy). #if !defined(va_copy) #if defined(__GNUC__) -#define va_copy(d, s) __va_copy(d, s) +#define va_copy(d, s) __va_copy((d), (s)) #else #define va_copy(d, s) ((d) = (s)) #endif diff --git a/core/io/logger.h b/core/io/logger.h index 0b871a13de..ff5b8ce489 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -49,11 +49,11 @@ public: ERR_SHADER }; - virtual void logv(const char *p_format, va_list p_list, bool p_err) = 0; + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0; virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); - void logf(const char *p_format, ...); - void logf_error(const char *p_format, ...); + void logf(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; + void logf_error(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; virtual ~Logger(); }; @@ -64,7 +64,7 @@ public: class StdLogger : public Logger { public: - virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0; virtual ~StdLogger(); }; @@ -88,7 +88,7 @@ class RotatedFileLogger : public Logger { 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); + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0; virtual ~RotatedFileLogger(); }; @@ -99,7 +99,7 @@ class CompositeLogger : public Logger { public: CompositeLogger(Vector<Logger *> p_loggers); - virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0; virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); void add_logger(Logger *p_logger); diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index eec1c55744..d1b6b82cf0 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -768,7 +768,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int r_variant = carray; } break; - default: { ERR_FAIL_V(ERR_BUG); } + default: { + ERR_FAIL_V(ERR_BUG); + } } return OK; @@ -794,7 +796,7 @@ static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) { } } -Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_object_as_id) { +Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects) { uint8_t *buf = r_buffer; @@ -819,11 +821,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } } break; case Variant::OBJECT: { - if (p_object_as_id) { + if (!p_full_objects) { flags |= ENCODE_FLAG_OBJECT_AS_ID; } } break; - default: {} // nothing to do at this stage + default: { + } // nothing to do at this stage } if (buf) { @@ -889,11 +892,11 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo if (buf) { encode_uint32(uint32_t(np.get_name_count()) | 0x80000000, buf); //for compatibility with the old format encode_uint32(np.get_subname_count(), buf + 4); - uint32_t flags = 0; + uint32_t np_flags = 0; if (np.is_absolute()) - flags |= 1; + np_flags |= 1; - encode_uint32(flags, buf + 8); + encode_uint32(np_flags, buf + 8); buf += 12; } @@ -1086,22 +1089,8 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } break; case Variant::OBJECT: { - if (p_object_as_id) { - - if (buf) { - - Object *obj = p_variant; - ObjectID id = 0; - if (obj && ObjectDB::instance_validate(obj)) { - id = obj->get_instance_id(); - } - - encode_uint64(id, buf); - } - - r_len += 8; + if (p_full_objects) { - } else { Object *obj = p_variant; if (!obj) { if (buf) { @@ -1139,7 +1128,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo _encode_string(E->get().name, buf, r_len); int len; - Error err = encode_variant(obj->get(E->get().name), buf, len, p_object_as_id); + Error err = encode_variant(obj->get(E->get().name), buf, len, p_full_objects); if (err) return err; ERR_FAIL_COND_V(len % 4, ERR_BUG); @@ -1148,6 +1137,19 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo buf += len; } } + } else { + if (buf) { + + Object *obj = p_variant; + ObjectID id = 0; + if (obj && ObjectDB::instance_validate(obj)) { + id = obj->get_instance_id(); + } + + encode_uint64(id, buf); + } + + r_len += 8; } } break; @@ -1180,14 +1182,14 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len++; //pad */ int len; - encode_variant(E->get(), buf, len, p_object_as_id); + encode_variant(E->get(), buf, len, p_full_objects); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) buf += len; Variant *v = d.getptr(E->get()); ERR_FAIL_COND_V(!v, ERR_BUG); - encode_variant(*v, buf, len, p_object_as_id); + encode_variant(*v, buf, len, p_full_objects); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) @@ -1209,7 +1211,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo for (int i = 0; i < v.size(); i++) { int len; - encode_variant(v.get(i), buf, len, p_object_as_id); + encode_variant(v.get(i), buf, len, p_full_objects); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) @@ -1229,11 +1231,15 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo buf += 4; PoolVector<uint8_t>::Read r = data.read(); copymem(buf, &r[0], datalen * datasize); + buf += datalen * datasize; } r_len += 4 + datalen * datasize; - while (r_len % 4) + while (r_len % 4) { r_len++; + if (buf) + *(buf++) = 0; + } } break; case Variant::POOL_INT_ARRAY: { @@ -1386,7 +1392,9 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len += 4 * 4 * len; } break; - default: { ERR_FAIL_V(ERR_BUG); } + default: { + ERR_FAIL_V(ERR_BUG); + } } return OK; diff --git a/core/io/marshalls.h b/core/io/marshalls.h index 11c4b2c98e..f361c29754 100644 --- a/core/io/marshalls.h +++ b/core/io/marshalls.h @@ -199,7 +199,7 @@ public: EncodedObjectAsID(); }; -Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL, bool p_allow_objects = true); -Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_object_as_id = false); +Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL, bool p_allow_objects = false); +Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false); #endif diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 7680d47620..2779837190 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -46,7 +46,8 @@ _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_mas case MultiplayerAPI::RPC_MODE_MASTERSYNC: { if (is_master) r_skip_rpc = true; // I am the master, so skip remote call. - } // Do not break, fall over to other sync. + FALLTHROUGH; + } case MultiplayerAPI::RPC_MODE_REMOTESYNC: case MultiplayerAPI::RPC_MODE_PUPPETSYNC: { // Call it, sync always results in a local call. @@ -282,8 +283,9 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name); } - ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); - ERR_FAIL_COND(!_can_call_mode(p_node, rpc_mode, p_from)); + bool can_call = _can_call_mode(p_node, rpc_mode, p_from); + ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); + ERR_FAIL_COND(!can_call); int argc = p_packet[p_offset]; Vector<Variant> args; @@ -299,7 +301,7 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ ERR_FAIL_COND(p_offset >= p_packet_len); int vlen; - Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen); + Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Invalid packet received. Unable to decode RPC argument."); ERR_FAIL_COND(err != OK); @@ -331,11 +333,12 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p rset_mode = p_node->get_script_instance()->get_rset_mode(p_name); } - ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + "."); - ERR_FAIL_COND(!_can_call_mode(p_node, rset_mode, p_from)); + bool can_call = _can_call_mode(p_node, rset_mode, p_from); + ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + "."); + ERR_FAIL_COND(!can_call); Variant value; - Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset); + Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Invalid packet received. Unable to decode RSET value."); ERR_FAIL_COND(err != OK); @@ -526,11 +529,11 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p if (p_set) { // Set argument. - Error err = encode_variant(*p_arg[0], NULL, len); + Error err = encode_variant(*p_arg[0], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); - encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len); + encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ofs += len; } else { @@ -539,11 +542,11 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p packet_cache.write[ofs] = p_argcount; ofs += 1; for (int i = 0; i < p_argcount; i++) { - Error err = encode_variant(*p_arg[i], NULL, len); + Error err = encode_variant(*p_arg[i], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); - encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len); + encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ofs += len; } } @@ -631,7 +634,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const ERR_FAIL_COND(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED); int node_id = network_peer->get_unique_id(); - bool skip_rpc = false; + bool skip_rpc = node_id == p_peer_id; bool call_local_native = false; bool call_local_script = false; bool is_master = p_node->is_network_master(); @@ -658,8 +661,11 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const } if (call_local_native) { + int temp_id = rpc_sender_id; + rpc_sender_id = get_network_unique_id(); Variant::CallError ce; p_node->call(p_method, p_arg, p_argcount, ce); + rpc_sender_id = temp_id; if (ce.error != Variant::CallError::CALL_OK) { String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); error = "rpc() aborted in local call: - " + error; @@ -669,9 +675,12 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const } if (call_local_script) { + int temp_id = rpc_sender_id; + rpc_sender_id = get_network_unique_id(); Variant::CallError ce; ce.error = Variant::CallError::CALL_OK; p_node->get_script_instance()->call(p_method, p_arg, p_argcount, ce); + rpc_sender_id = temp_id; if (ce.error != Variant::CallError::CALL_OK) { String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); error = "rpc() aborted in script local call: - " + error; @@ -679,6 +688,9 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const return; } } + + ERR_EXPLAIN("RPC '" + p_method + "' on yourself is not allowed by selected mode"); + ERR_FAIL_COND(skip_rpc && !(call_local_native || call_local_script)); } void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) { @@ -692,13 +704,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const int node_id = network_peer->get_unique_id(); bool is_master = p_node->is_network_master(); - bool skip_rset = false; + bool skip_rset = node_id == p_peer_id; + bool set_local = false; if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { // Check that send mode can use local call. - - bool set_local = false; - const Map<StringName, RPCMode>::Element *E = p_node->get_node_rset_mode(p_property); if (E) { @@ -707,7 +717,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const if (set_local) { bool valid; + int temp_id = rpc_sender_id; + + rpc_sender_id = get_network_unique_id(); p_node->set(p_property, p_value, &valid); + rpc_sender_id = temp_id; if (!valid) { String error = "rset() aborted in local set, property not found: - " + String(p_property); @@ -721,8 +735,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const set_local = _should_call_local(rpc_mode, is_master, skip_rset); if (set_local) { + int temp_id = rpc_sender_id; + rpc_sender_id = get_network_unique_id(); bool valid = p_node->get_script_instance()->set(p_property, p_value); + rpc_sender_id = temp_id; if (!valid) { String error = "rset() aborted in local script set, property not found: - " + String(p_property); @@ -733,8 +750,11 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const } } - if (skip_rset) + if (skip_rset) { + ERR_EXPLAIN("RSET for '" + p_property + "' on yourself is not allowed by selected mode"); + ERR_FAIL_COND(!set_local); return; + } const Variant *vptr = &p_value; @@ -818,6 +838,16 @@ Vector<int> MultiplayerAPI::get_network_connected_peers() const { return ret; } +void MultiplayerAPI::set_allow_object_decoding(bool p_enable) { + + allow_object_decoding = p_enable; +} + +bool MultiplayerAPI::is_object_decoding_allowed() const { + + return allow_object_decoding; +} + void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE)); @@ -838,6 +868,10 @@ void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &MultiplayerAPI::get_network_connected_peers); ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &MultiplayerAPI::set_refuse_new_network_connections); ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &MultiplayerAPI::is_refusing_new_network_connections); + ClassDB::bind_method(D_METHOD("set_allow_object_decoding", "enable"), &MultiplayerAPI::set_allow_object_decoding); + ClassDB::bind_method(D_METHOD("is_object_decoding_allowed"), &MultiplayerAPI::is_object_decoding_allowed); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); @@ -859,7 +893,8 @@ void MultiplayerAPI::_bind_methods() { BIND_ENUM_CONSTANT(RPC_MODE_PUPPETSYNC); } -MultiplayerAPI::MultiplayerAPI() { +MultiplayerAPI::MultiplayerAPI() : + allow_object_decoding(false) { rpc_sender_id = 0; root_node = NULL; clear(); diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index a9cf77aaba..779dd043bd 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -63,6 +63,7 @@ private: int last_send_cache_id; Vector<uint8_t> packet_cache; Node *root_node; + bool allow_object_decoding; protected: static void _bind_methods(); @@ -126,6 +127,9 @@ public: void set_refuse_new_network_connections(bool p_refuse); bool is_refusing_new_network_connections() const; + void set_allow_object_decoding(bool p_enable); + bool is_object_decoding_allowed() const; + MultiplayerAPI(); ~MultiplayerAPI(); }; diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 3aa1fcfd8f..c77c81f9e2 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -79,7 +79,7 @@ Error PacketPeer::put_packet_buffer(const PoolVector<uint8_t> &p_buffer) { return put_packet(&r[0], len); } -Error PacketPeer::get_var(Variant &r_variant) { +Error PacketPeer::get_var(Variant &r_variant, bool p_allow_objects) { const uint8_t *buffer; int buffer_size; @@ -87,13 +87,13 @@ Error PacketPeer::get_var(Variant &r_variant) { if (err) return err; - return decode_variant(r_variant, buffer, buffer_size, NULL, allow_object_decoding); + return decode_variant(r_variant, buffer, buffer_size, NULL, p_allow_objects || allow_object_decoding); } -Error PacketPeer::put_var(const Variant &p_packet) { +Error PacketPeer::put_var(const Variant &p_packet, bool p_full_objects) { int len; - Error err = encode_variant(p_packet, NULL, len, !allow_object_decoding); // compute len first + Error err = encode_variant(p_packet, NULL, len, p_full_objects || allow_object_decoding); // compute len first if (err) return err; @@ -102,15 +102,15 @@ Error PacketPeer::put_var(const Variant &p_packet) { uint8_t *buf = (uint8_t *)alloca(len); ERR_FAIL_COND_V(!buf, ERR_OUT_OF_MEMORY); - err = encode_variant(p_packet, buf, len, !allow_object_decoding); + err = encode_variant(p_packet, buf, len, p_full_objects || allow_object_decoding); ERR_FAIL_COND_V(err, err); return put_packet(buf, len); } -Variant PacketPeer::_bnd_get_var() { +Variant PacketPeer::_bnd_get_var(bool p_allow_objects) { Variant var; - get_var(var); + get_var(var, p_allow_objects); return var; }; @@ -132,8 +132,8 @@ Error PacketPeer::_get_packet_error() const { void PacketPeer::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_var"), &PacketPeer::_bnd_get_var); - ClassDB::bind_method(D_METHOD("put_var", "var"), &PacketPeer::put_var); + ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &PacketPeer::_bnd_get_var, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("put_var", "var", "full_objects"), &PacketPeer::put_var, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_packet"), &PacketPeer::_get_packet); ClassDB::bind_method(D_METHOD("put_packet", "buffer"), &PacketPeer::_put_packet); ClassDB::bind_method(D_METHOD("get_packet_error"), &PacketPeer::_get_packet_error); @@ -224,7 +224,7 @@ Error PacketPeerStream::get_packet(const uint8_t **r_buffer, int &r_buffer_size) uint32_t len = decode_uint32(lbuf); ERR_FAIL_COND_V(remaining < (int)len, ERR_UNAVAILABLE); - ERR_FAIL_COND_V(input_buffer.size() < len, ERR_UNAVAILABLE); + ERR_FAIL_COND_V(input_buffer.size() < (int)len, ERR_UNAVAILABLE); ring_buffer.read(lbuf, 4); //get rid of first 4 bytes ring_buffer.read(input_buffer.ptrw(), len); // read packet diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h index 48c50eb76b..6475e4fed9 100644 --- a/core/io/packet_peer.h +++ b/core/io/packet_peer.h @@ -39,8 +39,7 @@ class PacketPeer : public Reference { GDCLASS(PacketPeer, Reference); - Variant _bnd_get_var(); - void _bnd_put_var(const Variant &p_var); + Variant _bnd_get_var(bool p_allow_objects = false); static void _bind_methods(); @@ -64,8 +63,8 @@ public: virtual Error get_packet_buffer(PoolVector<uint8_t> &r_buffer); virtual Error put_packet_buffer(const PoolVector<uint8_t> &p_buffer); - virtual Error get_var(Variant &r_variant); - virtual Error put_var(const Variant &p_packet); + virtual Error get_var(Variant &r_variant, bool p_allow_objects = false); + virtual Error put_var(const Variant &p_packet, bool p_full_objects = false); void set_allow_object_decoding(bool p_enable); bool is_object_decoding_allowed() const; diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index 36bd429bc0..8920bbfb81 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -175,7 +175,7 @@ Error PCKPacker::flush(bool p_verbose) { printf("\n"); file->close(); - memdelete(buf); + memdelete_arr(buf); return OK; }; diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index e27dea37d6..f25abc4aab 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -106,7 +106,7 @@ StringName ResourceInteractiveLoaderBinary::_get_string() { uint32_t id = f->get_32(); if (id & 0x80000000) { uint32_t len = id & 0x7FFFFFFF; - if (len > str_buf.size()) { + if ((int)len > str_buf.size()) { str_buf.resize(len); } if (len == 0) @@ -296,9 +296,9 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { } break; case VARIANT_OBJECT: { - uint32_t type = f->get_32(); + uint32_t objtype = f->get_32(); - switch (type) { + switch (objtype) { case OBJECT_EMPTY: { //do none @@ -317,7 +317,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { case OBJECT_EXTERNAL_RESOURCE: { //old file format, still around for compatibility - String type = get_unicode_string(); + String exttype = get_unicode_string(); String path = get_unicode_string(); if (path.find("://") == -1 && path.is_rel_path()) { @@ -329,7 +329,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { path = remaps[path]; } - RES res = ResourceLoader::load(path, type); + RES res = ResourceLoader::load(path, exttype); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data()); @@ -342,11 +342,11 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { int erindex = f->get_32(); if (erindex < 0 || erindex >= external_resources.size()) { - WARN_PRINT("Broken external resource! (index out of size"); + WARN_PRINT("Broken external resource! (index out of size)"); r_v = Variant(); } else { - String type = external_resources[erindex].type; + String exttype = external_resources[erindex].type; String path = external_resources[erindex].path; if (path.find("://") == -1 && path.is_rel_path()) { @@ -354,7 +354,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); } - RES res = ResourceLoader::load(path, type); + RES res = ResourceLoader::load(path, exttype); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data()); @@ -1314,8 +1314,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia } else { f->store_32(VARIANT_INT); - int val = p_property; - f->store_32(int32_t(val)); + f->store_32(int32_t(p_property)); } } break; @@ -1502,7 +1501,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia if (!resource_set.has(res)) { f->store_32(OBJECT_EMPTY); - ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); + ERR_EXPLAIN("Resource was not pre cached for the resource section, most likely due to circular refedence."); ERR_FAIL(); } @@ -1651,6 +1650,10 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant return; if (!p_main && (!bundle_resources) && res->get_path().length() && res->get_path().find("::") == -1) { + if (res->get_path() == path) { + ERR_PRINTS("Circular reference to resource being saved found: '" + local_path + "' will be null next time it's loaded."); + return; + } int idx = external_resources.size(); external_resources[res] = idx; return; @@ -1667,7 +1670,20 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant if (E->get().usage & PROPERTY_USAGE_STORAGE) { - _find_resources(res->get(E->get().name)); + Variant value = res->get(E->get().name); + if (E->get().usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) { + RES sres = value; + if (sres.is_valid()) { + NonPersistentKey npk; + npk.base = res; + npk.property = E->get().name; + non_persistent_map[npk] = sres; + resource_set.insert(sres); + saved_resources.push_back(sres); + } + } else { + _find_resources(value); + } } } @@ -1709,7 +1725,8 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant get_string_index(np.get_subname(i)); } break; - default: {} + default: { + } } } @@ -1762,6 +1779,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p takeover_paths = false; local_path = p_path.get_base_dir(); + path = ProjectSettings::get_singleton()->localize_path(p_path); _find_resources(p_resource, true); @@ -1811,7 +1829,17 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p if ((F->get().usage & PROPERTY_USAGE_STORAGE)) { Property p; p.name_idx = get_string_index(F->get().name); - p.value = E->get()->get(F->get().name); + + if (F->get().usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT) { + NonPersistentKey npk; + npk.base = E->get(); + npk.property = F->get().name; + if (non_persistent_map.has(npk)) { + p.value = non_persistent_map[npk]; + } + } else { + p.value = E->get()->get(F->get().name); + } Variant default_value = ClassDB::class_get_default_property_value(E->get()->get_class(), F->get().name); diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index 8f2c48e745..a4894e4033 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -114,6 +114,7 @@ public: class ResourceFormatSaverBinaryInstance { String local_path; + String path; bool relative_paths; bool bundle_resources; @@ -123,6 +124,14 @@ class ResourceFormatSaverBinaryInstance { FileAccess *f; String magic; Set<RES> resource_set; + + struct NonPersistentKey { //for resource properties generated on the fly + RES base; + StringName property; + bool operator<(const NonPersistentKey &p_key) const { return base == p_key.base ? property < p_key.property : base < p_key.base; } + }; + + Map<NonPersistentKey, RES> non_persistent_map; Map<StringName, int> string_map; Vector<StringName> strings; diff --git a/core/io/resource_import.cpp b/core/io/resource_importer.cpp index 63dc0b6a26..4a58d37ca5 100644 --- a/core/io/resource_import.cpp +++ b/core/io/resource_importer.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* resource_import.cpp */ +/* resource_importer.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "resource_import.h" +#include "resource_importer.h" #include "core/os/os.h" #include "core/variant_parser.h" +bool ResourceFormatImporter::SortImporterByName::operator()(const Ref<ResourceImporter> &p_a, const Ref<ResourceImporter> &p_b) const { + return p_a->get_importer_name() < p_b->get_importer_name(); +} + Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid) const { Error err; @@ -90,6 +94,10 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy r_path_and_type.type = value; } else if (assign == "importer") { r_path_and_type.importer = value; + } else if (assign == "group_file") { + r_path_and_type.group_file = value; + } else if (assign == "metadata") { + r_path_and_type.metadata = value; } else if (assign == "valid") { if (r_valid) { *r_valid = value; @@ -177,6 +185,11 @@ void ResourceFormatImporter::get_recognized_extensions_for_type(const String &p_ } } +bool ResourceFormatImporter::exists(const String &p_path) const { + + return FileAccess::exists(p_path + ".import"); +} + bool ResourceFormatImporter::recognize_path(const String &p_path, const String &p_for_type) const { return FileAccess::exists(p_path + ".import"); @@ -283,6 +296,14 @@ void ResourceFormatImporter::get_internal_resource_path_list(const String &p_pat memdelete(f); } +String ResourceFormatImporter::get_import_group_file(const String &p_path) const { + + bool valid = true; + PathAndType pat; + _get_path_and_type(p_path, pat, &valid); + return valid ? pat.group_file : String(); +} + bool ResourceFormatImporter::is_import_valid(const String &p_path) const { bool valid = true; @@ -304,6 +325,18 @@ String ResourceFormatImporter::get_resource_type(const String &p_path) const { return pat.type; } +Variant ResourceFormatImporter::get_resource_metadata(const String &p_path) const { + PathAndType pat; + Error err = _get_path_and_type(p_path, pat); + + if (err != OK) { + + return Variant(); + } + + return pat.metadata; +} + void ResourceFormatImporter::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { PathAndType pat; @@ -366,6 +399,40 @@ String ResourceFormatImporter::get_import_base_path(const String &p_for_file) co return "res://.import/" + p_for_file.get_file() + "-" + p_for_file.md5_text(); } +bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) const { + + bool valid = true; + PathAndType pat; + _get_path_and_type(p_path, pat, &valid); + + if (!valid) { + return false; + } + + for (int i = 0; i < importers.size(); i++) { + if (importers[i]->get_importer_name() == pat.importer) { + if (!importers[i]->are_import_settings_valid(p_path)) { //importer thinks this is not valid + return false; + } + } + } + + return true; +} + +String ResourceFormatImporter::get_import_settings_hash() const { + + Vector<Ref<ResourceImporter> > sorted_importers = importers; + + sorted_importers.sort_custom<SortImporterByName>(); + + String hash; + for (int i = 0; i < sorted_importers.size(); i++) { + hash += ":" + sorted_importers[i]->get_importer_name() + ":" + sorted_importers[i]->get_import_settings_string(); + } + return hash.md5_text(); +} + ResourceFormatImporter *ResourceFormatImporter::singleton = NULL; ResourceFormatImporter::ResourceFormatImporter() { diff --git a/core/io/resource_import.h b/core/io/resource_importer.h index 96dd7983e6..2e01989564 100644 --- a/core/io/resource_import.h +++ b/core/io/resource_importer.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* resource_import.h */ +/* resource_importer.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef RESOURCE_IMPORT_H -#define RESOURCE_IMPORT_H +#ifndef RESOURCE_IMPORTER_H +#define RESOURCE_IMPORTER_H #include "core/io/resource_loader.h" @@ -43,12 +43,19 @@ class ResourceFormatImporter : public ResourceFormatLoader { String path; String type; String importer; + String group_file; + Variant metadata; }; Error _get_path_and_type(const String &p_path, PathAndType &r_path_and_type, bool *r_valid = NULL) const; static ResourceFormatImporter *singleton; + //need them to stay in order to compute the settings hash + struct SortImporterByName { + bool operator()(const Ref<ResourceImporter> &p_a, const Ref<ResourceImporter> &p_b) const; + }; + Vector<Ref<ResourceImporter> > importers; public: @@ -59,8 +66,12 @@ public: virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const; virtual bool handles_type(const String &p_type) const; virtual String get_resource_type(const String &p_path) const; + virtual Variant get_resource_metadata(const String &p_path) const; virtual bool is_import_valid(const String &p_path) const; virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); + virtual bool is_imported(const String &p_path) const { return recognize_path(p_path); } + virtual String get_import_group_file(const String &p_path) const; + virtual bool exists(const String &p_path) const; virtual bool can_be_imported(const String &p_path) const; virtual int get_import_order(const String &p_path) const; @@ -68,12 +79,17 @@ public: String get_internal_resource_path(const String &p_path) const; void get_internal_resource_path_list(const String &p_path, List<String> *r_paths); - void add_importer(const Ref<ResourceImporter> &p_importer) { importers.push_back(p_importer); } + void add_importer(const Ref<ResourceImporter> &p_importer) { + importers.push_back(p_importer); + } void remove_importer(const Ref<ResourceImporter> &p_importer) { importers.erase(p_importer); } Ref<ResourceImporter> get_importer_by_name(const String &p_name) const; Ref<ResourceImporter> get_importer_by_extension(const String &p_extension) const; void get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter> > *r_importers); + bool are_import_settings_valid(const String &p_path) const; + String get_import_settings_hash() const; + String get_import_base_path(const String &p_for_file) const; ResourceFormatImporter(); }; @@ -106,8 +122,13 @@ public: virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const = 0; virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const = 0; + virtual String get_option_group_file() const { return String(); } + + virtual Error 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 = NULL, Variant *r_metadata = NULL) = 0; - virtual Error 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 = NULL) = 0; + virtual Error import_group_file(const String &p_group_file, const Map<String, Map<StringName, Variant> > &p_source_file_options, const Map<String, String> &p_base_paths) { return ERR_UNAVAILABLE; } + virtual bool are_import_settings_valid(const String &p_path) const { return true; } + virtual String get_import_settings_string() const { return String(); } }; -#endif // RESOURCE_IMPORT_H +#endif // RESOURCE_IMPORTER_H diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index b8bc24c1de..56d3b8b133 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -30,7 +30,7 @@ #include "resource_loader.h" -#include "core/io/resource_import.h" +#include "core/io/resource_importer.h" #include "core/os/file_access.h" #include "core/os/os.h" #include "core/path_remap.h" @@ -53,6 +53,12 @@ Error ResourceInteractiveLoader::wait() { return err; } +ResourceInteractiveLoader::~ResourceInteractiveLoader() { + if (path_loading != String()) { + ResourceLoader::_remove_from_loading_map_and_thread(path_loading, path_loading_thread); + } +} + bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_for_type) const { String extension = p_path.get_extension(); @@ -280,6 +286,63 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c return RES(); } +bool ResourceLoader::_add_to_loading_map(const String &p_path) { + + bool success; + if (loading_map_mutex) { + loading_map_mutex->lock(); + } + + LoadingMapKey key; + key.path = p_path; + key.thread = Thread::get_caller_id(); + + if (loading_map.has(key)) { + success = false; + } else { + loading_map[key] = true; + success = true; + } + + if (loading_map_mutex) { + loading_map_mutex->unlock(); + } + + return success; +} + +void ResourceLoader::_remove_from_loading_map(const String &p_path) { + if (loading_map_mutex) { + loading_map_mutex->lock(); + } + + LoadingMapKey key; + key.path = p_path; + key.thread = Thread::get_caller_id(); + + loading_map.erase(key); + + if (loading_map_mutex) { + loading_map_mutex->unlock(); + } +} + +void ResourceLoader::_remove_from_loading_map_and_thread(const String &p_path, Thread::ID p_thread) { + if (loading_map_mutex) { + loading_map_mutex->lock(); + } + + LoadingMapKey key; + key.path = p_path; + key.thread = p_thread; + + loading_map.erase(key); + + if (loading_map_mutex) { + loading_map_mutex->unlock(); + } +} + RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) { if (r_error) @@ -292,6 +355,15 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p local_path = ProjectSettings::get_singleton()->localize_path(p_path); if (!p_no_cache) { + + { + bool success = _add_to_loading_map(local_path); + if (!success) { + ERR_EXPLAIN("Resource: '" + local_path + "' is already being loaded. Cyclic reference?"); + ERR_FAIL_V(RES()); + } + } + //lock first if possible if (ResourceCache::lock) { ResourceCache::lock->read_lock(); @@ -310,7 +382,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p if (ResourceCache::lock) { ResourceCache::lock->read_unlock(); } - print_verbose("Loading resource: " + local_path + " (cached)"); + _remove_from_loading_map(local_path); return res; } } @@ -322,12 +394,21 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p bool xl_remapped = false; String path = _path_remap(local_path, &xl_remapped); - ERR_FAIL_COND_V(path == "", RES()); + if (path == "") { + if (!p_no_cache) { + _remove_from_loading_map(local_path); + } + ERR_EXPLAIN("Remapping '" + local_path + "'failed."); + ERR_FAIL_V(RES()); + } print_verbose("Loading resource: " + path); RES res = _load(path, local_path, p_type_hint, p_no_cache, r_error); if (res.is_null()) { + if (!p_no_cache) { + _remove_from_loading_map(local_path); + } return RES(); } if (!p_no_cache) @@ -346,6 +427,10 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p } #endif + if (!p_no_cache) { + _remove_from_loading_map(local_path); + } + if (_loaded_callback) { _loaded_callback(res, p_path); } @@ -394,19 +479,37 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ else local_path = ProjectSettings::get_singleton()->localize_path(p_path); - if (!p_no_cache && ResourceCache::has(local_path)) { + if (!p_no_cache) { + + bool success = _add_to_loading_map(local_path); + if (!success) { + ERR_EXPLAIN("Resource: '" + local_path + "' is already being loaded. Cyclic reference?"); + ERR_FAIL_V(RES()); + } + + if (ResourceCache::has(local_path)) { - print_verbose("Loading resource: " + local_path + " (cached)"); - Ref<Resource> res_cached = ResourceCache::get(local_path); - Ref<ResourceInteractiveLoaderDefault> ril = Ref<ResourceInteractiveLoaderDefault>(memnew(ResourceInteractiveLoaderDefault)); + print_verbose("Loading resource: " + local_path + " (cached)"); + Ref<Resource> res_cached = ResourceCache::get(local_path); + Ref<ResourceInteractiveLoaderDefault> ril = Ref<ResourceInteractiveLoaderDefault>(memnew(ResourceInteractiveLoaderDefault)); - ril->resource = res_cached; - return ril; + ril->resource = res_cached; + ril->path_loading = local_path; + ril->path_loading_thread = Thread::get_caller_id(); + return ril; + } } bool xl_remapped = false; String path = _path_remap(local_path, &xl_remapped); - ERR_FAIL_COND_V(path == "", Ref<ResourceInteractiveLoader>()); + if (path == "") { + if (!p_no_cache) { + _remove_from_loading_map(local_path); + } + ERR_EXPLAIN("Remapping '" + local_path + "'failed."); + ERR_FAIL_V(RES()); + } + print_verbose("Loading resource: " + path); bool found = false; @@ -418,14 +521,22 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(path, local_path, r_error); if (ril.is_null()) continue; - if (!p_no_cache) + if (!p_no_cache) { ril->set_local_path(local_path); + ril->path_loading = local_path; + ril->path_loading_thread = Thread::get_caller_id(); + } + if (xl_remapped) ril->set_translation_remapped(true); return ril; } + if (!p_no_cache) { + _remove_from_loading_map(local_path); + } + if (found) { ERR_EXPLAIN("Failed loading resource: " + path); } else { @@ -497,6 +608,30 @@ int ResourceLoader::get_import_order(const String &p_path) { return 0; } +String ResourceLoader::get_import_group_file(const String &p_path) { + String path = _path_remap(p_path); + + String local_path; + if (path.is_rel_path()) + local_path = "res://" + path; + else + local_path = ProjectSettings::get_singleton()->localize_path(path); + + for (int i = 0; i < loader_count; i++) { + + if (!loader[i]->recognize_path(local_path)) + continue; + /* + if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) + continue; + */ + + return loader[i]->get_import_group_file(p_path); + } + + return String(); //not found +} + bool ResourceLoader::is_import_valid(const String &p_path) { String path = _path_remap(p_path); @@ -522,6 +657,31 @@ bool ResourceLoader::is_import_valid(const String &p_path) { return false; //not found } +bool ResourceLoader::is_imported(const String &p_path) { + + String path = _path_remap(p_path); + + String local_path; + if (path.is_rel_path()) + local_path = "res://" + path; + else + local_path = ProjectSettings::get_singleton()->localize_path(path); + + for (int i = 0; i < loader_count; i++) { + + if (!loader[i]->recognize_path(local_path)) + continue; + /* + if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) + continue; + */ + + return loader[i]->is_imported(p_path); + } + + return false; //not found +} + void ResourceLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { String path = _path_remap(p_path); @@ -794,9 +954,9 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) { void ResourceLoader::remove_custom_resource_format_loader(String script_path) { - Ref<ResourceFormatLoader> loader = _find_custom_resource_format_loader(script_path); - if (loader.is_valid()) - remove_resource_format_loader(loader); + Ref<ResourceFormatLoader> custom_loader = _find_custom_resource_format_loader(script_path); + if (custom_loader.is_valid()) + remove_resource_format_loader(custom_loader); } void ResourceLoader::add_custom_loaders() { @@ -810,7 +970,7 @@ void ResourceLoader::add_custom_loaders() { for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { StringName class_name = E->get(); - StringName base_class = ScriptServer::get_global_class_base(class_name); + StringName base_class = ScriptServer::get_global_class_native_base(class_name); if (base_class == custom_loader_base_class) { String path = ScriptServer::get_global_class_path(class_name); @@ -833,6 +993,27 @@ void ResourceLoader::remove_custom_loaders() { } } +Mutex *ResourceLoader::loading_map_mutex = NULL; +HashMap<ResourceLoader::LoadingMapKey, int, ResourceLoader::LoadingMapKeyHasher> ResourceLoader::loading_map; + +void ResourceLoader::initialize() { +#ifndef NO_THREADS + loading_map_mutex = Mutex::create(); +#endif +} + +void ResourceLoader::finalize() { +#ifndef NO_THREADS + const LoadingMapKey *K = NULL; + while ((K = loading_map.next(K))) { + ERR_PRINTS("Exited while resource is being loaded: " + K->path); + } + loading_map.clear(); + memdelete(loading_map_mutex); + loading_map_mutex = NULL; +#endif +} + ResourceLoadErrorNotify ResourceLoader::err_notify = NULL; void *ResourceLoader::err_notify_ud = NULL; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 6c0e9d5554..9e7020be7c 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -31,8 +31,8 @@ #ifndef RESOURCE_LOADER_H #define RESOURCE_LOADER_H +#include "core/os/thread.h" #include "core/resource.h" - /** @author Juan Linietsky <reduzio@gmail.com> */ @@ -40,6 +40,9 @@ class ResourceInteractiveLoader : public Reference { GDCLASS(ResourceInteractiveLoader, Reference); + friend class ResourceLoader; + String path_loading; + Thread::ID path_loading_thread; protected: static void _bind_methods(); @@ -54,6 +57,7 @@ public: virtual Error wait(); ResourceInteractiveLoader() {} + ~ResourceInteractiveLoader(); }; class ResourceFormatLoader : public Reference { @@ -75,7 +79,9 @@ public: virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map); virtual bool is_import_valid(const String &p_path) const { return true; } + virtual bool is_imported(const String &p_path) const { return false; } virtual int get_import_order(const String &p_path) const { return 0; } + virtual String get_import_group_file(const String &p_path) const { return ""; } //no group virtual ~ResourceFormatLoader() {} }; @@ -110,12 +116,33 @@ class ResourceLoader { static SelfList<Resource>::List remapped_list; friend class ResourceFormatImporter; + friend class ResourceInteractiveLoader; //internal load function static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error); static ResourceLoadedCallback _loaded_callback; static Ref<ResourceFormatLoader> _find_custom_resource_format_loader(String path); + static Mutex *loading_map_mutex; + + //used to track paths being loaded in a thread, avoids cyclic recursion + struct LoadingMapKey { + String path; + Thread::ID thread; + bool operator==(const LoadingMapKey &p_key) const { + return (thread == p_key.thread && path == p_key.path); + } + }; + struct LoadingMapKeyHasher { + + static _FORCE_INLINE_ uint32_t hash(const LoadingMapKey &p_key) { return p_key.path.hash() + HashMapHasherDefault::hash(p_key.thread); } + }; + + static HashMap<LoadingMapKey, int, LoadingMapKeyHasher> loading_map; + + static bool _add_to_loading_map(const String &p_path); + static void _remove_from_loading_map(const String &p_path); + static void _remove_from_loading_map_and_thread(const String &p_path, Thread::ID p_thread); public: static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); @@ -129,6 +156,8 @@ public: static void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); static Error rename_dependencies(const String &p_path, const Map<String, String> &p_map); static bool is_import_valid(const String &p_path); + static String get_import_group_file(const String &p_path); + static bool is_imported(const String &p_path); static int get_import_order(const String &p_path); static void set_timestamp_on_load(bool p_timestamp) { timestamp_on_load = p_timestamp; } @@ -170,6 +199,9 @@ public: static void remove_custom_resource_format_loader(String script_path); static void add_custom_loaders(); static void remove_custom_loaders(); + + static void initialize(); + static void finalize(); }; #endif diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 279788796c..0cecca904d 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -233,9 +233,9 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) { void ResourceSaver::remove_custom_resource_format_saver(String script_path) { - Ref<ResourceFormatSaver> saver = _find_custom_resource_format_saver(script_path); - if (saver.is_valid()) - remove_resource_format_saver(saver); + Ref<ResourceFormatSaver> custom_saver = _find_custom_resource_format_saver(script_path); + if (custom_saver.is_valid()) + remove_resource_format_saver(custom_saver); } void ResourceSaver::add_custom_savers() { @@ -249,7 +249,7 @@ void ResourceSaver::add_custom_savers() { for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { StringName class_name = E->get(); - StringName base_class = ScriptServer::get_global_class_base(class_name); + StringName base_class = ScriptServer::get_global_class_native_base(class_name); if (base_class == custom_saver_base_class) { String path = ScriptServer::get_global_class_path(class_name); diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp index 3042c0f60a..6ad24a5f3a 100644 --- a/core/io/stream_peer.cpp +++ b/core/io/stream_peer.cpp @@ -221,14 +221,14 @@ void StreamPeer::put_utf8_string(const String &p_string) { put_u32(cs.length()); put_data((const uint8_t *)cs.get_data(), cs.length()); } -void StreamPeer::put_var(const Variant &p_variant) { +void StreamPeer::put_var(const Variant &p_variant, bool p_full_objects) { int len = 0; Vector<uint8_t> buf; - encode_variant(p_variant, NULL, len); + encode_variant(p_variant, NULL, len, p_full_objects); buf.resize(len); put_32(len); - encode_variant(p_variant, buf.ptrw(), len); + encode_variant(p_variant, buf.ptrw(), len, p_full_objects); put_data(buf.ptr(), buf.size()); } @@ -359,7 +359,7 @@ String StreamPeer::get_utf8_string(int p_bytes) { ret.parse_utf8((const char *)buf.ptr(), buf.size()); return ret; } -Variant StreamPeer::get_var() { +Variant StreamPeer::get_var(bool p_allow_objects) { int len = get_32(); Vector<uint8_t> var; @@ -369,7 +369,7 @@ Variant StreamPeer::get_var() { ERR_FAIL_COND_V(err != OK, Variant()); Variant ret; - decode_variant(ret, var.ptr(), len); + decode_variant(ret, var.ptr(), len, NULL, p_allow_objects); return ret; } @@ -398,7 +398,7 @@ void StreamPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("put_double", "value"), &StreamPeer::put_double); ClassDB::bind_method(D_METHOD("put_string", "value"), &StreamPeer::put_string); ClassDB::bind_method(D_METHOD("put_utf8_string", "value"), &StreamPeer::put_utf8_string); - ClassDB::bind_method(D_METHOD("put_var", "value"), &StreamPeer::put_var); + ClassDB::bind_method(D_METHOD("put_var", "value", "full_objects"), &StreamPeer::put_var, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_8"), &StreamPeer::get_8); ClassDB::bind_method(D_METHOD("get_u8"), &StreamPeer::get_u8); @@ -412,7 +412,7 @@ void StreamPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_double"), &StreamPeer::get_double); ClassDB::bind_method(D_METHOD("get_string", "bytes"), &StreamPeer::get_string, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_utf8_string", "bytes"), &StreamPeer::get_utf8_string, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("get_var"), &StreamPeer::get_var); + ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &StreamPeer::get_var, DEFVAL(false)); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian_enabled"); } diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h index 059ccd016c..65e70995ad 100644 --- a/core/io/stream_peer.h +++ b/core/io/stream_peer.h @@ -73,7 +73,7 @@ public: void put_double(double p_val); void put_string(const String &p_string); void put_utf8_string(const String &p_string); - void put_var(const Variant &p_variant); + void put_var(const Variant &p_variant, bool p_full_objects = false); uint8_t get_u8(); int8_t get_8(); @@ -87,7 +87,7 @@ public: double get_double(); String get_string(int p_bytes = -1); String get_utf8_string(int p_bytes = -1); - Variant get_var(); + Variant get_var(bool p_allow_objects = false); StreamPeer() { big_endian = false; } }; diff --git a/core/io/zip_io.h b/core/io/zip_io.h index fb63878a4c..4eb1c8b46c 100644 --- a/core/io/zip_io.h +++ b/core/io/zip_io.h @@ -33,7 +33,7 @@ #include "core/os/file_access.h" -// Not direclty used in this header, but assumed available in downstream users +// Not directly used in this header, but assumed available in downstream users // like platform/*/export/export.cpp. Could be fixed, but probably better to have // thirdparty includes in as little headers as possible. #include "thirdparty/minizip/unzip.h" |