diff options
Diffstat (limited to 'core')
30 files changed, 616 insertions, 63 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 15f807017f..a1b22e7f7d 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1207,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 2149ee4512..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); @@ -840,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); diff --git a/core/core_bind.h b/core/core_bind.h index 345c517b99..ba22971d78 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -32,9 +32,6 @@ #define CORE_BIND_H #include "core/debugger/engine_profiler.h" -#include "core/io/compression.h" -#include "core/io/dir_access.h" -#include "core/io/file_access.h" #include "core/io/image.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" @@ -289,6 +286,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, diff --git a/core/doc_data.h b/core/doc_data.h index 3b7bf149b4..bb356f027e 100644 --- a/core/doc_data.h +++ b/core/doc_data.h @@ -32,7 +32,6 @@ #define DOC_DATA_H #include "core/io/xml_parser.h" -#include "core/templates/rb_map.h" #include "core/variant/variant.h" struct ScriptMemberInfo { diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index 5cf951a93c..e6e0fff266 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -46,6 +46,9 @@ static String get_type_name(const PropertyInfo &p_info) { return p_info.hint_string + "*"; } } + if (p_info.type == Variant::ARRAY && (p_info.hint == PROPERTY_HINT_ARRAY_TYPE)) { + return String("typedarray::") + p_info.hint_string; + } if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM))) { return String("enum::") + String(p_info.class_name); } @@ -215,7 +218,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t); Dictionary d2; d2["name"] = name; - uint32_t size; + uint32_t size = 0; switch (i) { case 0: size = type_size_array[j].size_32_bits_real_float; @@ -330,7 +333,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { last_type = t; } Dictionary d3; - uint32_t offset; + uint32_t offset = 0; switch (i) { case 0: offset = member_offset_array[idx].offset_32_bits_real_float; @@ -462,7 +465,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/input/input_event.cpp b/core/input/input_event.cpp index 596b704732..712fc68c93 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -1325,7 +1325,7 @@ bool InputEventAction::is_match(const Ref<InputEvent> &p_event, bool p_exact_mat return false; } - return p_event->is_action(action); + return p_event->is_action(action, p_exact_match); } bool InputEventAction::is_action(const StringName &p_action) const { diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp index 4454f2a100..79e7fa16e3 100644 --- a/core/io/dir_access.cpp +++ b/core/io/dir_access.cpp @@ -261,6 +261,51 @@ Ref<DirAccess> DirAccess::_open(const String &p_path) { 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()) { @@ -445,10 +490,22 @@ PackedStringArray DirAccess::get_files() { return _get_contents(false); } +PackedStringArray DirAccess::get_files_at(const String &p_path) { + Ref<DirAccess> da = DirAccess::open(p_path); + ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\".", 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); + ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\".", p_path)); + return da->get_directories(); +} + PackedStringArray DirAccess::_get_contents(bool p_directories) { PackedStringArray ret; @@ -498,20 +555,28 @@ void DirAccess::_bind_methods() { 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_method(D_METHOD("get_drive_count"), &DirAccess::get_drive_count); - ClassDB::bind_method(D_METHOD("get_drive", "idx"), &DirAccess::get_drive); + 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", "todir"), &DirAccess::change_dir); + 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); diff --git a/core/io/dir_access.h b/core/io/dir_access.h index a694f6388f..ee675f1c89 100644 --- a/core/io/dir_access.h +++ b/core/io/dir_access.h @@ -136,8 +136,21 @@ 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(); 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.cpp b/core/io/resource.cpp index 553698f8a6..ab30fb1ca3 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -489,7 +489,7 @@ bool ResourceCache::has(const String &p_path) { Resource **res = resources.getptr(p_path); - if (res && (*res)->reference_get_count() == 0) { + if (res && (*res)->get_reference_count() == 0) { // This resource is in the process of being deleted, ignore its existence. (*res)->path_cache = String(); resources.erase(p_path); 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/bvh_structs.inc b/core/math/bvh_structs.inc index 58c8f0479a..06f6e5d05d 100644 --- a/core/math/bvh_structs.inc +++ b/core/math/bvh_structs.inc @@ -100,7 +100,11 @@ public: num_items++; return id; } +#ifdef DEV_ENABLED return -1; +#else + ERR_FAIL_V_MSG(0, "BVH request_item error."); +#endif } }; 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/object/ref_counted.cpp b/core/object/ref_counted.cpp index cac2400744..50467d795d 100644 --- a/core/object/ref_counted.cpp +++ b/core/object/ref_counted.cpp @@ -48,9 +48,10 @@ void RefCounted::_bind_methods() { ClassDB::bind_method(D_METHOD("init_ref"), &RefCounted::init_ref); ClassDB::bind_method(D_METHOD("reference"), &RefCounted::reference); ClassDB::bind_method(D_METHOD("unreference"), &RefCounted::unreference); + ClassDB::bind_method(D_METHOD("get_reference_count"), &RefCounted::get_reference_count); } -int RefCounted::reference_get_count() const { +int RefCounted::get_reference_count() const { return refcount.get(); } diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h index bd06a84bd8..71790fb825 100644 --- a/core/object/ref_counted.h +++ b/core/object/ref_counted.h @@ -47,7 +47,7 @@ public: bool init_ref(); bool reference(); // returns false if refcount is at zero and didn't get increased bool unreference(); - int reference_get_count() const; + int get_reference_count() const; RefCounted(); ~RefCounted() {} diff --git a/core/os/os.cpp b/core/os/os.cpp index 526b31ae7e..ee8da21751 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -54,10 +54,6 @@ double OS::get_unix_time() const { return 0; } -void OS::debug_break() { - // something -} - void OS::_set_logger(CompositeLogger *p_logger) { if (_logger) { memdelete(_logger); diff --git a/core/os/os.h b/core/os/os.h index 0f79ff1a23..aa45a3b8a8 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -287,8 +287,6 @@ public: virtual Error move_to_trash(const String &p_path) { return FAILED; } - virtual void debug_break(); - virtual int get_exit_code() const; // `set_exit_code` should only be used from `SceneTree` (or from a similar // level, e.g. from the `Main::start` if leaving without creating a `SceneTree`). diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp index f622e2c7c5..e7f2cff7c5 100644 --- a/core/os/pool_allocator.cpp +++ b/core/os/pool_allocator.cpp @@ -35,8 +35,6 @@ #include "core/os/os.h" #include "core/string/print_string.h" -#include <assert.h> - #define COMPACT_CHUNK(m_entry, m_to_pos) \ do { \ void *_dst = &((unsigned char *)pool)[m_to_pos]; \ @@ -169,11 +167,6 @@ bool PoolAllocator::find_entry_index(EntryIndicesPos *p_map_pos, const Entry *p_ PoolAllocator::ID PoolAllocator::alloc(int p_size) { ERR_FAIL_COND_V(p_size < 1, POOL_ALLOCATOR_INVALID_ID); -#ifdef DEBUG_ENABLED - if (p_size > free_mem) { - OS::get_singleton()->debug_break(); - } -#endif ERR_FAIL_COND_V(p_size > free_mem, POOL_ALLOCATOR_INVALID_ID); mt_lock(); @@ -482,7 +475,6 @@ void *PoolAllocator::get(ID p_mem) { ERR_FAIL_COND_V(!e, nullptr); } if (e->lock == 0) { - //assert(0); mt_unlock(); ERR_PRINT("e->lock == 0"); return nullptr; diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 0233afe199..2e144a4c9a 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -44,6 +44,7 @@ #include "core/input/input_map.h" #include "core/input/shortcut.h" #include "core/io/config_file.h" +#include "core/io/dir_access.h" #include "core/io/dtls_server.h" #include "core/io/http_client.h" #include "core/io/image_loader.h" @@ -58,6 +59,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 +186,7 @@ void register_core_types() { GDREGISTER_ABSTRACT_CLASS(StreamPeer); GDREGISTER_CLASS(StreamPeerExtension); GDREGISTER_CLASS(StreamPeerBuffer); + GDREGISTER_CLASS(StreamPeerGZIP); GDREGISTER_CLASS(StreamPeerTCP); GDREGISTER_CLASS(TCPServer); @@ -249,6 +252,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); diff --git a/core/variant/array.h b/core/variant/array.h index c007376734..3d9a794969 100644 --- a/core/variant/array.h +++ b/core/variant/array.h @@ -47,7 +47,6 @@ class Array { void _unref() const; protected: - Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script); bool _assign(const Array &p_array); public: @@ -131,6 +130,7 @@ public: void set_read_only(bool p_enable); bool is_read_only() const; + Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script); Array(const Array &p_from); Array(); ~Array(); diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index 28efb43fc5..b35e2f004b 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -63,6 +63,21 @@ void Callable::callp(const Variant **p_arguments, int p_argcount, Variant &r_ret } } +Variant Callable::callv(const Array &p_arguments) const { + int argcount = p_arguments.size(); + const Variant **argptrs = nullptr; + if (argcount) { + argptrs = (const Variant **)alloca(sizeof(Variant *) * argcount); + for (int i = 0; i < argcount; i++) { + argptrs[i] = &p_arguments[i]; + } + } + CallError ce; + Variant ret; + callp(argptrs, argcount, ret, ce); + return ret; +} + Error Callable::rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const { if (is_null()) { r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL; diff --git a/core/variant/callable.h b/core/variant/callable.h index 1f1c983eb3..0305dc55c3 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -71,6 +71,7 @@ public: void callp(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const; void call_deferredp(const Variant **p_arguments, int p_argcount) const; + Variant callv(const Array &p_arguments) const; Error rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const; diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index f09885b325..1831f7b72a 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1859,6 +1859,7 @@ static void _register_variant_builtin_methods() { /* Callable */ + bind_method(Callable, callv, sarray("arguments"), varray()); bind_method(Callable, is_null, sarray(), varray()); bind_method(Callable, is_custom, sarray(), varray()); bind_method(Callable, is_standard, sarray(), varray()); @@ -2065,6 +2066,14 @@ static void _register_variant_builtin_methods() { bind_method(Array, all, sarray("method"), varray()); bind_method(Array, max, sarray(), varray()); bind_method(Array, min, sarray(), varray()); + bind_method(Array, typed_assign, sarray("array"), varray()); + bind_method(Array, set_typed, sarray("type", "class_name", "script"), varray()); + bind_method(Array, is_typed, sarray(), varray()); + bind_method(Array, get_typed_builtin, sarray(), varray()); + bind_method(Array, get_typed_class_name, sarray(), varray()); + bind_method(Array, get_typed_script, sarray(), varray()); + bind_method(Array, set_read_only, sarray("enable"), varray()); + bind_method(Array, is_read_only, sarray(), varray()); /* Byte Array */ bind_method(PackedByteArray, size, sarray(), varray()); diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp index d048f45737..3b88dc11ca 100644 --- a/core/variant/variant_construct.cpp +++ b/core/variant/variant_construct.cpp @@ -200,6 +200,7 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructNoArgs<Array>>(sarray()); add_constructor<VariantConstructor<Array, Array>>(sarray("from")); + add_constructor<VariantConstructorTypedArray>(sarray("base", "type", "class_name", "script")); add_constructor<VariantConstructorToArray<PackedByteArray>>(sarray("from")); add_constructor<VariantConstructorToArray<PackedInt32Array>>(sarray("from")); add_constructor<VariantConstructorToArray<PackedInt64Array>>(sarray("from")); diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h index 58a0f34c1e..34d228f4d2 100644 --- a/core/variant/variant_construct.h +++ b/core/variant/variant_construct.h @@ -336,6 +336,82 @@ public: } }; +class VariantConstructorTypedArray { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + if (p_args[0]->get_type() != Variant::ARRAY) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::ARRAY; + return; + } + + if (p_args[1]->get_type() != Variant::INT) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::INT; + return; + } + + if (p_args[2]->get_type() != Variant::STRING_NAME) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 2; + r_error.expected = Variant::STRING_NAME; + return; + } + + const Array &base_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]); + const uint32_t type = p_args[1]->operator uint32_t(); + const StringName &class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]); + r_ret = Array(base_arr, type, class_name, *p_args[3]); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + const Array &base_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]); + const uint32_t type = p_args[1]->operator uint32_t(); + const StringName &class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]); + *r_ret = Array(base_arr, type, class_name, *p_args[3]); + } + + static void ptr_construct(void *base, const void **p_args) { + const Array &base_arr = PtrToArg<Array>::convert(p_args[0]); + const uint32_t type = PtrToArg<uint32_t>::convert(p_args[1]); + const StringName &class_name = PtrToArg<StringName>::convert(p_args[2]); + const Variant &script = PtrToArg<Variant>::convert(p_args[3]); + Array dst_arr = Array(base_arr, type, class_name, script); + + PtrConstruct<Array>::construct(dst_arr, base); + } + + static int get_argument_count() { + return 4; + } + + static Variant::Type get_argument_type(int p_arg) { + switch (p_arg) { + case 0: { + return Variant::ARRAY; + } break; + case 1: { + return Variant::INT; + } break; + case 2: { + return Variant::STRING_NAME; + } break; + case 3: { + return Variant::NIL; + } break; + default: { + return Variant::NIL; + } break; + } + } + + static Variant::Type get_base_type() { + return Variant::ARRAY; + } +}; + template <class T> class VariantConstructorToArray { public: |