summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/project_settings.cpp24
-rw-r--r--core/core_bind.cpp645
-rw-r--r--core/core_bind.h154
-rw-r--r--core/extension/extension_api_dump.cpp2
-rw-r--r--core/extension/gdnative_interface.cpp2
-rw-r--r--core/io/dir_access.cpp160
-rw-r--r--core/io/dir_access.h33
-rw-r--r--core/io/file_access.cpp206
-rw-r--r--core/io/file_access.h32
-rw-r--r--core/io/file_access_compressed.cpp2
-rw-r--r--core/io/file_access_compressed.h2
-rw-r--r--core/io/file_access_encrypted.cpp2
-rw-r--r--core/io/file_access_encrypted.h2
-rw-r--r--core/io/file_access_memory.cpp2
-rw-r--r--core/io/file_access_memory.h2
-rw-r--r--core/io/file_access_network.cpp2
-rw-r--r--core/io/file_access_network.h2
-rw-r--r--core/io/file_access_pack.cpp2
-rw-r--r--core/io/file_access_pack.h2
-rw-r--r--core/io/file_access_zip.cpp2
-rw-r--r--core/io/file_access_zip.h2
-rw-r--r--core/io/image_loader.cpp54
-rw-r--r--core/io/image_loader.h51
-rw-r--r--core/io/json.cpp23
-rw-r--r--core/io/json.h6
-rw-r--r--core/io/resource_format_binary.cpp4
-rw-r--r--core/io/stream_peer_gzip.cpp209
-rw-r--r--core/io/stream_peer_gzip.h76
-rw-r--r--core/math/math_fieldwise.cpp4
-rw-r--r--core/math/math_funcs.h44
-rw-r--r--core/math/vector2i.h2
-rw-r--r--core/math/vector3i.h2
-rw-r--r--core/math/vector4.h2
-rw-r--r--core/math/vector4i.h2
-rw-r--r--core/object/undo_redo.cpp160
-rw-r--r--core/object/undo_redo.h34
-rw-r--r--core/os/os.h5
-rw-r--r--core/register_core_types.cpp8
38 files changed, 973 insertions, 995 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 6275502378..a1b22e7f7d 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -101,10 +101,15 @@ const PackedStringArray ProjectSettings::_get_supported_features() {
features.append(VERSION_BRANCH "." _MKSTR(VERSION_PATCH));
features.append(VERSION_FULL_CONFIG);
features.append(VERSION_FULL_BUILD);
- // For now, assume Vulkan is always supported.
- // This should be removed if it's possible to build the editor without Vulkan.
- features.append("Vulkan Clustered");
- features.append("Vulkan Mobile");
+
+#ifdef VULKAN_ENABLED
+ features.append("Forward Plus");
+ features.append("Mobile");
+#endif
+
+#ifdef GLES3_ENABLED
+ features.append("GL Compatibility");
+#endif
return features;
}
@@ -909,7 +914,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
project_features = ProjectSettings::get_required_features();
}
// Check the rendering API.
- const String rendering_api = has_setting("rendering/quality/driver/driver_name") ? (String)get_setting("rendering/quality/driver/driver_name") : String();
+ const String rendering_api = has_setting("rendering/renderer/rendering_method") ? (String)get_setting("rendering/renderer/rendering_method") : String();
if (!rendering_api.is_empty()) {
// Add the rendering API as a project feature if it doesn't already exist.
if (!project_features.has(rendering_api)) {
@@ -1139,6 +1144,7 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order);
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value);
ClassDB::bind_method(D_METHOD("add_property_info", "hint"), &ProjectSettings::_add_property_info_bind);
+ ClassDB::bind_method(D_METHOD("set_restart_if_changed", "name", "restart"), &ProjectSettings::set_restart_if_changed);
ClassDB::bind_method(D_METHOD("clear", "name"), &ProjectSettings::clear);
ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path);
ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path);
@@ -1201,10 +1207,16 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC("display/window/size/viewport_height", 648);
custom_prop_info["display/window/size/viewport_height"] = PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+ GLOBAL_DEF_BASIC("display/window/size/mode", 0);
+ custom_prop_info["display/window/size/mode"] = PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen");
+
GLOBAL_DEF_BASIC("display/window/size/resizable", true);
GLOBAL_DEF_BASIC("display/window/size/borderless", false);
- GLOBAL_DEF_BASIC("display/window/size/fullscreen", false);
GLOBAL_DEF("display/window/size/always_on_top", false);
+ GLOBAL_DEF("display/window/size/transparent", false);
+ GLOBAL_DEF("display/window/size/extend_to_title", false);
+ GLOBAL_DEF("display/window/size/no_focus", false);
+
GLOBAL_DEF("display/window/size/window_width_override", 0);
custom_prop_info["display/window/size/window_width_override"] = PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
GLOBAL_DEF("display/window/size/window_height_override", 0);
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index ba48adff6a..a164221fc2 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -709,6 +709,17 @@ Vector<Point2> Geometry2D::convex_hull(const Vector<Point2> &p_points) {
return ::Geometry2D::convex_hull(p_points);
}
+TypedArray<PackedVector2Array> Geometry2D::decompose_polygon_in_convex(const Vector<Vector2> &p_polygon) {
+ Vector<Vector<Point2>> decomp = ::Geometry2D::decompose_polygon_in_convex(p_polygon);
+
+ TypedArray<PackedVector2Array> ret;
+
+ for (int i = 0; i < decomp.size(); ++i) {
+ ret.push_back(decomp[i]);
+ }
+ return ret;
+}
+
TypedArray<PackedVector2Array> Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::merge_polygons(p_polygon_a, p_polygon_b);
@@ -810,14 +821,13 @@ Dictionary Geometry2D::make_atlas(const Vector<Size2> &p_rects) {
::Geometry2D::make_atlas(rects, result, size);
- Size2 r_size = size;
Vector<Point2> r_result;
for (int i = 0; i < result.size(); i++) {
r_result.push_back(result[i]);
}
ret["points"] = r_result;
- ret["size"] = r_size;
+ ret["size"] = size;
return ret;
}
@@ -841,6 +851,7 @@ void Geometry2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("triangulate_polygon", "polygon"), &Geometry2D::triangulate_polygon);
ClassDB::bind_method(D_METHOD("triangulate_delaunay", "points"), &Geometry2D::triangulate_delaunay);
ClassDB::bind_method(D_METHOD("convex_hull", "points"), &Geometry2D::convex_hull);
+ ClassDB::bind_method(D_METHOD("decompose_polygon_in_convex", "polygon"), &Geometry2D::decompose_polygon_in_convex);
ClassDB::bind_method(D_METHOD("merge_polygons", "polygon_a", "polygon_b"), &Geometry2D::merge_polygons);
ClassDB::bind_method(D_METHOD("clip_polygons", "polygon_a", "polygon_b"), &Geometry2D::clip_polygons);
@@ -992,636 +1003,6 @@ void Geometry3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &Geometry3D::clip_polygon);
}
-////// File //////
-
-Error File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
- Error err = open(p_path, p_mode_flags);
- if (err) {
- return err;
- }
-
- 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) {
- close();
- return err;
- }
- f = fae;
- return OK;
-}
-
-Error File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
- Error err = open(p_path, p_mode_flags);
- if (err) {
- return err;
- }
-
- 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) {
- close();
- return err;
- }
-
- f = fae;
- return OK;
-}
-
-Error File::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
- Ref<FileAccessCompressed> fac;
- fac.instantiate();
- fac->configure("GCPF", (Compression::Mode)p_compress_mode);
-
- Error err = fac->_open(p_path, p_mode_flags);
-
- if (err) {
- return err;
- }
-
- f = fac;
- return OK;
-}
-
-Error File::open(const String &p_path, ModeFlags p_mode_flags) {
- Error err;
- f = FileAccess::open(p_path, p_mode_flags, &err);
- if (f.is_valid()) {
- f->set_big_endian(big_endian);
- }
- return err;
-}
-
-void File::flush() {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before flushing.");
- f->flush();
-}
-
-void File::close() {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened.");
- f.unref();
-}
-
-bool File::is_open() const {
- return f != nullptr;
-}
-
-String File::get_path() const {
- 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.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.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.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.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.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.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.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.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.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.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.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.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.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.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) {
- return data;
- }
-
- Error err = data.resize(p_length);
- ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements.");
-
- uint8_t *w = data.ptrw();
- int64_t len = f->get_buffer(&w[0], p_length);
-
- if (len < p_length) {
- data.resize(len);
- }
-
- return data;
-}
-
-String File::get_as_text(bool p_skip_cr) const {
- ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission.");
-
- uint64_t original_pos = f->get_position();
- const_cast<FileAccess *>(*f)->seek(0);
-
- String text = f->get_as_utf8_string(p_skip_cr);
-
- const_cast<FileAccess *>(*f)->seek(original_pos);
-
- return text;
-}
-
-String File::get_md5(const String &p_path) const {
- return FileAccess::get_md5(p_path);
-}
-
-String File::get_sha256(const String &p_path) const {
- return FileAccess::get_sha256(p_path);
-}
-
-String File::get_line() const {
- 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.is_null(), Vector<String>(), "File must be opened before use, or is lacking read-write permission.");
- return f->get_csv_line(p_delim);
-}
-
-/**< use this for files WRITTEN in _big_ endian machines (i.e. amiga/mac)
- * It's not about the current CPU type but file formats.
- * These flags get reset to false (little endian) on each open
- */
-
-void File::set_big_endian(bool p_big_endian) {
- big_endian = p_big_endian;
- if (f.is_valid()) {
- f->set_big_endian(p_big_endian);
- }
-}
-
-bool File::is_big_endian() {
- return big_endian;
-}
-
-Error File::get_error() const {
- if (f.is_null()) {
- return ERR_UNCONFIGURED;
- }
- return f->get_error();
-}
-
-void File::store_8(uint8_t p_dest) {
- 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.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.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.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.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.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.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.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.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.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.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.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.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- uint64_t len = p_buffer.size();
- if (len == 0) {
- return;
- }
-
- const uint8_t *r = p_buffer.ptr();
-
- f->store_buffer(&r[0], len);
-}
-
-bool File::file_exists(const String &p_name) {
- return FileAccess::exists(p_name);
-}
-
-void File::store_var(const Variant &p_var, bool p_full_objects) {
- 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.");
-
- Vector<uint8_t> buff;
- buff.resize(len);
-
- uint8_t *w = buff.ptrw();
- err = encode_variant(p_var, &w[0], len, p_full_objects);
- ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
-
- store_32(len);
- store_buffer(buff);
-}
-
-Variant File::get_var(bool p_allow_objects) const {
- 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());
-
- const uint8_t *r = buff.ptr();
-
- Variant v;
- Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects);
- ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant.");
-
- return v;
-}
-
-uint64_t File::get_modified_time(const String &p_file) const {
- return FileAccess::get_modified_time(p_file);
-}
-
-void File::_bind_methods() {
- ClassDB::bind_method(D_METHOD("open_encrypted", "path", "mode_flags", "key"), &File::open_encrypted);
- ClassDB::bind_method(D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &File::open_encrypted_pass);
- ClassDB::bind_method(D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &File::open_compressed, DEFVAL(0));
-
- ClassDB::bind_method(D_METHOD("open", "path", "flags"), &File::open);
- ClassDB::bind_method(D_METHOD("flush"), &File::flush);
- ClassDB::bind_method(D_METHOD("close"), &File::close);
- ClassDB::bind_method(D_METHOD("get_path"), &File::get_path);
- ClassDB::bind_method(D_METHOD("get_path_absolute"), &File::get_path_absolute);
- ClassDB::bind_method(D_METHOD("is_open"), &File::is_open);
- ClassDB::bind_method(D_METHOD("seek", "position"), &File::seek);
- ClassDB::bind_method(D_METHOD("seek_end", "position"), &File::seek_end, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("get_position"), &File::get_position);
- ClassDB::bind_method(D_METHOD("get_length"), &File::get_length);
- ClassDB::bind_method(D_METHOD("eof_reached"), &File::eof_reached);
- ClassDB::bind_method(D_METHOD("get_8"), &File::get_8);
- ClassDB::bind_method(D_METHOD("get_16"), &File::get_16);
- ClassDB::bind_method(D_METHOD("get_32"), &File::get_32);
- ClassDB::bind_method(D_METHOD("get_64"), &File::get_64);
- ClassDB::bind_method(D_METHOD("get_float"), &File::get_float);
- ClassDB::bind_method(D_METHOD("get_double"), &File::get_double);
- ClassDB::bind_method(D_METHOD("get_real"), &File::get_real);
- ClassDB::bind_method(D_METHOD("get_buffer", "length"), &File::get_buffer);
- ClassDB::bind_method(D_METHOD("get_line"), &File::get_line);
- ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &File::get_csv_line, DEFVAL(","));
- ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &File::get_as_text, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_md5", "path"), &File::get_md5);
- ClassDB::bind_method(D_METHOD("get_sha256", "path"), &File::get_sha256);
- ClassDB::bind_method(D_METHOD("is_big_endian"), &File::is_big_endian);
- ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &File::set_big_endian);
- ClassDB::bind_method(D_METHOD("get_error"), &File::get_error);
- ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &File::get_var, DEFVAL(false));
-
- ClassDB::bind_method(D_METHOD("store_8", "value"), &File::store_8);
- ClassDB::bind_method(D_METHOD("store_16", "value"), &File::store_16);
- ClassDB::bind_method(D_METHOD("store_32", "value"), &File::store_32);
- ClassDB::bind_method(D_METHOD("store_64", "value"), &File::store_64);
- ClassDB::bind_method(D_METHOD("store_float", "value"), &File::store_float);
- ClassDB::bind_method(D_METHOD("store_double", "value"), &File::store_double);
- ClassDB::bind_method(D_METHOD("store_real", "value"), &File::store_real);
- ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &File::store_buffer);
- ClassDB::bind_method(D_METHOD("store_line", "line"), &File::store_line);
- ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &File::store_csv_line, DEFVAL(","));
- ClassDB::bind_method(D_METHOD("store_string", "string"), &File::store_string);
- ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &File::store_var, DEFVAL(false));
-
- ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &File::store_pascal_string);
- ClassDB::bind_method(D_METHOD("get_pascal_string"), &File::get_pascal_string);
-
- ClassDB::bind_static_method("File", D_METHOD("file_exists", "path"), &File::file_exists);
- ClassDB::bind_method(D_METHOD("get_modified_time", "file"), &File::get_modified_time);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
-
- BIND_ENUM_CONSTANT(READ);
- BIND_ENUM_CONSTANT(WRITE);
- BIND_ENUM_CONSTANT(READ_WRITE);
- BIND_ENUM_CONSTANT(WRITE_READ);
-
- BIND_ENUM_CONSTANT(COMPRESSION_FASTLZ);
- BIND_ENUM_CONSTANT(COMPRESSION_DEFLATE);
- BIND_ENUM_CONSTANT(COMPRESSION_ZSTD);
- BIND_ENUM_CONSTANT(COMPRESSION_GZIP);
-}
-
-////// Directory //////
-
-Error Directory::open(const String &p_path) {
- Error err;
- Ref<DirAccess> alt = DirAccess::open(p_path, &err);
- if (alt.is_null()) {
- return err;
- }
- d = alt;
- dir_open = true;
-
- return OK;
-}
-
-bool Directory::is_open() const {
- return d.is_valid() && dir_open;
-}
-
-Error Directory::list_dir_begin() {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- return d->list_dir_begin();
-}
-
-String Directory::get_next() {
- ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
-
- String next = d->get_next();
- while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && d->current_is_hidden()))) {
- next = d->get_next();
- }
- return next;
-}
-
-bool Directory::current_is_dir() const {
- ERR_FAIL_COND_V_MSG(!is_open(), false, "Directory must be opened before use.");
- return d->current_is_dir();
-}
-
-void Directory::list_dir_end() {
- ERR_FAIL_COND_MSG(!is_open(), "Directory must be opened before use.");
- d->list_dir_end();
-}
-
-PackedStringArray Directory::get_files() {
- return _get_contents(false);
-}
-
-PackedStringArray Directory::get_directories() {
- return _get_contents(true);
-}
-
-PackedStringArray Directory::_get_contents(bool p_directories) {
- PackedStringArray ret;
- ERR_FAIL_COND_V_MSG(!is_open(), ret, "Directory must be opened before use.");
-
- list_dir_begin();
- String s = get_next();
- while (!s.is_empty()) {
- if (current_is_dir() == p_directories) {
- ret.append(s);
- }
- s = get_next();
- }
-
- ret.sort();
- return ret;
-}
-
-void Directory::set_include_navigational(bool p_enable) {
- include_navigational = p_enable;
-}
-
-bool Directory::get_include_navigational() const {
- return include_navigational;
-}
-
-void Directory::set_include_hidden(bool p_enable) {
- include_hidden = p_enable;
-}
-
-bool Directory::get_include_hidden() const {
- return include_hidden;
-}
-
-int Directory::get_drive_count() {
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
- return d->get_drive_count();
-}
-
-String Directory::get_drive(int p_drive) {
- ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
- return d->get_drive(p_drive);
-}
-
-int Directory::get_current_drive() {
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
- return d->get_current_drive();
-}
-
-Error Directory::change_dir(String p_dir) {
- 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) {
- return err;
- }
- dir_open = true;
-
- return OK;
-}
-
-String Directory::get_current_dir() {
- ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
- return d->get_current_dir();
-}
-
-Error Directory::make_dir(String p_dir) {
- ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
- if (!p_dir.is_relative_path()) {
- 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.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
- if (!p_dir.is_relative_path()) {
- 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.is_null(), false, "Directory is not configured properly.");
- if (!p_file.is_relative_path()) {
- return FileAccess::exists(p_file);
- }
- return d->file_exists(p_file);
-}
-
-bool Directory::dir_exists(String p_dir) {
- 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);
- }
- return d->dir_exists(p_dir);
-}
-
-uint64_t Directory::get_space_left() {
- 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.
-}
-
-Error Directory::copy(String p_from, String p_to) {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- return d->copy(p_from, p_to);
-}
-
-Error Directory::rename(String p_from, String p_to) {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- 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()) {
- 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);
- }
-
- ERR_FAIL_COND_V_MSG(!d->file_exists(p_from) && !d->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
- return d->rename(p_from, 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()) {
- Ref<DirAccess> da = DirAccess::create_for_path(p_name);
- return da->remove(p_name);
- }
-
- return d->remove(p_name);
-}
-
-void Directory::_bind_methods() {
- ClassDB::bind_method(D_METHOD("open", "path"), &Directory::open);
- ClassDB::bind_method(D_METHOD("list_dir_begin"), &Directory::list_dir_begin, DEFVAL(false), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_next"), &Directory::get_next);
- ClassDB::bind_method(D_METHOD("current_is_dir"), &Directory::current_is_dir);
- ClassDB::bind_method(D_METHOD("list_dir_end"), &Directory::list_dir_end);
- ClassDB::bind_method(D_METHOD("get_files"), &Directory::get_files);
- ClassDB::bind_method(D_METHOD("get_directories"), &Directory::get_directories);
- ClassDB::bind_method(D_METHOD("get_drive_count"), &Directory::get_drive_count);
- ClassDB::bind_method(D_METHOD("get_drive", "idx"), &Directory::get_drive);
- ClassDB::bind_method(D_METHOD("get_current_drive"), &Directory::get_current_drive);
- ClassDB::bind_method(D_METHOD("change_dir", "todir"), &Directory::change_dir);
- ClassDB::bind_method(D_METHOD("get_current_dir"), &Directory::get_current_dir);
- ClassDB::bind_method(D_METHOD("make_dir", "path"), &Directory::make_dir);
- ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &Directory::make_dir_recursive);
- ClassDB::bind_method(D_METHOD("file_exists", "path"), &Directory::file_exists);
- ClassDB::bind_method(D_METHOD("dir_exists", "path"), &Directory::dir_exists);
- ClassDB::bind_method(D_METHOD("get_space_left"), &Directory::get_space_left);
- ClassDB::bind_method(D_METHOD("copy", "from", "to"), &Directory::copy);
- ClassDB::bind_method(D_METHOD("rename", "from", "to"), &Directory::rename);
- ClassDB::bind_method(D_METHOD("remove", "path"), &Directory::remove);
-
- ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &Directory::set_include_navigational);
- ClassDB::bind_method(D_METHOD("get_include_navigational"), &Directory::get_include_navigational);
- ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &Directory::set_include_hidden);
- ClassDB::bind_method(D_METHOD("get_include_hidden"), &Directory::get_include_hidden);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
-}
-
-Directory::Directory() {
- d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
-}
-
////// Marshalls //////
Marshalls *Marshalls::singleton = nullptr;
diff --git a/core/core_bind.h b/core/core_bind.h
index 0f85e473a5..3ca2da0acf 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -289,6 +289,7 @@ public:
Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon);
Vector<int> triangulate_delaunay(const Vector<Vector2> &p_points);
Vector<Point2> convex_hull(const Vector<Point2> &p_points);
+ TypedArray<PackedVector2Array> decompose_polygon_in_convex(const Vector<Vector2> &p_polygon);
enum PolyBooleanOperation {
OPERATION_UNION,
@@ -355,156 +356,6 @@ public:
Geometry3D() { singleton = this; }
};
-class File : public RefCounted {
- GDCLASS(File, RefCounted);
-
- Ref<FileAccess> f;
- bool big_endian = false;
-
-protected:
- static void _bind_methods();
-
-public:
- enum ModeFlags {
- READ = 1,
- WRITE = 2,
- READ_WRITE = 3,
- WRITE_READ = 7,
- };
-
- enum CompressionMode {
- COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
- COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
- COMPRESSION_ZSTD = Compression::MODE_ZSTD,
- COMPRESSION_GZIP = Compression::MODE_GZIP
- };
-
- Error open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
- Error open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
- Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
-
- Error open(const String &p_path, ModeFlags p_mode_flags); // open a file.
- void flush(); // Flush a file (write its buffer to disk).
- void close(); // Close a file.
- bool is_open() const; // True when file is open.
-
- String get_path() const; // Returns the path for the current open file.
- String get_path_absolute() const; // Returns the absolute path for the current open file.
-
- void seek(int64_t p_position); // Seek to a given position.
- void seek_end(int64_t p_position = 0); // Seek from the end of file.
- uint64_t get_position() const; // Get position in the file.
- uint64_t get_length() const; // Get size of the file.
-
- bool eof_reached() const; // Reading passed EOF.
-
- uint8_t get_8() const; // Get a byte.
- uint16_t get_16() const; // Get 16 bits uint.
- uint32_t get_32() const; // Get 32 bits uint.
- uint64_t get_64() const; // Get 64 bits uint.
-
- float get_float() const;
- double get_double() const;
- real_t get_real() const;
-
- Variant get_var(bool p_allow_objects = false) const;
-
- Vector<uint8_t> get_buffer(int64_t p_length) const; // Get an array of bytes.
- String get_line() const;
- Vector<String> get_csv_line(const String &p_delim = ",") const;
- String get_as_text(bool p_skip_cr = false) const;
- String get_md5(const String &p_path) const;
- String get_sha256(const String &p_path) const;
-
- /*
- * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac).
- * It's not about the current CPU type but file formats.
- * This flag gets reset to `false` (little endian) on each open.
- */
- void set_big_endian(bool p_big_endian);
- bool is_big_endian();
-
- Error get_error() const; // Get last error.
-
- void store_8(uint8_t p_dest); // Store a byte.
- void store_16(uint16_t p_dest); // Store 16 bits uint.
- void store_32(uint32_t p_dest); // Store 32 bits uint.
- void store_64(uint64_t p_dest); // Store 64 bits uint.
-
- void store_float(float p_dest);
- void store_double(double p_dest);
- void store_real(real_t p_real);
-
- void store_string(const String &p_string);
- void store_line(const String &p_string);
- void store_csv_line(const Vector<String> &p_values, const String &p_delim = ",");
-
- virtual void store_pascal_string(const String &p_string);
- virtual String get_pascal_string();
-
- void store_buffer(const Vector<uint8_t> &p_buffer); // Store an array of bytes.
-
- void store_var(const Variant &p_var, bool p_full_objects = false);
-
- static bool file_exists(const String &p_name); // Return true if a file exists.
-
- uint64_t get_modified_time(const String &p_file) const;
-
- File() {}
-};
-
-class Directory : public RefCounted {
- GDCLASS(Directory, RefCounted);
- Ref<DirAccess> d;
-
- bool dir_open = false;
- bool include_navigational = false;
- bool include_hidden = false;
-
-protected:
- static void _bind_methods();
-
-public:
- Error open(const String &p_path);
-
- bool is_open() const;
-
- Error list_dir_begin();
- String get_next();
- bool current_is_dir() const;
- void list_dir_end();
-
- PackedStringArray get_files();
- PackedStringArray get_directories();
- PackedStringArray _get_contents(bool p_directories);
-
- void set_include_navigational(bool p_enable);
- bool get_include_navigational() const;
- void set_include_hidden(bool p_enable);
- bool get_include_hidden() const;
-
- int get_drive_count();
- String get_drive(int p_drive);
- int get_current_drive();
-
- Error change_dir(String p_dir); // Can be relative or absolute, return false on success.
- String get_current_dir(); // Return current dir location.
-
- Error make_dir(String p_dir);
- Error make_dir_recursive(String p_dir);
-
- bool file_exists(String p_file);
- bool dir_exists(String p_dir);
-
- uint64_t get_space_left();
-
- Error copy(String p_from, String p_to);
- Error rename(String p_from, String p_to);
- Error remove(String p_name);
-
- Directory();
-};
-
class Marshalls : public Object {
GDCLASS(Marshalls, Object);
@@ -738,9 +589,6 @@ VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType);
-VARIANT_ENUM_CAST(core_bind::File::ModeFlags);
-VARIANT_ENUM_CAST(core_bind::File::CompressionMode);
-
VARIANT_ENUM_CAST(core_bind::Thread::Priority);
#endif // CORE_BIND_H
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 5cf951a93c..bda1a5cdc1 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -462,7 +462,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
d["indexing_return_type"] = index_type == Variant::NIL ? String("Variant") : Variant::get_type_name(index_type);
}
- d["is_keyed"] = Variant::ValidatedKeyedSetter(type);
+ d["is_keyed"] = Variant::is_keyed(type);
{
//members
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index 6c680e82c9..67dc55bdb7 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -884,7 +884,7 @@ static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_clas
MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname));
ERR_FAIL_COND_V(!mb, nullptr);
if (mb->get_hash() != p_hash) {
- ERR_PRINT_ONCE("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'.");
+ ERR_PRINT("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'.");
return nullptr;
}
// MethodBind *mb = ClassDB::get_method("Node", "get_name");
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index bed41b8d89..f86dfe8057 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -36,6 +36,8 @@
#include "core/os/os.h"
#include "core/templates/local_vector.h"
+thread_local Error DirAccess::last_dir_open_error = OK;
+
String DirAccess::_get_root_path() const {
switch (_access_type) {
case ACCESS_RESOURCES:
@@ -249,6 +251,61 @@ Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) {
return da;
}
+Ref<DirAccess> DirAccess::_open(const String &p_path) {
+ Error err = OK;
+ Ref<DirAccess> da = open(p_path, &err);
+ last_dir_open_error = err;
+ if (err) {
+ return Ref<DirAccess>();
+ }
+ return da;
+}
+
+int DirAccess::_get_drive_count() {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ return d->get_drive_count();
+}
+
+String DirAccess::get_drive_name(int p_idx) {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ return d->get_drive(p_idx);
+}
+
+Error DirAccess::make_dir_absolute(const String &p_dir) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
+ return d->make_dir(p_dir);
+}
+
+Error DirAccess::make_dir_recursive_absolute(const String &p_dir) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
+ return d->make_dir_recursive(p_dir);
+}
+
+bool DirAccess::dir_exists_absolute(const String &p_dir) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
+ return d->dir_exists(p_dir);
+}
+
+Error DirAccess::copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags) {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ // Support copying from res:// to user:// etc.
+ String from = ProjectSettings::get_singleton()->globalize_path(p_from);
+ String to = ProjectSettings::get_singleton()->globalize_path(p_to);
+ return d->copy(from, to, p_chmod_flags);
+}
+
+Error DirAccess::rename_absolute(const String &p_from, const String &p_to) {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ String from = ProjectSettings::get_singleton()->globalize_path(p_from);
+ String to = ProjectSettings::get_singleton()->globalize_path(p_to);
+ return d->rename(from, to);
+}
+
+Error DirAccess::remove_absolute(const String &p_path) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_path);
+ return d->remove(p_path);
+}
+
Ref<DirAccess> DirAccess::create(AccessType p_access) {
Ref<DirAccess> da = create_func[p_access] ? create_func[p_access]() : nullptr;
if (da.is_valid()) {
@@ -266,6 +323,10 @@ Ref<DirAccess> DirAccess::create(AccessType p_access) {
return da;
}
+Error DirAccess::get_open_error() {
+ return last_dir_open_error;
+}
+
String DirAccess::get_full_path(const String &p_path, AccessType p_access) {
Ref<DirAccess> d = DirAccess::create(p_access);
if (d.is_null()) {
@@ -424,3 +485,102 @@ bool DirAccess::exists(String p_dir) {
Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
return da->change_dir(p_dir) == OK;
}
+
+PackedStringArray DirAccess::get_files() {
+ return _get_contents(false);
+}
+
+PackedStringArray DirAccess::get_files_at(const String &p_path) {
+ Ref<DirAccess> da = DirAccess::open(p_path);
+ return da->get_files();
+}
+
+PackedStringArray DirAccess::get_directories() {
+ return _get_contents(true);
+}
+
+PackedStringArray DirAccess::get_directories_at(const String &p_path) {
+ Ref<DirAccess> da = DirAccess::open(p_path);
+ return da->get_directories();
+}
+
+PackedStringArray DirAccess::_get_contents(bool p_directories) {
+ PackedStringArray ret;
+
+ list_dir_begin();
+ String s = _get_next();
+ while (!s.is_empty()) {
+ if (current_is_dir() == p_directories) {
+ ret.append(s);
+ }
+ s = _get_next();
+ }
+
+ ret.sort();
+ return ret;
+}
+
+String DirAccess::_get_next() {
+ String next = get_next();
+ while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && current_is_hidden()))) {
+ next = get_next();
+ }
+ return next;
+}
+
+void DirAccess::set_include_navigational(bool p_enable) {
+ include_navigational = p_enable;
+}
+
+bool DirAccess::get_include_navigational() const {
+ return include_navigational;
+}
+
+void DirAccess::set_include_hidden(bool p_enable) {
+ include_hidden = p_enable;
+}
+
+bool DirAccess::get_include_hidden() const {
+ return include_hidden;
+}
+
+void DirAccess::_bind_methods() {
+ ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
+
+ ClassDB::bind_method(D_METHOD("list_dir_begin"), &DirAccess::list_dir_begin, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_next"), &DirAccess::_get_next);
+ ClassDB::bind_method(D_METHOD("current_is_dir"), &DirAccess::current_is_dir);
+ ClassDB::bind_method(D_METHOD("list_dir_end"), &DirAccess::list_dir_end);
+ ClassDB::bind_method(D_METHOD("get_files"), &DirAccess::get_files);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_files_at", "path"), &DirAccess::get_files_at);
+ ClassDB::bind_method(D_METHOD("get_directories"), &DirAccess::get_directories);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_directories_at", "path"), &DirAccess::get_directories_at);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_count"), &DirAccess::_get_drive_count);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_name", "idx"), &DirAccess::get_drive_name);
+ ClassDB::bind_method(D_METHOD("get_current_drive"), &DirAccess::get_current_drive);
+ ClassDB::bind_method(D_METHOD("change_dir", "to_dir"), &DirAccess::change_dir);
+ ClassDB::bind_method(D_METHOD("get_current_dir", "include_drive"), &DirAccess::get_current_dir, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("make_dir", "path"), &DirAccess::make_dir);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("make_dir_absolute", "path"), &DirAccess::make_dir_absolute);
+ ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &DirAccess::make_dir_recursive);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("make_dir_recursive_absolute", "path"), &DirAccess::make_dir_recursive_absolute);
+ ClassDB::bind_method(D_METHOD("file_exists", "path"), &DirAccess::file_exists);
+ ClassDB::bind_method(D_METHOD("dir_exists", "path"), &DirAccess::dir_exists);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("dir_exists_absolute", "path"), &DirAccess::dir_exists_absolute);
+ ClassDB::bind_method(D_METHOD("get_space_left"), &DirAccess::get_space_left);
+ ClassDB::bind_method(D_METHOD("copy", "from", "to", "chmod_flags"), &DirAccess::copy, DEFVAL(-1));
+ ClassDB::bind_static_method("DirAccess", D_METHOD("copy_absolute", "from", "to", "chmod_flags"), &DirAccess::copy_absolute, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("rename", "from", "to"), &DirAccess::rename);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("rename_absolute", "from", "to"), &DirAccess::rename_absolute);
+ ClassDB::bind_method(D_METHOD("remove", "path"), &DirAccess::remove);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("remove_absolute", "path"), &DirAccess::remove_absolute);
+
+ ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &DirAccess::set_include_navigational);
+ ClassDB::bind_method(D_METHOD("get_include_navigational"), &DirAccess::get_include_navigational);
+ ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden);
+ ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
+}
diff --git a/core/io/dir_access.h b/core/io/dir_access.h
index 2469c2a080..ee675f1c89 100644
--- a/core/io/dir_access.h
+++ b/core/io/dir_access.h
@@ -37,6 +37,8 @@
//@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies
class DirAccess : public RefCounted {
+ GDCLASS(DirAccess, RefCounted);
+
public:
enum AccessType {
ACCESS_RESOURCES,
@@ -53,7 +55,13 @@ private:
Error _copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links);
+ thread_local static Error last_dir_open_error;
+ bool include_navigational = false;
+ bool include_hidden = false;
+
protected:
+ static void _bind_methods();
+
String _get_root_path() const;
virtual String _get_root_string() const;
@@ -118,6 +126,7 @@ public:
static Ref<DirAccess> create_for_path(const String &p_path);
static Ref<DirAccess> create(AccessType p_access);
+ static Error get_open_error();
template <class T>
static void make_default(AccessType p_access) {
@@ -125,6 +134,30 @@ public:
}
static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr);
+ static Ref<DirAccess> _open(const String &p_path);
+
+ static int _get_drive_count();
+ static String get_drive_name(int p_idx);
+
+ static Error make_dir_absolute(const String &p_dir);
+ static Error make_dir_recursive_absolute(const String &p_dir);
+ static bool dir_exists_absolute(const String &p_dir);
+
+ static Error copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags = -1);
+ static Error rename_absolute(const String &p_from, const String &p_to);
+ static Error remove_absolute(const String &p_path);
+
+ PackedStringArray get_files();
+ static PackedStringArray get_files_at(const String &p_path);
+ PackedStringArray get_directories();
+ static PackedStringArray get_directories_at(const String &p_path);
+ PackedStringArray _get_contents(bool p_directories);
+ String _get_next();
+
+ void set_include_navigational(bool p_enable);
+ bool get_include_navigational() const;
+ void set_include_hidden(bool p_enable);
+ bool get_include_hidden() const;
DirAccess() {}
virtual ~DirAccess() {}
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 72c00bd678..499f083f51 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -32,6 +32,8 @@
#include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h"
+#include "core/io/file_access_compressed.h"
+#include "core/io/file_access_encrypted.h"
#include "core/io/file_access_pack.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
@@ -41,6 +43,7 @@ FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = { nullptr, nullptr
FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr;
bool FileAccess::backup_save = false;
+thread_local Error FileAccess::last_file_open_error = OK;
Ref<FileAccess> FileAccess::create(AccessType p_access) {
ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr);
@@ -81,7 +84,7 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
}
Error FileAccess::reopen(const String &p_path, int p_mode_flags) {
- return _open(p_path, p_mode_flags);
+ return open_internal(p_path, p_mode_flags);
}
Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) {
@@ -99,7 +102,7 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *
}
ret = create_for_path(p_path);
- Error err = ret->_open(p_path, p_mode_flags);
+ Error err = ret->open_internal(p_path, p_mode_flags);
if (r_error) {
*r_error = err;
@@ -111,6 +114,66 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *
return ret;
}
+Ref<FileAccess> FileAccess::_open(const String &p_path, ModeFlags p_mode_flags) {
+ Error err = OK;
+ Ref<FileAccess> fa = open(p_path, p_mode_flags, &err);
+ last_file_open_error = err;
+ if (err) {
+ return Ref<FileAccess>();
+ }
+ return fa;
+}
+
+Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
+ Ref<FileAccess> fa = _open(p_path, p_mode_flags);
+ if (fa.is_null()) {
+ return fa;
+ }
+
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
+ Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
+ if (err) {
+ last_file_open_error = err;
+ return Ref<FileAccess>();
+ }
+ return fae;
+}
+
+Ref<FileAccess> FileAccess::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
+ Ref<FileAccess> fa = _open(p_path, p_mode_flags);
+ if (fa.is_null()) {
+ return fa;
+ }
+
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
+ Error err = fae->open_and_parse_password(fa, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
+ if (err) {
+ last_file_open_error = err;
+ return Ref<FileAccess>();
+ }
+ return fae;
+}
+
+Ref<FileAccess> FileAccess::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
+ Ref<FileAccessCompressed> fac;
+ fac.instantiate();
+ fac->configure("GCPF", (Compression::Mode)p_compress_mode);
+ Error err = fac->open_internal(p_path, p_mode_flags);
+
+ if (err) {
+ last_file_open_error = err;
+ return Ref<FileAccess>();
+ }
+
+ return fac;
+}
+
+Error FileAccess::get_open_error() {
+ return last_file_open_error;
+}
+
FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) {
return create_func[p_access];
}
@@ -227,6 +290,20 @@ real_t FileAccess::get_real() const {
}
}
+Variant FileAccess::get_var(bool p_allow_objects) const {
+ uint32_t len = get_32();
+ Vector<uint8_t> buff = _get_buffer(len);
+ ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
+
+ const uint8_t *r = buff.ptr();
+
+ Variant v;
+ Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects);
+ ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant.");
+
+ return v;
+}
+
double FileAccess::get_double() const {
MarshallDouble m;
m.l = get_64();
@@ -370,6 +447,17 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
return strings;
}
+String FileAccess::get_as_text(bool p_skip_cr) const {
+ uint64_t original_pos = get_position();
+ const_cast<FileAccess *>(this)->seek(0);
+
+ String text = get_as_utf8_string(p_skip_cr);
+
+ const_cast<FileAccess *>(this)->seek(original_pos);
+
+ return text;
+}
+
uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
@@ -381,6 +469,27 @@ uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
return i;
}
+Vector<uint8_t> FileAccess::_get_buffer(int64_t p_length) const {
+ Vector<uint8_t> data;
+
+ ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
+ if (p_length == 0) {
+ return data;
+ }
+
+ Error err = data.resize(p_length);
+ ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements.");
+
+ uint8_t *w = data.ptrw();
+ int64_t len = get_buffer(&w[0], p_length);
+
+ if (len < p_length) {
+ data.resize(len);
+ }
+
+ return data;
+}
+
String FileAccess::get_as_utf8_string(bool p_skip_cr) const {
Vector<uint8_t> sourcef;
uint64_t len = get_length();
@@ -554,6 +663,33 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
}
}
+void FileAccess::_store_buffer(const Vector<uint8_t> &p_buffer) {
+ uint64_t len = p_buffer.size();
+ if (len == 0) {
+ return;
+ }
+
+ const uint8_t *r = p_buffer.ptr();
+
+ store_buffer(&r[0], len);
+}
+
+void FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
+ 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.");
+
+ Vector<uint8_t> buff;
+ buff.resize(len);
+
+ uint8_t *w = buff.ptrw();
+ err = encode_variant(p_var, &w[0], len, p_full_objects);
+ ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
+
+ store_32(len);
+ _store_buffer(buff);
+}
+
Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) {
Ref<FileAccess> f = FileAccess::open(p_path, READ, r_error);
if (f.is_null()) {
@@ -666,3 +802,69 @@ String FileAccess::get_sha256(const String &p_file) {
return String::hex_encode_buffer(hash, 32);
}
+
+void FileAccess::_bind_methods() {
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open", "path", "flags"), &FileAccess::_open);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::open_encrypted);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0));
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error);
+
+ ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush);
+ ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path);
+ ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute);
+ ClassDB::bind_method(D_METHOD("is_open"), &FileAccess::is_open);
+ ClassDB::bind_method(D_METHOD("seek", "position"), &FileAccess::seek);
+ ClassDB::bind_method(D_METHOD("seek_end", "position"), &FileAccess::seek_end, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_position"), &FileAccess::get_position);
+ ClassDB::bind_method(D_METHOD("get_length"), &FileAccess::get_length);
+ ClassDB::bind_method(D_METHOD("eof_reached"), &FileAccess::eof_reached);
+ ClassDB::bind_method(D_METHOD("get_8"), &FileAccess::get_8);
+ ClassDB::bind_method(D_METHOD("get_16"), &FileAccess::get_16);
+ ClassDB::bind_method(D_METHOD("get_32"), &FileAccess::get_32);
+ ClassDB::bind_method(D_METHOD("get_64"), &FileAccess::get_64);
+ ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
+ ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
+ ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
+ ClassDB::bind_method(D_METHOD("get_buffer", "length"), &FileAccess::_get_buffer);
+ ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line);
+ ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(","));
+ ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false));
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_md5", "path"), &FileAccess::get_md5);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_sha256", "path"), &FileAccess::get_sha256);
+ ClassDB::bind_method(D_METHOD("is_big_endian"), &FileAccess::is_big_endian);
+ ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &FileAccess::set_big_endian);
+ ClassDB::bind_method(D_METHOD("get_error"), &FileAccess::get_error);
+ ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &FileAccess::get_var, DEFVAL(false));
+
+ ClassDB::bind_method(D_METHOD("store_8", "value"), &FileAccess::store_8);
+ ClassDB::bind_method(D_METHOD("store_16", "value"), &FileAccess::store_16);
+ ClassDB::bind_method(D_METHOD("store_32", "value"), &FileAccess::store_32);
+ ClassDB::bind_method(D_METHOD("store_64", "value"), &FileAccess::store_64);
+ ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
+ ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
+ ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
+ ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &FileAccess::_store_buffer);
+ ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line);
+ ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
+ ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string);
+ ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &FileAccess::store_var, DEFVAL(false));
+
+ ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &FileAccess::store_pascal_string);
+ ClassDB::bind_method(D_METHOD("get_pascal_string"), &FileAccess::get_pascal_string);
+
+ ClassDB::bind_static_method("FileAccess", D_METHOD("file_exists", "path"), &FileAccess::exists);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_modified_time", "file"), &FileAccess::get_modified_time);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
+
+ BIND_ENUM_CONSTANT(READ);
+ BIND_ENUM_CONSTANT(WRITE);
+ BIND_ENUM_CONSTANT(READ_WRITE);
+ BIND_ENUM_CONSTANT(WRITE_READ);
+
+ BIND_ENUM_CONSTANT(COMPRESSION_FASTLZ);
+ BIND_ENUM_CONSTANT(COMPRESSION_DEFLATE);
+ BIND_ENUM_CONSTANT(COMPRESSION_ZSTD);
+ BIND_ENUM_CONSTANT(COMPRESSION_GZIP);
+}
diff --git a/core/io/file_access.h b/core/io/file_access.h
index fc0eb95d44..f8c42d3c0d 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -31,6 +31,7 @@
#ifndef FILE_ACCESS_H
#define FILE_ACCESS_H
+#include "core/io/compression.h"
#include "core/math/math_defs.h"
#include "core/object/ref_counted.h"
#include "core/os/memory.h"
@@ -42,6 +43,8 @@
*/
class FileAccess : public RefCounted {
+ GDCLASS(FileAccess, RefCounted);
+
public:
enum AccessType {
ACCESS_RESOURCES,
@@ -60,15 +63,18 @@ public:
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0;
protected:
+ static void _bind_methods();
+
AccessType get_access_type() const;
String fix_path(const String &p_path) const;
- virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) = 0; ///< open a file
virtual uint64_t _get_modified_time(const String &p_file) = 0;
static FileCloseFailNotify close_fail_notify;
private:
static bool backup_save;
+ thread_local static Error last_file_open_error;
AccessType _access_type = ACCESS_FILESYSTEM;
static CreateFunc create_func[ACCESS_MAX]; /** default file access creation function for a platform */
@@ -89,6 +95,13 @@ public:
WRITE_READ = 7,
};
+ enum CompressionMode {
+ COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
+ COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
+ COMPRESSION_ZSTD = Compression::MODE_ZSTD,
+ COMPRESSION_GZIP = Compression::MODE_GZIP
+ };
+
virtual bool is_open() const = 0; ///< true when file is open
virtual String get_path() const { return ""; } /// returns the path for the current open file
@@ -110,10 +123,14 @@ public:
virtual double get_double() const;
virtual real_t get_real() const;
+ Variant get_var(bool p_allow_objects = false) const;
+
virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
+ Vector<uint8_t> _get_buffer(int64_t p_length) const;
virtual String get_line() const;
virtual String get_token() const;
virtual Vector<String> get_csv_line(const String &p_delim = ",") const;
+ String get_as_text(bool p_skip_cr = false) const;
virtual String get_as_utf8_string(bool p_skip_cr = false) const;
/**
@@ -144,6 +161,9 @@ public:
virtual String get_pascal_string();
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ void _store_buffer(const Vector<uint8_t> &p_buffer);
+
+ void store_var(const Variant &p_var, bool p_full_objects = false);
virtual bool file_exists(const String &p_name) = 0; ///< return true if a file exists
@@ -152,6 +172,13 @@ public:
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 Ref<FileAccess> _open(const String &p_path, ModeFlags p_mode_flags);
+ static Ref<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
+ static Ref<FileAccess> open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
+ static Ref<FileAccess> open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
+ static Error get_open_error();
+
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);
@@ -177,4 +204,7 @@ public:
virtual ~FileAccess() {}
};
+VARIANT_ENUM_CAST(FileAccess::CompressionMode);
+VARIANT_ENUM_CAST(FileAccess::ModeFlags);
+
#endif // FILE_ACCESS_H
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 1d0a718166..d2c8a88269 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -95,7 +95,7 @@ Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) {
return ret == -1 ? ERR_FILE_CORRUPT : OK;
}
-Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessCompressed::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags == READ_WRITE, ERR_UNAVAILABLE);
_close();
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index e41491a92c..ee114c2c65 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -70,7 +70,7 @@ public:
Error open_after_magic(Ref<FileAccess> p_base);
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index d1b014a0be..be502dacd9 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -111,7 +111,7 @@ Error FileAccessEncrypted::open_and_parse_password(Ref<FileAccess> p_base, const
return open_and_parse(p_base, key, p_mode);
}
-Error FileAccessEncrypted::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessEncrypted::open_internal(const String &p_path, int p_mode_flags) {
return OK;
}
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 6200f87a7a..6b4588841d 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -60,7 +60,7 @@ public:
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) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual String get_path() const override; /// returns the path for the current open file
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 499d001234..21ded4247f 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -78,7 +78,7 @@ Error FileAccessMemory::open_custom(const uint8_t *p_data, uint64_t p_len) {
return OK;
}
-Error FileAccessMemory::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessMemory::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND);
String name = fix_path(p_path);
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index f2bd2aa832..b1f408eb98 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -45,7 +45,7 @@ public:
static void cleanup();
virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 1365b4b593..13730518bf 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -252,7 +252,7 @@ void FileAccessNetwork::_respond(uint64_t p_len, Error p_status) {
pages.resize(pc);
}
-Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessNetwork::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags != READ, ERR_UNAVAILABLE);
_close();
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index ceadc715a1..ee92d3b9db 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -132,7 +132,7 @@ public:
RESPONSE_GET_MODTIME,
};
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index adae0db0f4..dfcce30ab5 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -259,7 +259,7 @@ Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::Pack
//////////////////////////////////////////////////////////////////
-Error FileAccessPack::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessPack::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_V(ERR_UNAVAILABLE);
return ERR_UNAVAILABLE;
}
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 023758ac0f..4b9b49a161 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -148,7 +148,7 @@ class FileAccessPack : public FileAccess {
uint64_t off;
Ref<FileAccess> f;
- virtual Error _open(const String &p_path, int p_mode_flags) override;
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override;
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 17f2335a8e..2af6f370cf 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -234,7 +234,7 @@ ZipArchive::~ZipArchive() {
packages.clear();
}
-Error FileAccessZip::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessZip::open_internal(const String &p_path, int p_mode_flags) {
_close();
ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED);
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index 74a48192f3..6d61b9a291 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -85,7 +85,7 @@ class FileAccessZip : public FileAccess {
void _close();
public:
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index d09697b951..d6854666c0 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -32,6 +32,12 @@
#include "core/string/print_string.h"
+void ImageFormatLoader::_bind_methods() {
+ BIND_BITFIELD_FLAG(FLAG_NONE);
+ BIND_BITFIELD_FLAG(FLAG_FORCE_LINEAR);
+ BIND_BITFIELD_FLAG(FLAG_CONVERT_COLORS);
+}
+
bool ImageFormatLoader::recognize(const String &p_extension) const {
List<String> extensions;
get_recognized_extensions(&extensions);
@@ -44,7 +50,39 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
return false;
}
-Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, uint32_t p_flags, float p_scale) {
+Error ImageFormatLoaderExtension::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
+ Error err;
+ if (GDVIRTUAL_CALL(_load_image, p_image, p_fileaccess, p_flags, p_scale, err)) {
+ return err;
+ }
+ return ERR_UNAVAILABLE;
+}
+
+void ImageFormatLoaderExtension::get_recognized_extensions(List<String> *p_extension) const {
+ PackedStringArray ext;
+ if (GDVIRTUAL_CALL(_get_recognized_extensions, ext)) {
+ for (int i = 0; i < ext.size(); i++) {
+ p_extension->push_back(ext[i]);
+ }
+ }
+}
+
+void ImageFormatLoaderExtension::add_format_loader() {
+ ImageLoader::add_image_format_loader(this);
+}
+
+void ImageFormatLoaderExtension::remove_format_loader() {
+ ImageLoader::remove_image_format_loader(this);
+}
+
+void ImageFormatLoaderExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_recognized_extensions);
+ GDVIRTUAL_BIND(_load_image, "image", "fileaccess", "flags", "scale");
+ ClassDB::bind_method(D_METHOD("add_format_loader"), &ImageFormatLoaderExtension::add_format_loader);
+ ClassDB::bind_method(D_METHOD("remove_format_loader"), &ImageFormatLoaderExtension::remove_format_loader);
+}
+
+Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, BitField<ImageFormatLoader::LoaderFlags> p_flags, 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.");
Ref<FileAccess> f = p_custom;
@@ -60,7 +98,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess>
if (!loader[i]->recognize(extension)) {
continue;
}
- Error err = loader[i]->load_image(p_image, f, p_flags, p_scale);
+ Error err = loader.write[i]->load_image(p_image, f, p_flags, p_scale);
if (err != OK) {
ERR_PRINT("Error loading image: " + p_file);
}
@@ -79,7 +117,7 @@ void ImageLoader::get_recognized_extensions(List<String> *p_extensions) {
}
}
-ImageFormatLoader *ImageLoader::recognize(const String &p_extension) {
+Ref<ImageFormatLoader> ImageLoader::recognize(const String &p_extension) {
for (int i = 0; i < loader.size(); i++) {
if (loader[i]->recognize(p_extension)) {
return loader[i];
@@ -89,17 +127,17 @@ ImageFormatLoader *ImageLoader::recognize(const String &p_extension) {
return nullptr;
}
-Vector<ImageFormatLoader *> ImageLoader::loader;
+Vector<Ref<ImageFormatLoader>> ImageLoader::loader;
-void ImageLoader::add_image_format_loader(ImageFormatLoader *p_loader) {
+void ImageLoader::add_image_format_loader(Ref<ImageFormatLoader> p_loader) {
loader.push_back(p_loader);
}
-void ImageLoader::remove_image_format_loader(ImageFormatLoader *p_loader) {
+void ImageLoader::remove_image_format_loader(Ref<ImageFormatLoader> p_loader) {
loader.erase(p_loader);
}
-const Vector<ImageFormatLoader *> &ImageLoader::get_image_format_loaders() {
+const Vector<Ref<ImageFormatLoader>> &ImageLoader::get_image_format_loaders() {
return loader;
}
@@ -152,7 +190,7 @@ Ref<Resource> ResourceFormatLoaderImage::load(const String &p_path, const String
Ref<Image> image;
image.instantiate();
- Error err = ImageLoader::loader[idx]->load_image(image, f);
+ Error err = ImageLoader::loader.write[idx]->load_image(image, f);
if (err != OK) {
if (r_error) {
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index bf78005e40..f70fdf22aa 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -31,23 +31,23 @@
#ifndef IMAGE_LOADER_H
#define IMAGE_LOADER_H
+#include "core/core_bind.h"
#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
+#include "core/object/gdvirtual.gen.inc"
#include "core/string/ustring.h"
#include "core/templates/list.h"
+#include "core/variant/binder_common.h"
class ImageLoader;
-class ImageFormatLoader {
+class ImageFormatLoader : public RefCounted {
+ GDCLASS(ImageFormatLoader, RefCounted);
+
friend class ImageLoader;
friend class ResourceFormatLoaderImage;
-protected:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags = (uint32_t)FLAG_NONE, float p_scale = 1.0) = 0;
- virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
- bool recognize(const String &p_extension) const;
-
public:
enum LoaderFlags {
FLAG_NONE = 0,
@@ -55,23 +55,50 @@ public:
FLAG_CONVERT_COLORS = 2,
};
+protected:
+ static void _bind_methods();
+
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags = FLAG_NONE, float p_scale = 1.0) = 0;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
+ bool recognize(const String &p_extension) const;
+
+public:
virtual ~ImageFormatLoader() {}
};
+VARIANT_BITFIELD_CAST(ImageFormatLoader::LoaderFlags);
+
+class ImageFormatLoaderExtension : public ImageFormatLoader {
+ GDCLASS(ImageFormatLoaderExtension, ImageFormatLoader);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags = FLAG_NONE, float p_scale = 1.0) override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+
+ void add_format_loader();
+ void remove_format_loader();
+
+ GDVIRTUAL0RC(PackedStringArray, _get_recognized_extensions);
+ GDVIRTUAL4R(Error, _load_image, Ref<Image>, Ref<FileAccess>, BitField<ImageFormatLoader::LoaderFlags>, float);
+};
+
class ImageLoader {
- static Vector<ImageFormatLoader *> loader;
+ static Vector<Ref<ImageFormatLoader>> loader;
friend class ResourceFormatLoaderImage;
protected:
public:
- static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), uint32_t p_flags = (uint32_t)ImageFormatLoader::FLAG_NONE, float p_scale = 1.0);
+ static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), BitField<ImageFormatLoader::LoaderFlags> p_flags = ImageFormatLoader::FLAG_NONE, float p_scale = 1.0);
static void get_recognized_extensions(List<String> *p_extensions);
- static ImageFormatLoader *recognize(const String &p_extension);
+ static Ref<ImageFormatLoader> recognize(const String &p_extension);
- static void add_image_format_loader(ImageFormatLoader *p_loader);
- static void remove_image_format_loader(ImageFormatLoader *p_loader);
+ static void add_image_format_loader(Ref<ImageFormatLoader> p_loader);
+ static void remove_image_format_loader(Ref<ImageFormatLoader> p_loader);
- static const Vector<ImageFormatLoader *> &get_image_format_loaders();
+ static const Vector<Ref<ImageFormatLoader>> &get_image_format_loaders();
static void cleanup();
};
diff --git a/core/io/json.cpp b/core/io/json.cpp
index a685fcb718..7e267d35d4 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -56,6 +56,8 @@ String JSON::_make_indent(const String &p_indent, int p_size) {
}
String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision) {
+ ERR_FAIL_COND_V_MSG(p_cur_indent > Variant::MAX_RECURSION_DEPTH, "...", "JSON structure is too deep. Bailing.");
+
String colon = ":";
String end_statement = "";
@@ -357,17 +359,22 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
+ if (p_depth > Variant::MAX_RECURSION_DEPTH) {
+ r_err_str = "JSON structure is too deep. Bailing.";
+ return ERR_OUT_OF_MEMORY;
+ }
+
if (token.type == TK_CURLY_BRACKET_OPEN) {
Dictionary d;
- Error err = _parse_object(d, p_str, index, p_len, line, r_err_str);
+ Error err = _parse_object(d, p_str, index, p_len, line, p_depth + 1, r_err_str);
if (err) {
return err;
}
value = d;
} else if (token.type == TK_BRACKET_OPEN) {
Array a;
- Error err = _parse_array(a, p_str, index, p_len, line, r_err_str);
+ Error err = _parse_array(a, p_str, index, p_len, line, p_depth + 1, r_err_str);
if (err) {
return err;
}
@@ -396,7 +403,7 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in
return OK;
}
-Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
Token token;
bool need_comma = false;
@@ -421,7 +428,7 @@ Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_
}
Variant v;
- err = _parse_value(v, token, p_str, index, p_len, line, r_err_str);
+ err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
if (err) {
return err;
}
@@ -434,7 +441,7 @@ Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
bool at_key = true;
String key;
Token token;
@@ -483,7 +490,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index,
}
Variant v;
- err = _parse_value(v, token, p_str, index, p_len, line, r_err_str);
+ err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
if (err) {
return err;
}
@@ -514,7 +521,7 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st
return err;
}
- err = _parse_value(r_ret, token, str, idx, len, r_err_line, r_err_str);
+ err = _parse_value(r_ret, token, str, idx, len, r_err_line, 0, r_err_str);
// Check if EOF is reached
// or it's a type of the next token.
diff --git a/core/io/json.h b/core/io/json.h
index 208d4ad625..829a5f922b 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -74,9 +74,9 @@ class JSON : public RefCounted {
static String _make_indent(const String &p_indent, int p_size);
static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision = false);
static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
- static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
+ static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
+ static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
+ static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
static Error _parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line);
protected:
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 4f1204fc48..06649aba5b 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1206,7 +1206,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
Ref<FileAccessCompressed> facw;
facw.instantiate();
facw->configure("RSCC");
- err = facw->_open(p_path + ".depren", FileAccess::WRITE);
+ err = facw->open_internal(p_path + ".depren", FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(err, ERR_FILE_CORRUPT, "Cannot create file '" + p_path + ".depren'.");
fw = facw;
@@ -1986,7 +1986,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re
fac.instantiate();
fac->configure("RSCC");
f = fac;
- err = fac->_open(p_path, FileAccess::WRITE);
+ err = fac->open_internal(p_path, FileAccess::WRITE);
} else {
f = FileAccess::open(p_path, FileAccess::WRITE, &err);
}
diff --git a/core/io/stream_peer_gzip.cpp b/core/io/stream_peer_gzip.cpp
new file mode 100644
index 0000000000..ca8be2d62e
--- /dev/null
+++ b/core/io/stream_peer_gzip.cpp
@@ -0,0 +1,209 @@
+/*************************************************************************/
+/* stream_peer_gzip.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 "core/io/stream_peer_gzip.h"
+
+#include "core/io/zip_io.h"
+#include <zlib.h>
+
+void StreamPeerGZIP::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("start_compression", "use_deflate", "buffer_size"), &StreamPeerGZIP::start_compression, DEFVAL(false), DEFVAL(65535));
+ ClassDB::bind_method(D_METHOD("start_decompression", "use_deflate", "buffer_size"), &StreamPeerGZIP::start_decompression, DEFVAL(false), DEFVAL(65535));
+ ClassDB::bind_method(D_METHOD("finish"), &StreamPeerGZIP::finish);
+ ClassDB::bind_method(D_METHOD("clear"), &StreamPeerGZIP::clear);
+}
+
+StreamPeerGZIP::StreamPeerGZIP() {
+}
+
+StreamPeerGZIP::~StreamPeerGZIP() {
+ _close();
+}
+
+void StreamPeerGZIP::_close() {
+ if (ctx) {
+ z_stream *strm = (z_stream *)ctx;
+ if (compressing) {
+ deflateEnd(strm);
+ } else {
+ inflateEnd(strm);
+ }
+ memfree(strm);
+ ctx = nullptr;
+ }
+}
+
+void StreamPeerGZIP::clear() {
+ _close();
+ rb.clear();
+ buffer.clear();
+}
+
+Error StreamPeerGZIP::start_compression(bool p_is_deflate, int buffer_size) {
+ return _start(true, p_is_deflate, buffer_size);
+}
+
+Error StreamPeerGZIP::start_decompression(bool p_is_deflate, int buffer_size) {
+ return _start(false, p_is_deflate, buffer_size);
+}
+
+Error StreamPeerGZIP::_start(bool p_compress, bool p_is_deflate, int buffer_size) {
+ ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE);
+ clear();
+ compressing = p_compress;
+ rb.resize(nearest_shift(buffer_size - 1));
+ buffer.resize(1024);
+
+ // Create ctx.
+ ctx = memalloc(sizeof(z_stream));
+ z_stream &strm = *(z_stream *)ctx;
+ strm.next_in = Z_NULL;
+ strm.avail_in = 0;
+ strm.zalloc = zipio_alloc;
+ strm.zfree = zipio_free;
+ strm.opaque = Z_NULL;
+ int window_bits = p_is_deflate ? 15 : (15 + 16);
+ int err = Z_OK;
+ int level = Z_DEFAULT_COMPRESSION;
+ if (compressing) {
+ err = deflateInit2(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
+ } else {
+ err = inflateInit2(&strm, window_bits);
+ }
+ ERR_FAIL_COND_V(err != Z_OK, FAILED);
+ return OK;
+}
+
+Error StreamPeerGZIP::_process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close) {
+ ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ z_stream &strm = *(z_stream *)ctx;
+ strm.avail_in = p_src_size;
+ strm.avail_out = p_dst_size;
+ strm.next_in = (Bytef *)p_src;
+ strm.next_out = (Bytef *)p_dst;
+ int flush = p_close ? Z_FINISH : Z_NO_FLUSH;
+ if (compressing) {
+ int err = deflate(&strm, flush);
+ ERR_FAIL_COND_V(err != (p_close ? Z_STREAM_END : Z_OK), FAILED);
+ } else {
+ int err = inflate(&strm, flush);
+ ERR_FAIL_COND_V(err != Z_OK && err != Z_STREAM_END, FAILED);
+ }
+ r_out = p_dst_size - strm.avail_out;
+ r_consumed = p_src_size - strm.avail_in;
+ return OK;
+}
+
+Error StreamPeerGZIP::put_data(const uint8_t *p_data, int p_bytes) {
+ int wrote = 0;
+ Error err = put_partial_data(p_data, p_bytes, wrote);
+ if (err != OK) {
+ return err;
+ }
+ ERR_FAIL_COND_V(p_bytes != wrote, ERR_OUT_OF_MEMORY);
+ return OK;
+}
+
+Error StreamPeerGZIP::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
+ ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER);
+
+ // Ensure we have enough space in temporary buffer.
+ if (buffer.size() < p_bytes) {
+ buffer.resize(p_bytes);
+ }
+
+ r_sent = 0;
+ while (r_sent < p_bytes && rb.space_left() > 1024) { // Keep the ring buffer size meaningful.
+ int sent = 0;
+ int to_write = 0;
+ // Compress or decompress
+ Error err = _process(buffer.ptrw(), MIN(buffer.size(), rb.space_left()), p_data + r_sent, p_bytes - r_sent, sent, to_write);
+ if (err != OK) {
+ return err;
+ }
+ // When decompressing, we might need to do another round.
+ r_sent += sent;
+
+ // We can't write more than this buffer is full.
+ if (sent == 0 && to_write == 0) {
+ return OK;
+ }
+ if (to_write) {
+ // Copy to ring buffer.
+ int wrote = rb.write(buffer.ptr(), to_write);
+ ERR_FAIL_COND_V(wrote != to_write, ERR_BUG);
+ }
+ }
+ return OK;
+}
+
+Error StreamPeerGZIP::get_data(uint8_t *p_buffer, int p_bytes) {
+ int received = 0;
+ Error err = get_partial_data(p_buffer, p_bytes, received);
+ if (err != OK) {
+ return err;
+ }
+ ERR_FAIL_COND_V(p_bytes != received, ERR_UNAVAILABLE);
+ return OK;
+}
+
+Error StreamPeerGZIP::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
+ ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER);
+
+ r_received = MIN(p_bytes, rb.data_left());
+ if (r_received == 0) {
+ return OK;
+ }
+ int received = rb.read(p_buffer, r_received);
+ ERR_FAIL_COND_V(received != r_received, ERR_BUG);
+ return OK;
+}
+
+int StreamPeerGZIP::get_available_bytes() const {
+ return rb.data_left();
+}
+
+Error StreamPeerGZIP::finish() {
+ ERR_FAIL_COND_V(!ctx || !compressing, ERR_UNAVAILABLE);
+ // Ensure we have enough space in temporary buffer.
+ if (buffer.size() < 1024) {
+ buffer.resize(1024); // 1024 should be more than enough.
+ }
+ int consumed = 0;
+ int to_write = 0;
+ Error err = _process(buffer.ptrw(), 1024, nullptr, 0, consumed, to_write, true); // compress
+ if (err != OK) {
+ return err;
+ }
+ int wrote = rb.write(buffer.ptr(), to_write);
+ ERR_FAIL_COND_V(wrote != to_write, ERR_OUT_OF_MEMORY);
+ return OK;
+}
diff --git a/core/io/stream_peer_gzip.h b/core/io/stream_peer_gzip.h
new file mode 100644
index 0000000000..5bafdbca9b
--- /dev/null
+++ b/core/io/stream_peer_gzip.h
@@ -0,0 +1,76 @@
+/*************************************************************************/
+/* stream_peer_gzip.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 STREAM_PEER_GZIP_H
+#define STREAM_PEER_GZIP_H
+
+#include "core/io/stream_peer.h"
+
+#include "core/core_bind.h"
+#include "core/io/compression.h"
+#include "core/templates/ring_buffer.h"
+
+class StreamPeerGZIP : public StreamPeer {
+ GDCLASS(StreamPeerGZIP, StreamPeer);
+
+private:
+ void *ctx = nullptr; // Will hold our z_stream instance.
+ bool compressing = true;
+
+ RingBuffer<uint8_t> rb;
+ Vector<uint8_t> buffer;
+
+ Error _process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close = false);
+ void _close();
+ Error _start(bool p_compress, bool p_is_deflate, int buffer_size = 65535);
+
+protected:
+ static void _bind_methods();
+
+public:
+ Error start_compression(bool p_is_deflate, int buffer_size = 65535);
+ Error start_decompression(bool p_is_deflate, int buffer_size = 65535);
+
+ Error finish();
+ void clear();
+
+ virtual Error put_data(const uint8_t *p_data, int p_bytes) override;
+ virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
+
+ virtual Error get_data(uint8_t *p_buffer, int p_bytes) override;
+ virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
+
+ virtual int get_available_bytes() const override;
+
+ StreamPeerGZIP();
+ ~StreamPeerGZIP();
+};
+
+#endif // STREAM_PEER_GZIP_H
diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp
index 208f89f449..f36b228543 100644
--- a/core/math/math_fieldwise.cpp
+++ b/core/math/math_fieldwise.cpp
@@ -76,6 +76,7 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+
case Variant::VECTOR3I: {
SETUP_TYPE(Vector3i)
@@ -85,6 +86,7 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+
case Variant::VECTOR4: {
SETUP_TYPE(Vector4)
@@ -95,6 +97,7 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+
case Variant::VECTOR4I: {
SETUP_TYPE(Vector4i)
@@ -106,7 +109,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
-
case Variant::PLANE: {
SETUP_TYPE(Plane)
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 656fc9f798..7fa674a23d 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -267,6 +267,7 @@ public:
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
}
+
static _ALWAYS_INLINE_ float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
float from_rot = fmod(p_from, (float)Math_TAU);
@@ -293,6 +294,7 @@ public:
double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t);
return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t);
}
+
static _ALWAYS_INLINE_ float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
float p_to_t, float p_pre_t, float p_post_t) {
/* Barry-Goldman method */
@@ -320,6 +322,7 @@ public:
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
}
+
static _ALWAYS_INLINE_ float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
float p_to_t, float p_pre_t, float p_post_t) {
float from_rot = fmod(p_from, (float)Math_TAU);
@@ -346,6 +349,7 @@ public:
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
}
+
static _ALWAYS_INLINE_ float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) {
/* Formula from Wikipedia article on Bezier curves. */
float omt = (1.0f - p_t);
@@ -368,11 +372,19 @@ public:
return p_from + distance * p_weight;
}
- static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { return (p_value - p_from) / (p_to - p_from); }
- static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { return (p_value - p_from) / (p_to - p_from); }
+ static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) {
+ return (p_value - p_from) / (p_to - p_from);
+ }
+ static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) {
+ return (p_value - p_from) / (p_to - p_from);
+ }
- static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
- static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
+ static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) {
+ return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
+ }
+ static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) {
+ return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
+ }
static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) {
if (is_equal_approx(p_from, p_to)) {
@@ -388,14 +400,26 @@ public:
float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f);
return s * s * (3.0f - 2.0f * s);
}
- static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
- static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
+ static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) {
+ return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta;
+ }
+ static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) {
+ return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta;
+ }
- static _ALWAYS_INLINE_ double linear_to_db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
- static _ALWAYS_INLINE_ float linear_to_db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ double linear_to_db(double p_linear) {
+ return Math::log(p_linear) * 8.6858896380650365530225783783321;
+ }
+ static _ALWAYS_INLINE_ float linear_to_db(float p_linear) {
+ return Math::log(p_linear) * (float)8.6858896380650365530225783783321;
+ }
- static _ALWAYS_INLINE_ double db_to_linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
- static _ALWAYS_INLINE_ float db_to_linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); }
+ static _ALWAYS_INLINE_ double db_to_linear(double p_db) {
+ return Math::exp(p_db * 0.11512925464970228420089957273422);
+ }
+ static _ALWAYS_INLINE_ float db_to_linear(float p_db) {
+ return Math::exp(p_db * (float)0.11512925464970228420089957273422);
+ }
static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); }
static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); }
diff --git a/core/math/vector2i.h b/core/math/vector2i.h
index 0245900a3b..e131bdea94 100644
--- a/core/math/vector2i.h
+++ b/core/math/vector2i.h
@@ -38,6 +38,8 @@ class String;
struct Vector2;
struct _NO_DISCARD_ Vector2i {
+ static const int AXIS_COUNT = 2;
+
enum Axis {
AXIS_X,
AXIS_Y,
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index 825ce40318..c6d03cd031 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -38,6 +38,8 @@ class String;
struct Vector3;
struct _NO_DISCARD_ Vector3i {
+ static const int AXIS_COUNT = 3;
+
enum Axis {
AXIS_X,
AXIS_Y,
diff --git a/core/math/vector4.h b/core/math/vector4.h
index f964264108..d89f3ddb05 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -37,6 +37,8 @@
#include "core/string/ustring.h"
struct _NO_DISCARD_ Vector4 {
+ static const int AXIS_COUNT = 4;
+
enum Axis {
AXIS_X,
AXIS_Y,
diff --git a/core/math/vector4i.h b/core/math/vector4i.h
index d08e40d754..fdf33b9569 100644
--- a/core/math/vector4i.h
+++ b/core/math/vector4i.h
@@ -38,6 +38,8 @@ class String;
struct Vector4;
struct _NO_DISCARD_ Vector4i {
+ static const int AXIS_COUNT = 4;
+
enum Axis {
AXIS_X,
AXIS_Y,
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index d3c48853f1..aa66e86bc0 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -126,27 +126,28 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
force_keep_in_merge_ends = false;
}
-void UndoRedo::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
- ERR_FAIL_COND(p_object == nullptr);
+void UndoRedo::add_do_method(const Callable &p_callable) {
+ ERR_FAIL_COND(p_callable.is_null());
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
+
+ Object *object = p_callable.get_object();
+ ERR_FAIL_NULL(object);
+
Operation do_op;
- do_op.object = p_object->get_instance_id();
- if (Object::cast_to<RefCounted>(p_object)) {
- do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
+ do_op.callable = p_callable;
+ do_op.object = p_callable.get_object_id();
+ if (Object::cast_to<RefCounted>(object)) {
+ do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object));
}
-
do_op.type = Operation::TYPE_METHOD;
- do_op.name = p_method;
+ do_op.name = p_callable.get_method();
- for (int i = 0; i < p_argcount; i++) {
- do_op.args.push_back(*p_args[i]);
- }
actions.write[current_action + 1].do_ops.push_back(do_op);
}
-void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
- ERR_FAIL_COND(p_object == nullptr);
+void UndoRedo::add_undo_method(const Callable &p_callable) {
+ ERR_FAIL_COND(p_callable.is_null());
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -155,19 +156,19 @@ void UndoRedo::add_undo_methodp(Object *p_object, const StringName &p_method, co
return;
}
+ Object *object = p_callable.get_object();
+ ERR_FAIL_NULL(object);
+
Operation undo_op;
- undo_op.object = p_object->get_instance_id();
- if (Object::cast_to<RefCounted>(p_object)) {
- undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object));
+ undo_op.callable = p_callable;
+ undo_op.object = p_callable.get_object_id();
+ if (Object::cast_to<RefCounted>(object)) {
+ undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(object));
}
-
undo_op.type = Operation::TYPE_METHOD;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
- undo_op.name = p_method;
+ undo_op.name = p_callable.get_method();
- for (int i = 0; i < p_argcount; i++) {
- undo_op.args.push_back(*p_args[i]);
- }
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -183,7 +184,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
do_op.type = Operation::TYPE_PROPERTY;
do_op.name = p_property;
- do_op.args.push_back(p_value);
+ do_op.value = p_value;
actions.write[current_action + 1].do_ops.push_back(do_op);
}
@@ -206,7 +207,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
undo_op.type = Operation::TYPE_PROPERTY;
undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends;
undo_op.name = p_property;
- undo_op.args.push_back(p_value);
+ undo_op.value = p_value;
actions.write[current_action + 1].undo_ops.push_back(undo_op);
}
@@ -312,33 +313,42 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
switch (op.type) {
case Operation::TYPE_METHOD: {
- int argc = op.args.size();
- Vector<const Variant *> argptrs;
- argptrs.resize(argc);
-
- for (int i = 0; i < argc; i++) {
- argptrs.write[i] = &op.args[i];
- }
-
Callable::CallError ce;
- obj->callp(op.name, (const Variant **)argptrs.ptr(), argc, ce);
+ Variant ret;
+ op.callable.callp(nullptr, 0, ret, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, (const Variant **)argptrs.ptr(), argc, ce));
+ ERR_PRINT("Error calling UndoRedo method operation '" + String(op.name) + "': " + Variant::get_call_error_text(obj, op.name, nullptr, 0, ce));
}
#ifdef TOOLS_ENABLED
Resource *res = Object::cast_to<Resource>(obj);
if (res) {
res->set_edited(true);
}
-
#endif
if (method_callback) {
- method_callback(method_callback_ud, obj, op.name, (const Variant **)argptrs.ptr(), argc);
+ Vector<Variant> binds;
+ if (op.callable.is_custom()) {
+ CallableCustomBind *ccb = dynamic_cast<CallableCustomBind *>(op.callable.get_custom());
+ if (ccb) {
+ binds = ccb->get_binds();
+ }
+ }
+
+ if (binds.is_empty()) {
+ method_callback(method_callback_ud, obj, op.name, nullptr, 0);
+ } else {
+ const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * binds.size());
+ for (int i = 0; i < binds.size(); i++) {
+ args[i] = (const Variant *)&binds[i];
+ }
+
+ method_callback(method_callback_ud, obj, op.name, args, binds.size());
+ }
}
} break;
case Operation::TYPE_PROPERTY: {
- obj->set(op.name, op.args[0]);
+ obj->set(op.name, op.value);
#ifdef TOOLS_ENABLED
Resource *res = Object::cast_to<Resource>(obj);
if (res) {
@@ -346,7 +356,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
}
#endif
if (property_callback) {
- property_callback(prop_callback_ud, obj, op.name, op.args[0]);
+ property_callback(prop_callback_ud, obj, op.name, op.value);
}
} break;
case Operation::TYPE_REFERENCE: {
@@ -444,87 +454,13 @@ UndoRedo::~UndoRedo() {
clear_history();
}
-void UndoRedo::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 0;
- return;
- }
-
- if (p_args[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- return;
- }
-
- if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING_NAME;
- return;
- }
-
- r_error.error = Callable::CallError::CALL_OK;
-
- Object *object = *p_args[0];
- StringName method = *p_args[1];
-
- add_do_methodp(object, method, p_args + 2, p_argcount - 2);
-}
-
-void UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (p_argcount < 2) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 0;
- return;
- }
-
- if (p_args[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
- return;
- }
-
- if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::STRING_NAME;
- return;
- }
-
- r_error.error = Callable::CallError::CALL_OK;
-
- Object *object = *p_args[0];
- StringName method = *p_args[1];
-
- add_undo_methodp(object, method, p_args + 2, p_argcount - 2);
-}
-
void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
ClassDB::bind_method(D_METHOD("commit_action", "execute"), &UndoRedo::commit_action, DEFVAL(true));
ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action);
- {
- MethodInfo mi;
- mi.name = "add_do_method";
- mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
- mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
-
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_do_method", &UndoRedo::_add_do_method, mi, varray(), false);
- }
-
- {
- MethodInfo mi;
- mi.name = "add_undo_method";
- mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
- mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
-
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_undo_method", &UndoRedo::_add_undo_method, mi, varray(), false);
- }
-
+ ClassDB::bind_method(D_METHOD("add_do_method", "callable"), &UndoRedo::add_do_method);
+ ClassDB::bind_method(D_METHOD("add_undo_method", "callable"), &UndoRedo::add_undo_method);
ClassDB::bind_method(D_METHOD("add_do_property", "object", "property", "value"), &UndoRedo::add_do_property);
ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &UndoRedo::add_undo_property);
ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference);
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 63cf3e5cbe..c7c58697c3 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -46,8 +46,6 @@ public:
};
typedef void (*CommitNotifyCallback)(void *p_ud, const String &p_name);
- void _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- void _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
typedef void (*MethodNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
typedef void (*PropertyNotifyCallback)(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
@@ -58,14 +56,14 @@ private:
TYPE_METHOD,
TYPE_PROPERTY,
TYPE_REFERENCE
- };
+ } type;
- Type type;
bool force_keep_in_merge_ends;
Ref<RefCounted> ref;
ObjectID object;
StringName name;
- Vector<Variant> args;
+ Callable callable;
+ Variant value;
void delete_reference();
};
@@ -106,30 +104,8 @@ protected:
public:
void create_action(const String &p_name = "", MergeMode p_mode = MERGE_DISABLE);
- void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
- void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
-
- template <typename... VarArgs>
- void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
- Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
- const Variant *argptrs[sizeof...(p_args) + 1];
- for (uint32_t i = 0; i < sizeof...(p_args); i++) {
- argptrs[i] = &args[i];
- }
-
- add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
- }
- template <typename... VarArgs>
- void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
- Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
- const Variant *argptrs[sizeof...(p_args) + 1];
- for (uint32_t i = 0; i < sizeof...(p_args); i++) {
- argptrs[i] = &args[i];
- }
-
- add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
- }
-
+ void add_do_method(const Callable &p_callable);
+ void add_undo_method(const Callable &p_callable);
void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value);
void add_do_reference(Object *p_object);
diff --git a/core/os/os.h b/core/os/os.h
index 6944d29eeb..0f79ff1a23 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -69,6 +69,7 @@ class OS {
// so we can retrieve the rendering drivers available
int _display_driver_id = -1;
String _current_rendering_driver_name;
+ String _current_rendering_method;
protected:
void _set_logger(CompositeLogger *p_logger);
@@ -98,6 +99,8 @@ protected:
virtual void initialize_joypads() = 0;
void set_current_rendering_driver_name(String p_driver_name) { _current_rendering_driver_name = p_driver_name; }
+ void set_current_rendering_method(String p_name) { _current_rendering_method = p_name; }
+
void set_display_driver_id(int p_display_driver_id) { _display_driver_id = p_display_driver_id; }
virtual void set_main_loop(MainLoop *p_main_loop) = 0;
@@ -116,6 +119,8 @@ public:
static OS *get_singleton();
String get_current_rendering_driver_name() const { return _current_rendering_driver_name; }
+ String get_current_rendering_method() const { return _current_rendering_method; }
+
int get_display_driver_id() const { return _display_driver_id; }
void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, Logger::ErrorType p_type = Logger::ERR_ERROR);
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 6dfb0f82e0..bad53ab4e6 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -58,6 +58,7 @@
#include "core/io/resource_format_binary.h"
#include "core/io/resource_importer.h"
#include "core/io/resource_uid.h"
+#include "core/io/stream_peer_gzip.h"
#include "core/io/stream_peer_tls.h"
#include "core/io/tcp_server.h"
#include "core/io/translation_loader_po.h"
@@ -184,6 +185,7 @@ void register_core_types() {
GDREGISTER_ABSTRACT_CLASS(StreamPeer);
GDREGISTER_CLASS(StreamPeerExtension);
GDREGISTER_CLASS(StreamPeerBuffer);
+ GDREGISTER_CLASS(StreamPeerGZIP);
GDREGISTER_CLASS(StreamPeerTCP);
GDREGISTER_CLASS(TCPServer);
@@ -228,8 +230,8 @@ void register_core_types() {
GDREGISTER_CLASS(ResourceFormatLoader);
GDREGISTER_CLASS(ResourceFormatSaver);
- GDREGISTER_CLASS(core_bind::File);
- GDREGISTER_CLASS(core_bind::Directory);
+ GDREGISTER_ABSTRACT_CLASS(FileAccess);
+ GDREGISTER_ABSTRACT_CLASS(DirAccess);
GDREGISTER_CLASS(core_bind::Thread);
GDREGISTER_CLASS(core_bind::Mutex);
GDREGISTER_CLASS(core_bind::Semaphore);
@@ -249,6 +251,8 @@ void register_core_types() {
GDREGISTER_CLASS(EncodedObjectAsID);
GDREGISTER_CLASS(RandomNumberGenerator);
+ GDREGISTER_ABSTRACT_CLASS(ImageFormatLoader);
+ GDREGISTER_CLASS(ImageFormatLoaderExtension);
GDREGISTER_ABSTRACT_CLASS(ResourceImporter);
GDREGISTER_CLASS(NativeExtension);