diff options
Diffstat (limited to 'core')
75 files changed, 758 insertions, 290 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 57654e96dc..0032c43179 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -180,6 +180,7 @@ void _ResourceSaver::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_OMIT_EDITOR_PROPERTIES); BIND_ENUM_CONSTANT(FLAG_SAVE_BIG_ENDIAN); BIND_ENUM_CONSTANT(FLAG_COMPRESS); + BIND_ENUM_CONSTANT(FLAG_REPLACE_SUBRESOURCE_PATHS); } _ResourceSaver::_ResourceSaver() { @@ -1019,6 +1020,11 @@ void _OS::center_window() { OS::get_singleton()->center_window(); } +void _OS::move_window_to_foreground() { + + OS::get_singleton()->move_window_to_foreground(); +} + bool _OS::is_debug_build() const { #ifdef DEBUG_ENABLED @@ -1120,6 +1126,7 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("request_attention"), &_OS::request_attention); ClassDB::bind_method(D_METHOD("get_real_window_size"), &_OS::get_real_window_size); ClassDB::bind_method(D_METHOD("center_window"), &_OS::center_window); + ClassDB::bind_method(D_METHOD("move_window_to_foreground"), &_OS::move_window_to_foreground); ClassDB::bind_method(D_METHOD("set_borderless_window", "borderless"), &_OS::set_borderless_window); ClassDB::bind_method(D_METHOD("get_borderless_window"), &_OS::get_borderless_window); @@ -1747,9 +1754,9 @@ String _File::get_line() const { return f->get_line(); } -Vector<String> _File::get_csv_line(String delim) const { +Vector<String> _File::get_csv_line(const String &p_delim) const { ERR_FAIL_COND_V(!f, Vector<String>()); - return f->get_csv_line(delim); + return f->get_csv_line(p_delim); } /**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac) @@ -1846,6 +1853,11 @@ void _File::store_line(const String &p_string) { f->store_line(p_string); } +void _File::store_csv_line(const Vector<String> &p_values, const String &p_delim) { + ERR_FAIL_COND(!f); + f->store_csv_line(p_values, p_delim); +} + void _File::store_buffer(const PoolVector<uint8_t> &p_buffer) { ERR_FAIL_COND(!f); @@ -1929,6 +1941,7 @@ void _File::_bind_methods() { ClassDB::bind_method(D_METHOD("get_real"), &_File::get_real); ClassDB::bind_method(D_METHOD("get_buffer", "len"), &_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"), &_File::get_as_text); ClassDB::bind_method(D_METHOD("get_md5", "path"), &_File::get_md5); ClassDB::bind_method(D_METHOD("get_sha256", "path"), &_File::get_sha256); @@ -1936,7 +1949,6 @@ void _File::_bind_methods() { ClassDB::bind_method(D_METHOD("set_endian_swap", "enable"), &_File::set_endian_swap); ClassDB::bind_method(D_METHOD("get_error"), &_File::get_error); ClassDB::bind_method(D_METHOD("get_var"), &_File::get_var); - ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &_File::get_csv_line, DEFVAL(",")); ClassDB::bind_method(D_METHOD("store_8", "value"), &_File::store_8); ClassDB::bind_method(D_METHOD("store_16", "value"), &_File::store_16); @@ -1947,6 +1959,7 @@ void _File::_bind_methods() { 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"), &_File::store_var); @@ -2487,7 +2500,7 @@ _Thread::~_Thread() { if (active) { ERR_EXPLAIN("Reference to a Thread object object was lost while the thread is still running..."); } - ERR_FAIL_COND(active == true); + ERR_FAIL_COND(active); } ///////////////////////////////////// @@ -2859,10 +2872,10 @@ void JSONParseResult::_bind_methods() { ClassDB::bind_method(D_METHOD("set_error_line", "error_line"), &JSONParseResult::set_error_line); ClassDB::bind_method(D_METHOD("set_result", "result"), &JSONParseResult::set_result); - ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "error", PROPERTY_HINT_NONE, "Error", PROPERTY_USAGE_CLASS_IS_ENUM), "set_error", "get_error"); - ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "error_string"), "set_error_string", "get_error_string"); - ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "error_line"), "set_error_line", "get_error_line"); - ADD_PROPERTYNZ(PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_result", "get_result"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "error", PROPERTY_HINT_NONE, "Error", PROPERTY_USAGE_CLASS_IS_ENUM), "set_error", "get_error"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "error_string"), "set_error_string", "get_error_string"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "error_line"), "set_error_line", "get_error_line"); + ADD_PROPERTY(PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_result", "get_result"); } void JSONParseResult::set_error(Error p_error) { diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 3a913e01ed..720b14bf56 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -80,6 +80,7 @@ public: FLAG_OMIT_EDITOR_PROPERTIES = 8, FLAG_SAVE_BIG_ENDIAN = 16, FLAG_COMPRESS = 32, + FLAG_REPLACE_SUBRESOURCE_PATHS = 64, }; static _ResourceSaver *get_singleton() { return singleton; } @@ -184,6 +185,7 @@ public: virtual bool is_window_always_on_top() const; virtual void request_attention(); virtual void center_window(); + virtual void move_window_to_foreground(); virtual void set_borderless_window(bool p_borderless); virtual bool get_borderless_window() const; @@ -453,6 +455,7 @@ public: PoolVector<uint8_t> get_buffer(int 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() const; String get_md5(const String &p_path) const; String get_sha256(const String &p_path) const; @@ -478,12 +481,11 @@ public: 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(); - Vector<String> get_csv_line(String delim = ",") const; - void store_buffer(const PoolVector<uint8_t> &p_buffer); ///< store an array of bytes void store_var(const Variant &p_var); diff --git a/core/class_db.cpp b/core/class_db.cpp index dcc07f8f41..052a4586fe 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -809,10 +809,10 @@ void ClassDB::add_signal(StringName p_class, const MethodInfo &p_signal) { ClassInfo *type = classes.getptr(p_class); ERR_FAIL_COND(!type); - ClassInfo *check = type; StringName sname = p_signal.name; -#ifdef DEBUG_METHODS_ENABLED +#ifdef DEBUG_METHODS_ENABLED + ClassInfo *check = type; while (check) { if (check->signal_map.has(sname)) { ERR_EXPLAIN("Type " + String(p_class) + " already has signal: " + String(sname)); @@ -936,9 +936,8 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons } #ifdef DEBUG_METHODS_ENABLED - if (type->property_setget.has(p_pinfo.name)) { - ERR_EXPLAIN("Object already has property: " + p_class); + ERR_EXPLAIN("Object " + p_class + " already has property: " + p_pinfo.name); ERR_FAIL(); } #endif @@ -1367,6 +1366,41 @@ void ClassDB::get_extensions_for_type(const StringName &p_class, List<String> *p } } +HashMap<StringName, HashMap<StringName, Variant> > ClassDB::default_values; + +Variant ClassDB::class_get_default_property_value(const StringName &p_class, const StringName &p_property) { + + if (!default_values.has(p_class)) { + + default_values[p_class] = HashMap<StringName, Variant>(); + + if (ClassDB::can_instance(p_class)) { + + Object *c = ClassDB::instance(p_class); + List<PropertyInfo> plist; + c->get_property_list(&plist); + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + if (E->get().usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR)) { + + Variant v = c->get(E->get().name); + default_values[p_class][E->get().name] = v; + } + } + memdelete(c); + } + } + + if (!default_values.has(p_class)) { + return Variant(); + } + + if (!default_values[p_class].has(p_property)) { + return Variant(); + } + + return default_values[p_class][p_property]; +} + RWLock *ClassDB::lock = NULL; void ClassDB::init() { @@ -1393,6 +1427,7 @@ void ClassDB::cleanup() { classes.clear(); resource_base_extensions.clear(); compat_classes.clear(); + default_values.clear(); memdelete(lock); } diff --git a/core/class_db.h b/core/class_db.h index 11cc3033cf..75f9e8d6a7 100644 --- a/core/class_db.h +++ b/core/class_db.h @@ -161,6 +161,8 @@ public: static void _add_class2(const StringName &p_class, const StringName &p_inherits); + static HashMap<StringName, HashMap<StringName, Variant> > default_values; + public: // DO NOT USE THIS!!!!!! NEEDS TO BE PUBLIC BUT DO NOT USE NO MATTER WHAT!!! template <class T> @@ -352,6 +354,8 @@ public: static void get_enum_list(const StringName &p_class, List<StringName> *p_enums, bool p_no_inheritance = false); static void get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance = false); + static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property); + static StringName get_category(const StringName &p_node); static void set_class_enabled(StringName p_class, bool p_enable); diff --git a/core/color.cpp b/core/color.cpp index 55dd1ec6b9..ac314417ec 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -468,7 +468,7 @@ String Color::to_html(bool p_alpha) const { return txt; } -Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) { +Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const { p_h = Math::fmod(p_h * 360.0f, 360.0f); if (p_h < 0.0) diff --git a/core/color.h b/core/color.h index add61343ff..d6ad5f91c5 100644 --- a/core/color.h +++ b/core/color.h @@ -194,7 +194,7 @@ struct Color { static bool html_is_valid(const String &p_color); static Color named(const String &p_name); String to_html(bool p_alpha = true) const; - Color from_hsv(float p_h, float p_s, float p_v, float p_a); + Color from_hsv(float p_h, float p_s, float p_v, float p_a) const; static Color from_rgbe9995(uint32_t p_color); _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys diff --git a/core/cowdata.h b/core/cowdata.h index 9e75d4ed55..54ece4c856 100644 --- a/core/cowdata.h +++ b/core/cowdata.h @@ -87,7 +87,10 @@ private: #if defined(_add_overflow) && defined(_mul_overflow) size_t o; size_t p; - if (_mul_overflow(p_elements, sizeof(T), &o)) return false; + if (_mul_overflow(p_elements, sizeof(T), &o)) { + *out = 0; + return false; + } *out = next_power_of_2(o); if (_add_overflow(o, static_cast<size_t>(32), &p)) return false; //no longer allocated here return true; diff --git a/core/dictionary.cpp b/core/dictionary.cpp index ba32606819..6a3ab82879 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -112,6 +112,15 @@ Variant Dictionary::get_valid(const Variant &p_key) const { return E.get(); } +Variant Dictionary::get(const Variant &p_key, const Variant &p_default) const { + const Variant *result = getptr(p_key); + if (!result) { + return p_default; + } + + return *result; +} + int Dictionary::size() const { return _p->variant_map.size(); @@ -145,6 +154,11 @@ bool Dictionary::operator==(const Dictionary &p_dictionary) const { return _p == p_dictionary._p; } +bool Dictionary::operator!=(const Dictionary &p_dictionary) const { + + return _p != p_dictionary._p; +} + void Dictionary::_ref(const Dictionary &p_from) const { //make a copy first (thread safe) diff --git a/core/dictionary.h b/core/dictionary.h index 9950fb6361..b77cc55254 100644 --- a/core/dictionary.h +++ b/core/dictionary.h @@ -58,6 +58,7 @@ public: Variant *getptr(const Variant &p_key); Variant get_valid(const Variant &p_key) const; + Variant get(const Variant &p_key, const Variant &p_default) const; int size() const; bool empty() const; @@ -69,6 +70,7 @@ public: bool erase(const Variant &p_key); bool operator==(const Dictionary &p_dictionary) const; + bool operator!=(const Dictionary &p_dictionary) const; uint32_t hash() const; void operator=(const Dictionary &p_dictionary); diff --git a/core/dvector.h b/core/dvector.h index 0d0848a19a..2830c57ec0 100644 --- a/core/dvector.h +++ b/core/dvector.h @@ -149,7 +149,7 @@ class PoolVector { } } - if (old_alloc->refcount.unref() == true) { + if (old_alloc->refcount.unref()) { //this should never happen but.. #ifdef DEBUG_ENABLED @@ -209,7 +209,7 @@ class PoolVector { if (!alloc) return; - if (alloc->refcount.unref() == false) { + if (!alloc->refcount.unref()) { alloc = NULL; return; } diff --git a/core/global_constants.cpp b/core/global_constants.cpp index c70f960a66..7e9b8b393c 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -547,8 +547,9 @@ void register_global_constants() { BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_INTERNATIONALIZED); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_GROUP); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_CATEGORY); - BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONZERO); - BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONONE); + //deprecated, replaced by ClassDB function to check default value + //BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONZERO); + //BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_STORE_IF_NONONE); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_NO_INSTANCE_STATE); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_RESTART_IF_CHANGED); BIND_GLOBAL_ENUM_CONSTANT(PROPERTY_USAGE_SCRIPT_VARIABLE); diff --git a/core/hash_map.h b/core/hash_map.h index 8620edba73..3869cd3c36 100644 --- a/core/hash_map.h +++ b/core/hash_map.h @@ -150,7 +150,7 @@ private: if (new_hash_table_power == -1) return; - Element **new_hash_table = memnew_arr(Element *, (1 << new_hash_table_power)); + Element **new_hash_table = memnew_arr(Element *, ((uint64_t)1 << new_hash_table_power)); if (!new_hash_table) { ERR_PRINT("Out of Memory"); @@ -230,7 +230,7 @@ private: if (!p_t.hash_table || p_t.hash_table_power == 0) return; /* not copying from empty table */ - hash_table = memnew_arr(Element *, 1 << p_t.hash_table_power); + hash_table = memnew_arr(Element *, (uint64_t)1 << p_t.hash_table_power); hash_table_power = p_t.hash_table_power; elements = p_t.elements; diff --git a/core/image.cpp b/core/image.cpp index c0002e0cd6..dca8aedb8f 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -307,6 +307,7 @@ void Image::_get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_widt r_width = w; r_height = h; } + int Image::get_mipmap_offset(int p_mipmap) const { ERR_FAIL_INDEX_V(p_mipmap, get_mipmap_count() + 1, -1); @@ -499,8 +500,6 @@ void Image::convert(Format p_new_format) { bool gen_mipmaps = mipmaps; - //mipmaps=false; - _copy_internals_from(new_img); if (gen_mipmaps) @@ -781,9 +780,9 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { // Setup mipmap-aware scaling Image dst2; - int mip1; - int mip2; - float mip1_weight; + int mip1 = 0; + int mip2 = 0; + float mip1_weight = 0; if (mipmap_aware) { float avg_scale = ((float)p_width / width + (float)p_height / height) * 0.5f; if (avg_scale >= 1.0f) { @@ -799,6 +798,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { if (interpolate_mipmaps) { dst2.create(p_width, p_height, 0, format); } + bool had_mipmaps = mipmaps; if (interpolate_mipmaps && !had_mipmaps) { generate_mipmaps(); @@ -951,6 +951,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { } void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) { + if (!_can_modify(format)) { ERR_EXPLAIN("Cannot crop in indexed, compressed or custom image formats."); ERR_FAIL(); @@ -996,7 +997,7 @@ void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) { } } - if (mipmaps > 0) + if (has_mipmaps()) dst.generate_mipmaps(); _copy_internals_from(dst); } @@ -1013,10 +1014,10 @@ void Image::flip_y() { ERR_FAIL(); } - bool gm = mipmaps; - - if (gm) + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { clear_mipmaps(); + } { PoolVector<uint8_t>::Write w = data.write(); @@ -1037,8 +1038,9 @@ void Image::flip_y() { } } - if (gm) + if (used_mipmaps) { generate_mipmaps(); + } } void Image::flip_x() { @@ -1048,9 +1050,10 @@ void Image::flip_x() { ERR_FAIL(); } - bool gm = mipmaps; - if (gm) + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { clear_mipmaps(); + } { PoolVector<uint8_t>::Write w = data.write(); @@ -1071,8 +1074,9 @@ void Image::flip_x() { } } - if (gm) + if (used_mipmaps) { generate_mipmaps(); + } } int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps) { @@ -1167,12 +1171,13 @@ void Image::expand_x2_hq2x() { ERR_FAIL_COND(!_can_modify(format)); - Format current = format; - bool mm = has_mipmaps(); - if (mm) { + bool used_mipmaps = has_mipmaps(); + if (used_mipmaps) { clear_mipmaps(); } + Format current = format; + if (current != FORMAT_RGBA8) convert(FORMAT_RGBA8); @@ -1193,6 +1198,8 @@ void Image::expand_x2_hq2x() { if (current != FORMAT_RGBA8) convert(current); + // FIXME: This is likely meant to use "used_mipmaps" as defined above, but if we do, + // we end up with a regression: GH-22747 if (mipmaps) { generate_mipmaps(); } @@ -1466,7 +1473,8 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma void Image::create(const char **p_xpm) { - int size_width, size_height; + int size_width = 0; + int size_height = 0; int pixelchars = 0; mipmaps = false; bool has_alpha = false; @@ -1482,8 +1490,8 @@ void Image::create(const char **p_xpm) { int line = 0; HashMap<String, Color> colormap; - int colormap_size; - uint32_t pixel_size; + int colormap_size = 0; + uint32_t pixel_size = 0; PoolVector<uint8_t>::Write w; while (status != DONE) { @@ -1758,6 +1766,15 @@ int Image::get_image_required_mipmaps(int p_width, int p_height, Format p_format return mm; } +int Image::get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap) { + + if (p_mipmap <= 0) { + return 0; + } + int mm; + return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmap - 1); +} + bool Image::is_compressed() const { return format > FORMAT_RGBE9995; } @@ -1914,7 +1931,8 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) return; - Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest, clipped_src_rect.size)); + Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y)); + Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size)); PoolVector<uint8_t>::Write wp = data.write(); uint8_t *dst_data_ptr = wp.ptr(); @@ -1968,7 +1986,8 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) return; - Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest, clipped_src_rect.size)); + Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y)); + Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size)); PoolVector<uint8_t>::Write wp = data.write(); uint8_t *dst_data_ptr = wp.ptr(); @@ -2025,7 +2044,8 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) return; - Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest, clipped_src_rect.size)); + Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y)); + Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size)); lock(); Ref<Image> img = p_src; @@ -2079,7 +2099,8 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) return; - Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest, clipped_src_rect.size)); + Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y)); + Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size)); lock(); Ref<Image> img = p_src; diff --git a/core/image.h b/core/image.h index 11f9380c3c..0770eb953e 100644 --- a/core/image.h +++ b/core/image.h @@ -286,6 +286,7 @@ public: static int get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps = false); static int get_image_required_mipmaps(int p_width, int p_height, Format p_format); + static int get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap); enum CompressMode { COMPRESS_S3TC, diff --git a/core/io/compression.cpp b/core/io/compression.cpp index e456a85c65..3c0b6541bd 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -175,7 +175,7 @@ int Compression::decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p } break; case MODE_ZSTD: { ZSTD_DCtx *dctx = ZSTD_createDCtx(); - if (zstd_long_distance_matching) ZSTD_DCtx_setMaxWindowSize(dctx, 1 << zstd_window_log_size); + if (zstd_long_distance_matching) ZSTD_DCtx_setMaxWindowSize(dctx, (size_t)1 << zstd_window_log_size); int ret = ZSTD_decompressDCtx(dctx, p_dst, p_dst_max_size, p_src, p_src_size); ZSTD_freeDCtx(dctx); return ret; diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 6b6856dcc8..b9544ac166 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -500,8 +500,9 @@ uint64_t FileAccessNetwork::_get_modified_time(const String &p_file) { void FileAccessNetwork::configure() { GLOBAL_DEF("network/remote_fs/page_size", 65536); + ProjectSettings::get_singleton()->set_custom_property_info("network/remote_fs/page_size", PropertyInfo(Variant::INT, "network/remote_fs/page_size", PROPERTY_HINT_RANGE, "1,65536,1,or_greater")); //is used as denominator and can't be zero GLOBAL_DEF("network/remote_fs/page_read_ahead", 4); - GLOBAL_DEF("network/remote_fs/max_pages", 20); + ProjectSettings::get_singleton()->set_custom_property_info("network/remote_fs/page_read_ahead", PropertyInfo(Variant::INT, "network/remote_fs/page_read_ahead", PROPERTY_HINT_RANGE, "0,8,1,or_greater")); } FileAccessNetwork::FileAccessNetwork() { @@ -519,7 +520,6 @@ FileAccessNetwork::FileAccessNetwork() { nc->unlock_mutex(); page_size = GLOBAL_GET("network/remote_fs/page_size"); read_ahead = GLOBAL_GET("network/remote_fs/page_read_ahead"); - max_pages = GLOBAL_GET("network/remote_fs/max_pages"); last_activity_val = 0; waiting_on_page = -1; last_page = -1; diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index e32dcea990..c929e8446d 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -98,7 +98,6 @@ class FileAccessNetwork : public FileAccess { int page_size; int read_ahead; - int max_pages; mutable int waiting_on_page; mutable int last_activity_val; diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index e3c8fb9eb8..3823285792 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -169,11 +169,11 @@ bool PackedSourcePCK::try_open_pack(const String &p_path) { uint32_t version = f->get_32(); uint32_t ver_major = f->get_32(); uint32_t ver_minor = f->get_32(); - uint32_t ver_rev = f->get_32(); + f->get_32(); // ver_rev ERR_EXPLAIN("Pack version unsupported: " + itos(version)); ERR_FAIL_COND_V(version != PACK_VERSION, false); - ERR_EXPLAIN("Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + "." + itos(ver_rev)); + ERR_EXPLAIN("Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor)); ERR_FAIL_COND_V(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false); for (int i = 0; i < 16; i++) { @@ -455,7 +455,7 @@ String DirAccessPack::get_current_dir() { while (pd->parent) { pd = pd->parent; - p = pd->name + "/" + p; + p = pd->name.plus_file(p); } return "res://" + p; diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index f202320043..e4fbb0247d 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -60,7 +60,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_c String extension = p_file.get_extension(); - for (int i = 0; i < loader_count; i++) { + for (int i = 0; i < loader.size(); i++) { if (!loader[i]->recognize(extension)) continue; @@ -83,30 +83,45 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, FileAccess *p_c void ImageLoader::get_recognized_extensions(List<String> *p_extensions) { - for (int i = 0; i < loader_count; i++) { + for (int i = 0; i < loader.size(); i++) { loader[i]->get_recognized_extensions(p_extensions); } } -bool ImageLoader::recognize(const String &p_extension) { +ImageFormatLoader *ImageLoader::recognize(const String &p_extension) { - for (int i = 0; i < loader_count; i++) { + for (int i = 0; i < loader.size(); i++) { if (loader[i]->recognize(p_extension)) - return true; + return loader[i]; } - return false; + return NULL; } -ImageFormatLoader *ImageLoader::loader[MAX_LOADERS]; -int ImageLoader::loader_count = 0; +Vector<ImageFormatLoader *> ImageLoader::loader; void ImageLoader::add_image_format_loader(ImageFormatLoader *p_loader) { - ERR_FAIL_COND(loader_count >= MAX_LOADERS); - loader[loader_count++] = p_loader; + loader.push_back(p_loader); +} + +void ImageLoader::remove_image_format_loader(ImageFormatLoader *p_loader) { + + loader.erase(p_loader); +} + +const Vector<ImageFormatLoader *> &ImageLoader::get_image_format_loaders() { + + return loader; +} + +void ImageLoader::cleanup() { + + while (loader.size()) { + remove_image_format_loader(loader[0]); + } } ///////////////// @@ -118,7 +133,6 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin if (r_error) { *r_error = ERR_CANT_OPEN; } - memdelete(f); return RES(); } @@ -138,7 +152,7 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin int idx = -1; - for (int i = 0; i < ImageLoader::loader_count; i++) { + for (int i = 0; i < ImageLoader::loader.size(); i++) { if (ImageLoader::loader[i]->recognize(extension)) { idx = i; break; diff --git a/core/io/image_loader.h b/core/io/image_loader.h index 561f275e0c..7a58d46f93 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -70,20 +70,21 @@ public: class ImageLoader { - enum { - MAX_LOADERS = 8 - }; + static Vector<ImageFormatLoader *> loader; friend class ResourceFormatLoaderImage; - static ImageFormatLoader *loader[MAX_LOADERS]; - static int loader_count; protected: public: static Error load_image(String p_file, Ref<Image> p_image, FileAccess *p_custom = NULL, bool p_force_linear = false, float p_scale = 1.0); static void get_recognized_extensions(List<String> *p_extensions); - static bool recognize(const String &p_extension); + static 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 const Vector<ImageFormatLoader *> &get_image_format_loaders(); + + static void cleanup(); }; class ResourceFormatLoaderImage : public ResourceFormatLoader { diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp index 6d979d10eb..194d1af6bf 100644 --- a/core/io/ip_address.cpp +++ b/core/io/ip_address.cpp @@ -184,7 +184,7 @@ bool IP_Address::is_ipv4() const { } const uint8_t *IP_Address::get_ipv4() const { - ERR_FAIL_COND_V(!is_ipv4(), 0); + ERR_FAIL_COND_V(!is_ipv4(), &(field8[12])); // Not the correct IPv4 (it's an IPv6), but we don't want to return a null pointer risking an engine crash. return &(field8[12]); } diff --git a/core/io/logger.cpp b/core/io/logger.cpp index 051c02ab32..01755c8ee9 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -45,6 +45,10 @@ #endif #endif +#if defined(MINGW_ENABLED) || defined(_MSC_VER) +#define sprintf sprintf_s +#endif + bool Logger::should_log(bool p_err) { return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled); } diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 628019ef7f..6338cee39d 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -850,17 +850,16 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } break; case Variant::INT: { - int64_t val = p_variant; if (flags & ENCODE_FLAG_64) { //64 bits if (buf) { - encode_uint64(val, buf); + encode_uint64(p_variant.operator int64_t(), buf); } r_len += 8; } else { if (buf) { - encode_uint32(int32_t(val), buf); + encode_uint32(p_variant.operator int32_t(), buf); } r_len += 4; @@ -868,8 +867,6 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } break; case Variant::REAL: { - double d = p_variant; - float f = d; if (flags & ENCODE_FLAG_64) { if (buf) { encode_double(p_variant.operator double(), buf); diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 17b77bc535..b3f0a76a80 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -416,7 +416,7 @@ bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); - if (!F || F->get() == false) { + if (!F || !F->get()) { // Path was not cached, or was cached but is unconfirmed. if (!F) { // Not cached at all, take note. @@ -578,7 +578,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p network_peer->set_target_peer(E->get()); // To this one specifically. - if (F->get() == true) { + if (F->get()) { // This one confirmed path, so use id. encode_uint32(psc->id, &(packet_cache.write[1])); network_peer->put_packet(packet_cache.ptr(), ofs); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index e5741014a4..6f3a8c3d2e 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -1309,7 +1309,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia case Variant::INT: { int64_t val = p_property; - if (val > 0x7FFFFFFF || val < -0x80000000) { + if (val > 0x7FFFFFFF || val < -(int64_t)0x80000000) { f->store_32(VARIANT_INT64); f->store_64(val); @@ -1813,8 +1813,13 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p Property p; p.name_idx = get_string_index(F->get().name); p.value = E->get()->get(F->get().name); - if (((F->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && p.value.is_zero()) || ((F->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && p.value.is_one())) + + Variant default_value = ClassDB::class_get_default_property_value(E->get()->get_class(), F->get().name); + + if (default_value.get_type() != Variant::NIL && bool(Variant::evaluate(Variant::OP_EQUAL, p.value, default_value))) { continue; + } + p.pi = F->get(); rd.properties.push_back(p); diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 8c56d55e85..71b01aa94a 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -259,6 +259,10 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p } #endif + if (_loaded_callback) { + _loaded_callback(res, p_path); + } + return res; } @@ -635,6 +639,12 @@ void ResourceLoader::clear_path_remaps() { path_remaps.clear(); } +void ResourceLoader::set_load_callback(ResourceLoadedCallback p_callback) { + _loaded_callback = p_callback; +} + +ResourceLoadedCallback ResourceLoader::_loaded_callback = NULL; + ResourceLoadErrorNotify ResourceLoader::err_notify = NULL; void *ResourceLoader::err_notify_ud = NULL; @@ -647,3 +657,5 @@ bool ResourceLoader::timestamp_on_load = false; SelfList<Resource>::List ResourceLoader::remapped_list; HashMap<String, Vector<String> > ResourceLoader::translation_remaps; HashMap<String, String> ResourceLoader::path_remaps; + +ResourceLoaderImport ResourceLoader::import = NULL; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index de0981350d..a46a00203f 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -77,6 +77,9 @@ public: typedef void (*ResourceLoadErrorNotify)(void *p_ud, const String &p_text); typedef void (*DependencyErrorNotify)(void *p_ud, const String &p_loading, const String &p_which, const String &p_type); +typedef Error (*ResourceLoaderImport)(const String &p_path); +typedef void (*ResourceLoadedCallback)(RES p_resource, const String &p_path); + class ResourceLoader { enum { @@ -104,6 +107,8 @@ class ResourceLoader { //internal load function static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error); + static ResourceLoadedCallback _loaded_callback; + public: static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); @@ -118,6 +123,7 @@ public: static int get_import_order(const String &p_path); static void set_timestamp_on_load(bool p_timestamp) { timestamp_on_load = p_timestamp; } + static bool get_timestamp_on_load() { return timestamp_on_load; } static void notify_load_error(const String &p_err) { if (err_notify) err_notify(err_notify_ud, p_err); @@ -147,6 +153,9 @@ public: static void reload_translation_remaps(); static void load_translation_remaps(); static void clear_translation_remaps(); + + static void set_load_callback(ResourceLoadedCallback p_callback); + static ResourceLoaderImport import; }; #endif diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 5c8188f735..097e81e308 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -90,7 +90,7 @@ Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t rwcopy->set_path(old_path); if (save_callback && p_path.begins_with("res://")) - save_callback(p_path); + save_callback(p_resource, p_path); return OK; } else { diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h index 7ed580f2d6..cdd43292a2 100644 --- a/core/io/resource_saver.h +++ b/core/io/resource_saver.h @@ -46,7 +46,7 @@ public: virtual ~ResourceFormatSaver() {} }; -typedef void (*ResourceSavedCallback)(const String &p_path); +typedef void (*ResourceSavedCallback)(Ref<Resource> p_resource, const String &p_path); class ResourceSaver { @@ -76,6 +76,8 @@ public: static void add_resource_format_saver(ResourceFormatSaver *p_format_saver, bool p_at_front = false); static void set_timestamp_on_save(bool p_timestamp) { timestamp_on_save = p_timestamp; } + static bool get_timestamp_on_save() { return timestamp_on_save; } + static void set_save_callback(ResourceSavedCallback p_callback); }; diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp index 6e51c56357..6ffc963783 100644 --- a/core/math/bsp_tree.cpp +++ b/core/math/bsp_tree.cpp @@ -165,7 +165,6 @@ int BSP_Tree::get_points_inside(const Vector3 *p_points, int p_point_count) cons int pass_count = 0; const Node *nodesptr = &nodes[0]; const Plane *planesptr = &planes[0]; - int plane_count = planes.size(); int node_count = nodes.size(); if (node_count == 0) // no nodes! @@ -192,9 +191,9 @@ int BSP_Tree::get_points_inside(const Vector3 *p_points, int p_point_count) cons break; } - uint16_t plane = nodesptr[idx].plane; #ifdef DEBUG_ENABLED - + int plane_count = planes.size(); + uint16_t plane = nodesptr[idx].plane; ERR_FAIL_INDEX_V(plane, plane_count, false); #endif diff --git a/core/math/expression.cpp b/core/math/expression.cpp index a16267cf0a..0cfb54234c 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -2120,6 +2120,10 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu } Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) { + if (error_set) { + ERR_EXPLAIN("There was previously a parse error: " + error_str); + ERR_FAIL_V(Variant()); + } execution_error = false; Variant output; diff --git a/core/math/face3.cpp b/core/math/face3.cpp index aa46fde7f7..8366137131 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -202,11 +202,12 @@ bool Face3::intersects_aabb(const AABB &p_aabb) const { { \ real_t aabb_min = p_aabb.position.m_ax; \ real_t aabb_max = p_aabb.position.m_ax + p_aabb.size.m_ax; \ - real_t tri_min, tri_max; \ - for (int i = 0; i < 3; i++) { \ - if (i == 0 || vertex[i].m_ax > tri_max) \ + real_t tri_min = vertex[0].m_ax; \ + real_t tri_max = vertex[0].m_ax; \ + for (int i = 1; i < 3; i++) { \ + if (vertex[i].m_ax > tri_max) \ tri_max = vertex[i].m_ax; \ - if (i == 0 || vertex[i].m_ax < tri_min) \ + if (vertex[i].m_ax < tri_min) \ tri_min = vertex[i].m_ax; \ } \ \ diff --git a/core/math/geometry.h b/core/math/geometry.h index a813a90774..df63f0dabe 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -800,6 +800,21 @@ public: return Vector<Vector<Vector2> >(); } + static bool is_polygon_clockwise(const Vector<Vector2> &p_polygon) { + int c = p_polygon.size(); + if (c < 3) + return false; + const Vector2 *p = p_polygon.ptr(); + real_t sum = 0; + for (int i = 0; i < c; i++) { + const Vector2 &v1 = p[i]; + const Vector2 &v2 = p[(i + 1) % c]; + sum += (v2.x - v1.x) * (v2.y + v1.y); + } + + return sum > 0.0f; + } + static PoolVector<PoolVector<Face3> > separate_objects(PoolVector<Face3> p_array); static PoolVector<Face3> wrap_geometry(PoolVector<Face3> p_array, real_t *p_error = NULL); ///< create a "wrap" that encloses the given geometry diff --git a/core/math/math_defs.h b/core/math/math_defs.h index a5feee6eb5..db9055cee2 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -93,9 +93,9 @@ enum Corner { }; /** - * The "Real" type is an abstract type used for real numbers, such as 1.5, + * The "Real" type is an abstract type used for real numbers, such as 1.5, * in contrast to integer numbers. Precision can be controlled with the - * presence or absence of the REAL_T_IS_DOUBLE define. + * presence or absence of the REAL_T_IS_DOUBLE define. */ #ifdef REAL_T_IS_DOUBLE typedef double real_t; diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp index 0c06d2a2b5..06355d15ed 100644 --- a/core/math/math_funcs.cpp +++ b/core/math/math_funcs.cpp @@ -30,30 +30,27 @@ #include "math_funcs.h" -#include "core/os/os.h" - -pcg32_random_t Math::default_pcg = { 12047754176567800795ULL, PCG_DEFAULT_INC_64 }; +RandomPCG Math::default_rand(RandomPCG::DEFAULT_SEED, RandomPCG::DEFAULT_INC); #define PHI 0x9e3779b9 -// TODO: we should eventually expose pcg.inc too uint32_t Math::rand_from_seed(uint64_t *seed) { - pcg32_random_t pcg = { *seed, PCG_DEFAULT_INC_64 }; - uint32_t r = pcg32_random_r(&pcg); - *seed = pcg.state; + RandomPCG rng = RandomPCG(*seed, RandomPCG::DEFAULT_INC); + uint32_t r = rng.rand(); + *seed = rng.get_seed(); return r; } void Math::seed(uint64_t x) { - default_pcg.state = x; + default_rand.seed(x); } void Math::randomize() { - seed(OS::get_singleton()->get_ticks_usec() * default_pcg.state + PCG_DEFAULT_INC_64); + default_rand.randomize(); } uint32_t Math::rand() { - return pcg32_random_r(&default_pcg); + return default_rand.rand(); } int Math::step_decimals(double p_step) { @@ -169,13 +166,9 @@ uint32_t Math::larger_prime(uint32_t p_val) { } double Math::random(double from, double to) { - unsigned int r = Math::rand(); - double ret = (double)r / (double)RANDOM_MAX; - return (ret) * (to - from) + from; + return default_rand.random(from, to); } float Math::random(float from, float to) { - unsigned int r = Math::rand(); - float ret = (float)r / (float)RANDOM_MAX; - return (ret) * (to - from) + from; + return default_rand.random(from, to); } diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 472baf0484..f9d89d5d5a 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -32,6 +32,7 @@ #define MATH_FUNCS_H #include "core/math/math_defs.h" +#include "core/math/random_pcg.h" #include "core/typedefs.h" #include "thirdparty/misc/pcg.h" @@ -41,12 +42,12 @@ class Math { - static pcg32_random_t default_pcg; + static RandomPCG default_rand; public: Math() {} // useless to instance - static const uint64_t RANDOM_MAX = 4294967295; + static const uint64_t RANDOM_MAX = 0xFFFFFFFF; static _ALWAYS_INLINE_ double sin(double p_x) { return ::sin(p_x); } static _ALWAYS_INLINE_ float sin(float p_x) { return ::sinf(p_x); } @@ -305,16 +306,6 @@ public: return b; } -#if defined(__GNUC__) - - static _ALWAYS_INLINE_ int64_t dtoll(double p_double) { return (int64_t)p_double; } ///@TODO OPTIMIZE - static _ALWAYS_INLINE_ int64_t dtoll(float p_float) { return (int64_t)p_float; } ///@TODO OPTIMIZE and rename -#else - - static _ALWAYS_INLINE_ int64_t dtoll(double p_double) { return (int64_t)p_double; } ///@TODO OPTIMIZE - static _ALWAYS_INLINE_ int64_t dtoll(float p_float) { return (int64_t)p_float; } ///@TODO OPTIMIZE and rename -#endif - static _ALWAYS_INLINE_ uint32_t halfbits_to_floatbits(uint16_t h) { uint16_t h_exp, h_sig; uint32_t f_sgn, f_exp, f_sig; diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp index fca54b1556..925a7b3f1e 100644 --- a/core/math/matrix3.cpp +++ b/core/math/matrix3.cpp @@ -299,14 +299,14 @@ Vector3 Basis::rotref_posscale_decomposition(Basis &rotref) const { ERR_FAIL_COND_V(determinant() == 0, Vector3()); Basis m = transposed() * (*this); - ERR_FAIL_COND_V(m.is_diagonal() == false, Vector3()); + ERR_FAIL_COND_V(!m.is_diagonal(), Vector3()); #endif Vector3 scale = get_scale(); Basis inv_scale = Basis().scaled(scale.inverse()); // this will also absorb the sign of scale rotref = (*this) * inv_scale; #ifdef MATH_CHECKS - ERR_FAIL_COND_V(rotref.is_orthogonal() == false, Vector3()); + ERR_FAIL_COND_V(!rotref.is_orthogonal(), Vector3()); #endif return scale.abs(); } @@ -430,7 +430,7 @@ Vector3 Basis::get_euler_xyz() const { Vector3 euler; #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_rotation() == false, euler); + ERR_FAIL_COND_V(!is_rotation(), euler); #endif real_t sy = elements[0][2]; if (sy < 1.0) { @@ -497,7 +497,7 @@ Vector3 Basis::get_euler_yxz() const { Vector3 euler; #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_rotation() == false, euler); + ERR_FAIL_COND_V(!is_rotation(), euler); #endif real_t m12 = elements[1][2]; @@ -556,7 +556,7 @@ bool Basis::is_equal_approx(const Basis &a, const Basis &b) const { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - if (Math::is_equal_approx(a.elements[i][j], b.elements[i][j]) == false) + if (!Math::is_equal_approx(a.elements[i][j], b.elements[i][j])) return false; } } @@ -600,7 +600,7 @@ Basis::operator String() const { Quat Basis::get_quat() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_rotation() == false, Quat()); + ERR_FAIL_COND_V(!is_rotation(), Quat()); #endif real_t trace = elements[0][0] + elements[1][1] + elements[2][2]; real_t temp[4]; @@ -697,7 +697,7 @@ void Basis::set_orthogonal_index(int p_index) { void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { #ifdef MATH_CHECKS - ERR_FAIL_COND(is_rotation() == false); + ERR_FAIL_COND(!is_rotation()); #endif real_t angle, x, y, z; // variables for result real_t epsilon = 0.01; // margin to allow for rounding errors @@ -785,7 +785,7 @@ void Basis::set_quat(const Quat &p_quat) { void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_phi) { // Rotation matrix from axis and angle, see https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_angle #ifdef MATH_CHECKS - ERR_FAIL_COND(p_axis.is_normalized() == false); + ERR_FAIL_COND(!p_axis.is_normalized()); #endif Vector3 axis_sq(p_axis.x * p_axis.x, p_axis.y * p_axis.y, p_axis.z * p_axis.z); @@ -837,8 +837,8 @@ void Basis::set_diagonal(const Vector3 p_diag) { Basis Basis::slerp(const Basis &target, const real_t &t) const { // TODO: implement this directly without using quaternions to make it more efficient #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_rotation() == false, Basis()); - ERR_FAIL_COND_V(target.is_rotation() == false, Basis()); + ERR_FAIL_COND_V(!is_rotation(), Basis()); + ERR_FAIL_COND_V(!target.is_rotation(), Basis()); #endif Quat from(*this); diff --git a/core/math/quat.cpp b/core/math/quat.cpp index d660ce4553..791e84f089 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -100,7 +100,7 @@ void Quat::set_euler_yxz(const Vector3 &p_euler) { // This implementation uses YXZ convention (Z is the first rotation). Vector3 Quat::get_euler_yxz() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, Vector3(0, 0, 0)); + ERR_FAIL_COND_V(!is_normalized(), Vector3(0, 0, 0)); #endif Basis m(*this); return m.get_euler_yxz(); @@ -140,15 +140,15 @@ bool Quat::is_normalized() const { Quat Quat::inverse() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, Quat()); + ERR_FAIL_COND_V(!is_normalized(), Quat()); #endif return Quat(-x, -y, -z, w); } Quat Quat::slerp(const Quat &q, const real_t &t) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, Quat()); - ERR_FAIL_COND_V(q.is_normalized() == false, Quat()); + ERR_FAIL_COND_V(!is_normalized(), Quat()); + ERR_FAIL_COND_V(!q.is_normalized(), Quat()); #endif Quat to1; real_t omega, cosom, sinom, scale0, scale1; @@ -194,8 +194,8 @@ Quat Quat::slerp(const Quat &q, const real_t &t) const { Quat Quat::slerpni(const Quat &q, const real_t &t) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, Quat()); - ERR_FAIL_COND_V(q.is_normalized() == false, Quat()); + ERR_FAIL_COND_V(!is_normalized(), Quat()); + ERR_FAIL_COND_V(!q.is_normalized(), Quat()); #endif const Quat &from = *this; @@ -216,8 +216,8 @@ Quat Quat::slerpni(const Quat &q, const real_t &t) const { Quat Quat::cubic_slerp(const Quat &q, const Quat &prep, const Quat &postq, const real_t &t) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, Quat()); - ERR_FAIL_COND_V(q.is_normalized() == false, Quat()); + ERR_FAIL_COND_V(!is_normalized(), Quat()); + ERR_FAIL_COND_V(!q.is_normalized(), Quat()); #endif //the only way to do slerp :| real_t t2 = (1.0 - t) * t * 2; @@ -233,7 +233,7 @@ Quat::operator String() const { void Quat::set_axis_angle(const Vector3 &axis, const real_t &angle) { #ifdef MATH_CHECKS - ERR_FAIL_COND(axis.is_normalized() == false); + ERR_FAIL_COND(!axis.is_normalized()); #endif real_t d = axis.length(); if (d == 0) diff --git a/core/math/quat.h b/core/math/quat.h index 10d3846c87..c4f9b3a732 100644 --- a/core/math/quat.h +++ b/core/math/quat.h @@ -87,7 +87,7 @@ public: _FORCE_INLINE_ Vector3 xform(const Vector3 &v) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, v); + ERR_FAIL_COND_V(!is_normalized(), v); #endif Vector3 u(x, y, z); Vector3 uv = u.cross(v); diff --git a/core/math/random_number_generator.cpp b/core/math/random_number_generator.cpp new file mode 100644 index 0000000000..e4ec0dac99 --- /dev/null +++ b/core/math/random_number_generator.cpp @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* random_number_generator.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "random_number_generator.h" + +RandomNumberGenerator::RandomNumberGenerator() : + randbase() {} + +void RandomNumberGenerator::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_seed", "seed"), &RandomNumberGenerator::set_seed); + ClassDB::bind_method(D_METHOD("get_seed"), &RandomNumberGenerator::get_seed); + ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed"); + + ClassDB::bind_method(D_METHOD("randi"), &RandomNumberGenerator::randi); + ClassDB::bind_method(D_METHOD("randf"), &RandomNumberGenerator::randf); + ClassDB::bind_method(D_METHOD("rand_range", "from", "to"), &RandomNumberGenerator::rand_range); + ClassDB::bind_method(D_METHOD("randomize"), &RandomNumberGenerator::randomize); +} diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h new file mode 100644 index 0000000000..557863fdbd --- /dev/null +++ b/core/math/random_number_generator.h @@ -0,0 +1,61 @@ +/*************************************************************************/ +/* random_number_generator.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 RANDOM_NUMBER_GENERATOR_H +#define RANDOM_NUMBER_GENERATOR_H + +#include "core/math/random_pcg.h" +#include "core/reference.h" + +class RandomNumberGenerator : public Reference { + GDCLASS(RandomNumberGenerator, Reference); + + RandomPCG randbase; + +protected: + static void _bind_methods(); + +public: + _FORCE_INLINE_ void set_seed(uint64_t seed) { randbase.seed(seed); } + + _FORCE_INLINE_ uint64_t get_seed() { return randbase.get_seed(); } + + _FORCE_INLINE_ void randomize() { return randbase.randomize(); } + + _FORCE_INLINE_ uint32_t randi() { return randbase.rand(); } + + _FORCE_INLINE_ real_t randf() { return randbase.randf(); } + + _FORCE_INLINE_ real_t rand_range(real_t from, real_t to) { return randbase.random(from, to); } + + RandomNumberGenerator(); +}; + +#endif // RANDOM_NUMBER_GENERATOR_H diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp new file mode 100644 index 0000000000..16899f79da --- /dev/null +++ b/core/math/random_pcg.cpp @@ -0,0 +1,55 @@ +/*************************************************************************/ +/* random_pcg.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "random_pcg.h" + +#include "core/os/os.h" + +RandomPCG::RandomPCG(uint64_t seed, uint64_t inc) : + pcg() { + pcg.state = seed; + pcg.inc = inc; +} + +void RandomPCG::randomize() { + seed(OS::get_singleton()->get_ticks_usec() * pcg.state + PCG_DEFAULT_INC_64); +} + +double RandomPCG::random(double from, double to) { + unsigned int r = rand(); + double ret = (double)r / (double)RANDOM_MAX; + return (ret) * (to - from) + from; +} + +float RandomPCG::random(float from, float to) { + unsigned int r = rand(); + float ret = (float)r / (float)RANDOM_MAX; + return (ret) * (to - from) + from; +} diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h new file mode 100644 index 0000000000..4a43c36ede --- /dev/null +++ b/core/math/random_pcg.h @@ -0,0 +1,61 @@ +/*************************************************************************/ +/* random_pcg.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 RANDOM_PCG_H +#define RANDOM_PCG_H + +#include "core/math/math_defs.h" + +#include "thirdparty/misc/pcg.h" + +class RandomPCG { + pcg32_random_t pcg; + +public: + static const uint64_t DEFAULT_SEED = 12047754176567800795ULL; + static const uint64_t DEFAULT_INC = PCG_DEFAULT_INC_64; + static const uint64_t RANDOM_MAX = 4294967295; + + RandomPCG(uint64_t seed = DEFAULT_SEED, uint64_t inc = PCG_DEFAULT_INC_64); + + _FORCE_INLINE_ void seed(uint64_t seed) { pcg.state = seed; } + _FORCE_INLINE_ uint64_t get_seed() { return pcg.state; } + + void randomize(); + _FORCE_INLINE_ uint32_t rand() { return pcg32_random_r(&pcg); } + _FORCE_INLINE_ double randf() { return (double)rand() / (double)RANDOM_MAX; } + _FORCE_INLINE_ float randd() { return (float)rand() / (float)RANDOM_MAX; } + + double random(double from, double to); + float random(float from, float to); + real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); } +}; + +#endif // RANDOM_PCG_H diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index 84c9f0fca6..7c6f056f09 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -167,7 +167,7 @@ Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, c // slide returns the component of the vector along the given plane, specified by its normal vector. Vector2 Vector2::slide(const Vector2 &p_normal) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(p_normal.is_normalized() == false, Vector2()); + ERR_FAIL_COND_V(!p_normal.is_normalized(), Vector2()); #endif return *this - p_normal * this->dot(p_normal); } @@ -178,7 +178,7 @@ Vector2 Vector2::bounce(const Vector2 &p_normal) const { Vector2 Vector2::reflect(const Vector2 &p_normal) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(p_normal.is_normalized() == false, Vector2()); + ERR_FAIL_COND_V(!p_normal.is_normalized(), Vector2()); #endif return 2.0 * p_normal * this->dot(p_normal) - *this; } diff --git a/core/math/vector2.h b/core/math/vector2.h index df49484aaf..e5e555597d 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -230,7 +230,7 @@ Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const { Vector2 Vector2::slerp(const Vector2 &p_b, real_t p_t) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, Vector2()); + ERR_FAIL_COND_V(!is_normalized(), Vector2()); #endif real_t theta = angle_to(p_b); return rotated(theta * p_t); diff --git a/core/math/vector3.h b/core/math/vector3.h index 5302832eeb..16feba6a0c 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -218,7 +218,7 @@ Vector3 Vector3::linear_interpolate(const Vector3 &p_b, real_t p_t) const { Vector3 Vector3::slerp(const Vector3 &p_b, real_t p_t) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(is_normalized() == false, Vector3()); + ERR_FAIL_COND_V(!is_normalized(), Vector3()); #endif real_t theta = angle_to(p_b); @@ -430,7 +430,7 @@ void Vector3::zero() { // slide returns the component of the vector along the given plane, specified by its normal vector. Vector3 Vector3::slide(const Vector3 &p_normal) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(p_normal.is_normalized() == false, Vector3()); + ERR_FAIL_COND_V(!p_normal.is_normalized(), Vector3()); #endif return *this - p_normal * this->dot(p_normal); } @@ -441,7 +441,7 @@ Vector3 Vector3::bounce(const Vector3 &p_normal) const { Vector3 Vector3::reflect(const Vector3 &p_normal) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V(p_normal.is_normalized() == false, Vector3()); + ERR_FAIL_COND_V(!p_normal.is_normalized(), Vector3()); #endif return 2.0 * p_normal * this->dot(p_normal) - *this; } diff --git a/core/message_queue.cpp b/core/message_queue.cpp index 7f788c90a7..2952593798 100644 --- a/core/message_queue.cpp +++ b/core/message_queue.cpp @@ -209,9 +209,9 @@ void MessageQueue::statistics() { } break; } + } else { //object was deleted print_line("Object was deleted while awaiting a callback"); - } else { null_count++; } @@ -338,6 +338,7 @@ MessageQueue::MessageQueue() { buffer_end = 0; buffer_max_used = 0; buffer_size = GLOBAL_DEF_RST("memory/limits/message_queue/max_size_kb", DEFAULT_QUEUE_SIZE_KB); + ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/message_queue/max_size_kb", PropertyInfo(Variant::INT, "memory/limits/message_queue/max_size_kb", PROPERTY_HINT_RANGE, "0,2048,1,or_greater")); buffer_size *= 1024; buffer = memnew_arr(uint8_t, buffer_size); } diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h index 3705762d6c..9840442519 100644 --- a/core/oa_hash_map.h +++ b/core/oa_hash_map.h @@ -125,7 +125,7 @@ private: while (42) { if (hashes[pos] == EMPTY_HASH) { - _construct(pos, hash, p_key, p_value); + _construct(pos, hash, key, value); return; } @@ -136,7 +136,7 @@ private: if (hashes[pos] & DELETED_HASH_BIT) { // we found a place where we can fit in! - _construct(pos, hash, p_key, p_value); + _construct(pos, hash, key, value); return; } diff --git a/core/object.cpp b/core/object.cpp index 946040ba34..3a14c7c0b5 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -440,16 +440,6 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid if (r_valid) *r_valid = true; return; -#ifdef TOOLS_ENABLED - } else if (p_name == CoreStringNames::get_singleton()->_sections_unfolded) { - Array arr = p_value; - for (int i = 0; i < arr.size(); i++) { - editor_section_folding.insert(arr[i]); - } - if (r_valid) - *r_valid = true; - return; -#endif } //something inside the object... :| @@ -520,16 +510,7 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { if (r_valid) *r_valid = true; return ret; -#ifdef TOOLS_ENABLED - } else if (p_name == CoreStringNames::get_singleton()->_sections_unfolded) { - Array array; - for (Set<String>::Element *E = editor_section_folding.front(); E; E = E->next()) { - array.push_back(E->get()); - } - if (r_valid) - *r_valid = true; - return array; -#endif + } else { //something inside the object... :| bool success = _getv(p_name, ret); @@ -655,15 +636,11 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons #ifdef TOOLS_ENABLED p_list->push_back(PropertyInfo(Variant::NIL, "Script", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP)); #endif - p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NONZERO)); + p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT)); } -#ifdef TOOLS_ENABLED - if (editor_section_folding.size()) { - p_list->push_back(PropertyInfo(Variant::ARRAY, CoreStringNames::get_singleton()->_sections_unfolded, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + if (!metadata.empty()) { + p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); } -#endif - if (!metadata.empty()) - p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_STORE_IF_NONZERO)); if (script_instance && !p_reversed) { p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); script_instance->get_property_list(p_list); @@ -1466,8 +1443,20 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str if (!s) { bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal); //check in script - if (!signal_is_valid && !script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)) - signal_is_valid = true; + if (!signal_is_valid && !script.is_null()) { + + if (Ref<Script>(script)->has_script_signal(p_signal)) { + signal_is_valid = true; + } +#ifdef TOOLS_ENABLED + else { + //allow connecting signals anyway if script is invalid, see issue #17070 + if (!Ref<Script>(script)->is_valid()) { + signal_is_valid = true; + } + } +#endif + } if (!signal_is_valid) { ERR_EXPLAIN("In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to method '" + p_to_object->get_class() + "." + p_to_method + "'"); @@ -1738,6 +1727,8 @@ void Object::_bind_methods() { ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_deferred", &Object::_call_deferred_bind, mi); } + ClassDB::bind_method(D_METHOD("set_deferred", "property", "value"), &Object::set_deferred); + ClassDB::bind_method(D_METHOD("callv", "method", "arg_array"), &Object::callv); ClassDB::bind_method(D_METHOD("has_method", "method"), &Object::has_method); @@ -1794,6 +1785,10 @@ void Object::call_deferred(const StringName &p_method, VARIANT_ARG_DECLARE) { MessageQueue::get_singleton()->push_call(this, p_method, VARIANT_ARG_PASS); } +void Object::set_deferred(const StringName &p_property, const Variant &p_value) { + MessageQueue::get_singleton()->push_set(this, p_property, p_value); +} + void Object::set_block_signals(bool p_block) { _block_signals = p_block; @@ -1958,30 +1953,30 @@ Object::~Object() { memdelete(script_instance); script_instance = NULL; - List<Connection> sconnections; const StringName *S = NULL; - while ((S = signal_map.next(S))) { + while ((S = signal_map.next(NULL))) { Signal *s = &signal_map[*S]; - ERR_EXPLAIN("Attempt to delete an object in the middle of a signal emission from it"); - ERR_CONTINUE(s->lock > 0); - - for (int i = 0; i < s->slot_map.size(); i++) { - - sconnections.push_back(s->slot_map.getv(i).conn); + if (s->lock) { + ERR_EXPLAIN("Attempt to delete an object in the middle of a signal emission from it"); + ERR_CONTINUE(s->lock > 0); } - } - for (List<Connection>::Element *E = sconnections.front(); E; E = E->next()) { + //brute force disconnect for performance + int slot_count = s->slot_map.size(); + const VMap<Signal::Target, Signal::Slot>::Pair *slot_list = s->slot_map.get_array(); - Connection &c = E->get(); - ERR_CONTINUE(c.source != this); //bug? + for (int i = 0; i < slot_count; i++) { + + slot_list[i].value.conn.target->connections.erase(slot_list[i].value.cE); + } - this->_disconnect(c.signal, c.target, c.method, true); + signal_map.erase(*S); } + //signals from nodes that connect to this node while (connections.size()) { Connection c = connections.front()->get(); diff --git a/core/object.h b/core/object.h index b23160c1df..88a98dacbe 100644 --- a/core/object.h +++ b/core/object.h @@ -103,8 +103,9 @@ enum PropertyUsageFlags { PROPERTY_USAGE_INTERNATIONALIZED = 64, //hint for internationalized strings PROPERTY_USAGE_GROUP = 128, //used for grouping props in the editor PROPERTY_USAGE_CATEGORY = 256, - PROPERTY_USAGE_STORE_IF_NONZERO = 512, //only store if nonzero - PROPERTY_USAGE_STORE_IF_NONONE = 1024, //only store if false + //those below are deprecated thanks to ClassDB's now class value cache + //PROPERTY_USAGE_STORE_IF_NONZERO = 512, //only store if nonzero + //PROPERTY_USAGE_STORE_IF_NONONE = 1024, //only store if false PROPERTY_USAGE_NO_INSTANCE_STATE = 2048, PROPERTY_USAGE_RESTART_IF_CHANGED = 4096, PROPERTY_USAGE_SCRIPT_VARIABLE = 8192, @@ -126,10 +127,6 @@ enum PropertyUsageFlags { #define ADD_SIGNAL(m_signal) ClassDB::add_signal(get_class_static(), m_signal) #define ADD_PROPERTY(m_property, m_setter, m_getter) ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter)) #define ADD_PROPERTYI(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), m_property, _scs_create(m_setter), _scs_create(m_getter), m_index) -#define ADD_PROPERTYNZ(m_property, m_setter, m_getter) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONZERO), _scs_create(m_setter), _scs_create(m_getter)) -#define ADD_PROPERTYINZ(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONZERO), _scs_create(m_setter), _scs_create(m_getter), m_index) -#define ADD_PROPERTYNO(m_property, m_setter, m_getter) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), _scs_create(m_setter), _scs_create(m_getter)) -#define ADD_PROPERTYINO(m_property, m_setter, m_getter, m_index) ClassDB::add_property(get_class_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), _scs_create(m_setter), _scs_create(m_getter), m_index) #define ADD_GROUP(m_name, m_prefix) ClassDB::add_property_group(get_class_static(), m_name, m_prefix) struct PropertyInfo { @@ -701,6 +698,7 @@ public: bool is_connected(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method) const; void call_deferred(const StringName &p_method, VARIANT_ARG_LIST); + void set_deferred(const StringName &p_property, const Variant &p_value); void set_block_signals(bool p_block); bool is_blocking_signals() const; @@ -723,6 +721,9 @@ public: #ifdef TOOLS_ENABLED void editor_set_section_unfold(const String &p_section, bool p_unfolded); bool editor_is_section_unfolded(const String &p_section); + const Set<String> &editor_get_section_folding() const { return editor_section_folding; } + void editor_clear_section_folding() { editor_section_folding.clear(); } + #endif //used by script languages to store binding data diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index e09e5e16ad..679b1c9054 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -346,9 +346,9 @@ String FileAccess::get_line() const { return String::utf8(line.get_data()); } -Vector<String> FileAccess::get_csv_line(String delim) const { +Vector<String> FileAccess::get_csv_line(const String &p_delim) const { - ERR_FAIL_COND_V(delim.length() != 1, Vector<String>()); + ERR_FAIL_COND_V(p_delim.length() != 1, Vector<String>()); String l; int qc = 0; @@ -376,7 +376,7 @@ Vector<String> FileAccess::get_csv_line(String delim) const { CharType c = l[i]; CharType s[2] = { 0, 0 }; - if (!in_quote && c == delim[0]) { + if (!in_quote && c == p_delim[0]) { strings.push_back(current); current = String(); } else if (c == '"') { @@ -525,6 +525,28 @@ void FileAccess::store_line(const String &p_line) { store_8('\n'); } +void FileAccess::store_csv_line(const Vector<String> &p_values, const String &p_delim) { + + ERR_FAIL_COND(p_delim.length() != 1); + + String line = ""; + int size = p_values.size(); + for (int i = 0; i < size; ++i) { + String value = p_values[i]; + + if (value.find("\"") != -1 || value.find(p_delim) != -1 || value.find("\n") != -1) { + value = "\"" + value.replace("\"", "\"\"") + "\""; + } + if (i < size - 1) { + value += p_delim; + } + + line += value; + } + + store_line(line); +} + void FileAccess::store_buffer(const uint8_t *p_src, int p_length) { for (int i = 0; i < p_length; i++) diff --git a/core/os/file_access.h b/core/os/file_access.h index b7d93e9f5d..f1f3005dd9 100644 --- a/core/os/file_access.h +++ b/core/os/file_access.h @@ -112,7 +112,7 @@ public: virtual int get_buffer(uint8_t *p_dst, int p_length) const; ///< get an array of bytes virtual String get_line() const; virtual String get_token() const; - virtual Vector<String> get_csv_line(String delim = ",") const; + virtual Vector<String> get_csv_line(const String &p_delim = ",") const; /**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac) * It's not about the current CPU type but file formats. @@ -136,6 +136,7 @@ public: virtual void store_string(const String &p_string); virtual void store_line(const String &p_line); + virtual 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(); diff --git a/core/os/input.cpp b/core/os/input.cpp index 6830df7e81..3b895b16b4 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -42,7 +42,7 @@ Input *Input::get_singleton() { } void Input::set_mouse_mode(MouseMode p_mode) { - ERR_FAIL_INDEX(p_mode, 4); + ERR_FAIL_INDEX((int)p_mode, 4); OS::get_singleton()->set_mouse_mode((OS::MouseMode)p_mode); } @@ -86,7 +86,7 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode); ClassDB::bind_method(D_METHOD("get_mouse_mode"), &Input::get_mouse_mode); ClassDB::bind_method(D_METHOD("warp_mouse_position", "to"), &Input::warp_mouse_position); - ClassDB::bind_method(D_METHOD("action_press", "action"), &Input::action_press); + ClassDB::bind_method(D_METHOD("action_press", "action", "strength"), &Input::action_press, DEFVAL(1.f)); ClassDB::bind_method(D_METHOD("action_release", "action"), &Input::action_release); ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW)); ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2())); diff --git a/core/os/input.h b/core/os/input.h index db523d6789..dc2c213db2 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -113,7 +113,7 @@ public: virtual Vector3 get_magnetometer() const = 0; virtual Vector3 get_gyroscope() const = 0; - virtual void action_press(const StringName &p_action) = 0; + virtual void action_press(const StringName &p_action, float p_strength = 1.f) = 0; virtual void action_release(const StringName &p_action) = 0; void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const; diff --git a/core/os/memory.cpp b/core/os/memory.cpp index 041371a6e2..f25e40ef78 100644 --- a/core/os/memory.cpp +++ b/core/os/memory.cpp @@ -172,9 +172,9 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) { if (prepad) { mem -= PAD_ALIGN; - uint64_t *s = (uint64_t *)mem; #ifdef DEBUG_ENABLED + uint64_t *s = (uint64_t *)mem; atomic_sub(&mem_usage, *s); #endif diff --git a/core/os/os.h b/core/os/os.h index 7786ffb26e..53a5ebde01 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -480,6 +480,7 @@ public: enum EngineContext { CONTEXT_EDITOR, CONTEXT_PROJECTMAN, + CONTEXT_ENGINE, }; virtual void set_context(int p_context); diff --git a/core/os/rw_lock.h b/core/os/rw_lock.h index 8d1029723b..4333d9a016 100644 --- a/core/os/rw_lock.h +++ b/core/os/rw_lock.h @@ -57,9 +57,7 @@ class RWLockRead { public: RWLockRead(const RWLock *p_lock) { - if (p_lock) { - lock = const_cast<RWLock *>(p_lock); - } + lock = const_cast<RWLock *>(p_lock); if (lock) lock->read_lock(); } ~RWLockRead() { diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 99a23bbee1..407bb78375 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -288,9 +288,28 @@ void ProjectSettings::_convert_to_last_version() { } } +/* + * This method is responsible for loading a project.godot file and/or data file + * using the following merit order: + * - If using NetworkClient, try to lookup project file or fail. + * - If --main-pack was passed by the user (`p_main_pack`), load it or fail. + * - Search for .pck file matching binary name. There are two possibilities: + * o exec_path.get_basename() + '.pck' (e.g. 'win_game.exe' -> 'win_game.pck') + * o exec_path + '.pck' (e.g. 'linux_game' -> 'linux_game.pck') + * For each tentative, if the file exists, load it or fail. + * - On relevant platforms (Android/iOS), lookup project file in OS resource path. + * If found, load it or fail. + * - Lookup project file in passed `p_path` (--path passed by the user), i.e. we + * are running from source code. + * If not found and `p_upwards` is true (--upwards passed by the user), look for + * project files in parent folders up to the system root (used to run a game + * from command line while in a subfolder). + * If a project file is found, load it or fail. + * If nothing was found, error out. + */ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards) { - //If looking for files in network, just use network! + // If looking for files in a network client, use it directly if (FileAccessNetworkClient::get_singleton()) { @@ -302,9 +321,7 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo return err; } - String exec_path = OS::get_singleton()->get_executable_path(); - - //Attempt with a passed main pack first + // Attempt with a user-defined main pack first if (p_main_pack != "") { @@ -320,25 +337,39 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo return err; } - //Attempt with execname.pck + // Attempt with exec_name.pck + // (This is the usual case when distributing a Godot game.) + + // Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle) + // or the exec path's basename + '.pck' (Windows). + // We need to test both possibilities as extensions for Linux binaries are optional + // (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck'). + + String exec_path = OS::get_singleton()->get_executable_path(); + if (exec_path != "") { bool found = false; - // get our filename without our path (note, using exec_path.get_file before get_basename anymore because not all file systems have dots in their file names!) - String filebase_name = exec_path.get_file().get_basename(); + String exec_dir = exec_path.get_base_dir(); + String exec_filename = exec_path.get_file(); + String exec_basename = exec_filename.get_basename(); + + // Try to load data pack at the location of the executable + // As mentioned above, we have two potential names to attempt - // try to open at the location of executable - String datapack_name = exec_path.get_base_dir().plus_file(filebase_name) + ".pck"; - if (_load_resource_pack(datapack_name)) { + if (_load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) || + _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck"))) { found = true; } else { - datapack_name = filebase_name + ".pck"; - if (_load_resource_pack(datapack_name)) { + // If we couldn't find them next to the executable, we attempt + // the current working directory. Same story, two tests. + if (_load_resource_pack(exec_basename + ".pck") || + _load_resource_pack(exec_filename + ".pck")) { found = true; } } - // if we opened our package, try and load our project... + // If we opened our package, try and load our project if (found) { Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); if (err == OK) { @@ -350,17 +381,15 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo } } - //Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this) - if (OS::get_singleton()->get_resource_dir() != "") { - //OS will call Globals->get_resource_path which will be empty if not overridden! - //if the OS would rather use somewhere else, then it will not be empty. + // Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this) + if (OS::get_singleton()->get_resource_dir() != "") { + // OS will call ProjectSettings->get_resource_path which will be empty if not overridden! + // If the OS would rather use a specific location, then it will not be empty. resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/"); - if (resource_path.length() && resource_path[resource_path.length() - 1] == '/') + if (resource_path != "" && resource_path[resource_path.length() - 1] == '/') { resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end - - // data.pck and data.zip are deprecated and no longer supported, apologies. - // make sure this is loaded from the resource path + } Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); if (err == OK) { @@ -371,21 +400,19 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo return err; } - //Nothing was found, try to find a project.godot somewhere! + // Nothing was found, try to find a project file in provided path (`p_path`) + // or, if requested (`p_upwards`) in parent directories. DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); ERR_FAIL_COND_V(!d, ERR_CANT_CREATE); - d->change_dir(p_path); - String candidate = d->get_current_dir(); String current_dir = d->get_current_dir(); - + String candidate = current_dir; bool found = false; Error err; while (true) { - err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary")); if (err == OK) { // Optional, we don't mind if it fails @@ -396,10 +423,10 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo } if (p_upwards) { - // Try to load settings ascending through dirs shape! + // Try to load settings ascending through parent directories d->change_dir(".."); if (d->get_current_dir() == current_dir) - break; //not doing anything useful + break; // not doing anything useful current_dir = d->get_current_dir(); } else { break; @@ -416,6 +443,8 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo if (resource_path.length() && resource_path[resource_path.length() - 1] == '/') resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end + // If we're loading a project.godot from source code, we can operate some + // ProjectSettings conversions if need be. _convert_to_last_version(); return OK; @@ -1133,6 +1162,7 @@ ProjectSettings::ProjectSettings() { custom_prop_info["rendering/quality/intended_usage/framebuffer_allocation"] = PropertyInfo(Variant::INT, "rendering/quality/intended_usage/framebuffer_allocation", PROPERTY_HINT_ENUM, "2D,2D Without Sampling,3D,3D Without Effects"); GLOBAL_DEF("debug/settings/profiler/max_functions", 16384); + custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1"); //assigning here, because using GLOBAL_GET on every block for compressing can be slow Compression::zstd_long_distance_matching = GLOBAL_DEF("compression/formats/zstd/long_distance_matching", false); diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index b0023b4c26..6b776cb0b1 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -55,6 +55,7 @@ #include "core/math/a_star.h" #include "core/math/expression.h" #include "core/math/geometry.h" +#include "core/math/random_number_generator.h" #include "core/math/triangle_mesh.h" #include "core/os/input.h" #include "core/os/main_loop.h" @@ -180,6 +181,7 @@ void register_core_types() { ClassDB::register_virtual_class<PackedDataContainerRef>(); ClassDB::register_class<AStar>(); ClassDB::register_class<EncodedObjectAsID>(); + ClassDB::register_class<RandomNumberGenerator>(); ClassDB::register_class<JSONParseResult>(); @@ -199,6 +201,7 @@ void register_core_types() { void register_core_settings() { //since in register core types, globals may not e present GLOBAL_DEF_RST("network/limits/packet_peer_stream/max_buffer_po2", (16)); + ProjectSettings::get_singleton()->set_custom_property_info("network/limits/packet_peer_stream/max_buffer_po2", PropertyInfo(Variant::INT, "network/limits/packet_peer_stream/max_buffer_po2", PROPERTY_HINT_RANGE, "0,64,1,or_greater")); } void register_core_singletons() { diff --git a/core/resource.cpp b/core/resource.cpp index 4dcd338e94..a76e16232e 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -379,9 +379,9 @@ void Resource::_bind_methods() { ClassDB::bind_method(D_METHOD("duplicate", "subresources"), &Resource::duplicate, DEFVAL(false)); ADD_SIGNAL(MethodInfo("changed")); ADD_GROUP("Resource", "resource_"); - ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "resource_local_to_scene"), "set_local_to_scene", "is_local_to_scene"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resource_local_to_scene"), "set_local_to_scene", "is_local_to_scene"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_path", "get_path"); - ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "resource_name"), "set_name", "get_name"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "resource_name"), "set_name", "get_name"); BIND_VMETHOD(MethodInfo("_setup_local_to_scene")); } diff --git a/core/rid.h b/core/rid.h index fbb3e443fc..81d5b45d21 100644 --- a/core/rid.h +++ b/core/rid.h @@ -118,7 +118,6 @@ protected: p_rid._data->_owner = NULL; } -# #endif public: diff --git a/core/ring_buffer.h b/core/ring_buffer.h index 2516880064..54486f8cad 100644 --- a/core/ring_buffer.h +++ b/core/ring_buffer.h @@ -135,6 +135,12 @@ public: return p_n; }; + inline int decrease_write(int p_n) { + p_n = MIN(p_n, data_left()); + inc(write_pos, size_mask + 1 - p_n); + return p_n; + } + Error write(const T &p_v) { ERR_FAIL_COND_V(space_left() < 1, FAILED); data.write[inc(write_pos, 1)] = p_v; diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 388e3b77a3..a03ddd0983 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -108,7 +108,7 @@ void ScriptDebuggerRemote::_put_variable(const String &p_name, const Variant &p_ } int len = 0; - Error err = encode_variant(var, NULL, len); + Error err = encode_variant(var, NULL, len, true); if (err != OK) ERR_PRINT("Failed to encode variant"); @@ -578,8 +578,14 @@ void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { for (ScriptConstantsMap::Element *sc = constants.front(); sc; sc = sc->next()) { for (Map<StringName, Variant>::Element *E = sc->get().front(); E; E = E->next()) { String script_path = sc->key() == si->get_script().ptr() ? "" : sc->key()->get_path().get_file() + "/"; - PropertyInfo pi(E->value().get_type(), "Constants/" + script_path + E->key()); - properties.push_back(PropertyDesc(pi, E->value())); + if (E->value().get_type() == Variant::OBJECT) { + Variant id = ((Object *)E->value())->get_instance_id(); + PropertyInfo pi(id.get_type(), "Constants/" + E->key(), PROPERTY_HINT_OBJECT_ID, "Object"); + properties.push_back(PropertyDesc(pi, id)); + } else { + PropertyInfo pi(E->value().get_type(), "Constants/" + script_path + E->key()); + properties.push_back(PropertyDesc(pi, E->value())); + } } } } @@ -592,8 +598,14 @@ void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { Map<StringName, Variant> constants; s->get_constants(&constants); for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { - PropertyInfo pi(E->value().get_type(), String("Constants/") + E->key()); - properties.push_front(PropertyDesc(pi, E->value())); + if (E->value().get_type() == Variant::OBJECT) { + Variant id = ((Object *)E->value())->get_instance_id(); + PropertyInfo pi(id.get_type(), "Constants/" + E->key(), PROPERTY_HINT_OBJECT_ID, "Object"); + properties.push_front(PropertyDesc(pi, E->value())); + } else { + PropertyInfo pi(E->value().get_type(), String("Constants/") + E->key()); + properties.push_front(PropertyDesc(pi, E->value())); + } } } } @@ -634,10 +646,9 @@ void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { prop.push_back(pi.hint); prop.push_back(pi.hint_string); prop.push_back(pi.usage); + if (!res.is_null()) { - var = String("PATH") + res->get_path(); - } else if (var.get_type() == Variant::STRING) { - var = String("DATA") + var; + var = res->get_path(); } prop.push_back(var); @@ -1089,7 +1100,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() : eh.userdata = this; add_error_handler(&eh); - profile_info.resize(CLAMP(int(ProjectSettings::get_singleton()->get("debug/settings/profiler/max_functions")), 128, 65535)); + profile_info.resize(GLOBAL_GET("debug/settings/profiler/max_functions")); profile_info_ptrs.resize(profile_info.size()); } diff --git a/core/script_language.cpp b/core/script_language.cpp index 5b65da9ef1..496521486e 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -563,7 +563,8 @@ Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_nam PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) : owner(p_owner), language(p_language), - script(p_script) { + script(p_script), + build_failed(false) { } PlaceHolderScriptInstance::~PlaceHolderScriptInstance() { diff --git a/core/script_language.h b/core/script_language.h index bcd9c2c5ea..654d1d4265 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -128,6 +128,7 @@ public: virtual MethodInfo get_method_info(const StringName &p_method) const = 0; virtual bool is_tool() const = 0; + virtual bool is_valid() const = 0; virtual ScriptLanguage *get_language() const = 0; diff --git a/core/set.h b/core/set.h index 744019d5b4..59aa54128e 100644 --- a/core/set.h +++ b/core/set.h @@ -595,6 +595,7 @@ public: return e; } + inline bool empty() const { return _data.size_cache == 0; } inline int size() const { return _data.size_cache; } int calculate_depth() const { diff --git a/core/typedefs.h b/core/typedefs.h index 2b26bf08f7..5c15da9c2d 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -44,6 +44,7 @@ #define _MKSTR(m_x) _STR(m_x) #endif +//should always inline no matter what #ifndef _ALWAYS_INLINE_ #if defined(__GNUC__) && (__GNUC__ >= 4) @@ -58,10 +59,17 @@ #endif +//should always inline, except in some cases because it makes debugging harder #ifndef _FORCE_INLINE_ + +#ifdef DISABLE_FORCED_INLINE +#define _FORCE_INLINE_ inline +#else #define _FORCE_INLINE_ _ALWAYS_INLINE_ #endif +#endif + //custom, gcc-safe offsetof, because gcc complains a lot. template <class T> T *_nullptr() { diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 7d67076df5..3d41c374ea 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -325,7 +325,7 @@ bool UndoRedo::undo() { return true; } -void UndoRedo::clear_history() { +void UndoRedo::clear_history(bool p_increase_version) { ERR_FAIL_COND(action_level > 0); _discard_redo(); @@ -333,7 +333,8 @@ void UndoRedo::clear_history() { while (actions.size()) _pop_history_tail(); - //version++; + if (p_increase_version) + version++; } String UndoRedo::get_current_action_name() const { @@ -493,7 +494,7 @@ void UndoRedo::_bind_methods() { 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); ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &UndoRedo::add_undo_reference); - ClassDB::bind_method(D_METHOD("clear_history"), &UndoRedo::clear_history); + ClassDB::bind_method(D_METHOD("clear_history", "increase_version"), &UndoRedo::clear_history, DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_current_action_name"), &UndoRedo::get_current_action_name); ClassDB::bind_method(D_METHOD("get_version"), &UndoRedo::get_version); ClassDB::bind_method(D_METHOD("redo"), &UndoRedo::redo); diff --git a/core/undo_redo.h b/core/undo_redo.h index 22dcd60472..f09fca9a78 100644 --- a/core/undo_redo.h +++ b/core/undo_redo.h @@ -112,7 +112,7 @@ public: bool redo(); bool undo(); String get_current_action_name() const; - void clear_history(); + void clear_history(bool p_increase_version = true); uint64_t get_version() const; diff --git a/core/ustring.cpp b/core/ustring.cpp index e46896ca85..3f017fa985 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -49,7 +49,7 @@ #endif #if defined(MINGW_ENABLED) || defined(_MSC_VER) -#define snprintf _snprintf +#define snprintf _snprintf_s #endif #define MAX_DIGITS 6 @@ -586,6 +586,8 @@ String String::camelcase_to_underscore(bool lowercase) const { bool is_upper = cstr[i] >= A && cstr[i] <= Z; bool is_number = cstr[i] >= '0' && cstr[i] <= '9'; bool are_next_2_lower = false; + bool is_next_lower = false; + bool is_next_number = false; bool was_precedent_upper = cstr[i - 1] >= A && cstr[i - 1] <= Z; bool was_precedent_number = cstr[i - 1] >= '0' && cstr[i - 1] <= '9'; @@ -593,7 +595,18 @@ String String::camelcase_to_underscore(bool lowercase) const { are_next_2_lower = cstr[i + 1] >= a && cstr[i + 1] <= z && cstr[i + 2] >= a && cstr[i + 2] <= z; } - bool should_split = ((is_upper && !was_precedent_upper && !was_precedent_number) || (was_precedent_upper && is_upper && are_next_2_lower) || (is_number && !was_precedent_number)); + if (i + 1 < this->size()) { + is_next_lower = cstr[i + 1] >= a && cstr[i + 1] <= z; + is_next_number = cstr[i + 1] >= '0' && cstr[i + 1] <= '9'; + } + + const bool a = is_upper && !was_precedent_upper && !was_precedent_number; + const bool b = was_precedent_upper && is_upper && are_next_2_lower; + const bool c = is_number && !was_precedent_number; + const bool can_break_number_letter = is_number && !was_precedent_number && is_next_lower; + const bool can_break_letter_number = !is_number && was_precedent_number && (is_next_lower || is_next_number); + + bool should_split = a || b || c || can_break_number_letter || can_break_letter_number; if (should_split) { new_string += this->substr(start_index, i - start_index) + "_"; start_index = i; @@ -1828,8 +1841,8 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point int sign, expSign = false; double fraction, dblExp; const double *d; - register const C *p; - register int c; + const C *p; + int c; int exp = 0; /* Exponent read from "EX" field. */ int fracExp = 0; /* Exponent that derives from the fractional * part. Under normal circumstances, it is @@ -2761,16 +2774,13 @@ String String::format(const Variant &values, String placeholder) const { if (value_arr.size() == 2) { Variant v_key = value_arr[0]; - String key; - - key = v_key.get_construct_string(); + String key = v_key; if (key.left(1) == "\"" && key.right(key.length() - 1) == "\"") { key = key.substr(1, key.length() - 2); } Variant v_val = value_arr[1]; - String val; - val = v_val.get_construct_string(); + String val = v_val; if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") { val = val.substr(1, val.length() - 2); @@ -2782,8 +2792,7 @@ String String::format(const Variant &values, String placeholder) const { } } else { //Array structure ["RobotGuy","Logis","rookie"] Variant v_val = values_arr[i]; - String val; - val = v_val.get_construct_string(); + String val = v_val; if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") { val = val.substr(1, val.length() - 2); @@ -2802,8 +2811,8 @@ String String::format(const Variant &values, String placeholder) const { d.get_key_list(&keys); for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { - String key = E->get().get_construct_string(); - String val = d[E->get()].get_construct_string(); + String key = E->get(); + String val = d[E->get()]; if (key.left(1) == "\"" && key.right(key.length() - 1) == "\"") { key = key.substr(1, key.length() - 2); @@ -3092,7 +3101,7 @@ String String::simplify_path() const { } else if (s.begins_with("user://")) { drive = "user://"; - s = s.substr(6, s.length()); + s = s.substr(7, s.length()); } else if (s.begins_with("/") || s.begins_with("\\")) { drive = s.substr(0, 1); @@ -4026,7 +4035,7 @@ String String::sprintf(const Array &values, bool *error) const { str = str.pad_decimals(min_decimals); // Show sign - if (show_sign && value >= 0) { + if (show_sign && str.left(1) != "-") { str = str.insert(0, "+"); } diff --git a/core/ustring.h b/core/ustring.h index d2766ec7a3..8e4dbd8031 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -63,7 +63,7 @@ public: CharString &operator+=(char p_char); int length() const { return size() ? size() - 1 : 0; } const char *get_data() const; - operator const char *() { return get_data(); }; + operator const char *() const { return get_data(); }; }; typedef wchar_t CharType; diff --git a/core/variant.cpp b/core/variant.cpp index 7d75c2243b..eb9f34fee6 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -858,7 +858,7 @@ bool Variant::is_one() const { // atomic types case BOOL: { - return _data._bool == true; + return _data._bool; } break; case INT: { @@ -1662,7 +1662,17 @@ Variant::operator Transform() const { return Transform(*_data._basis, Vector3()); else if (type == QUAT) return Transform(Basis(*reinterpret_cast<const Quat *>(_data._mem)), Vector3()); - else + else if (type == TRANSFORM2D) { + const Transform2D &t = *_data._transform2d; + Transform m; + m.basis.elements[0][0] = t.elements[0][0]; + m.basis.elements[1][0] = t.elements[0][1]; + m.basis.elements[0][1] = t.elements[1][0]; + m.basis.elements[1][1] = t.elements[1][1]; + m.origin[0] = t.elements[2][0]; + m.origin[1] = t.elements[2][1]; + return m; + } else return Transform(); } diff --git a/core/variant_call.cpp b/core/variant_call.cpp index f7fa2ebc70..0c6e43fe36 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -155,9 +155,7 @@ struct _VariantCall { funcdata.default_args = p_defaultarg; funcdata._const = p_const; funcdata.returns = p_has_return; -#ifdef DEBUG_ENABLED funcdata.return_type = p_return; -#endif if (p_argtype1.name) { funcdata.arg_types.push_back(p_argtype1.type); @@ -486,6 +484,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(Dictionary, keys); VCALL_LOCALMEM0R(Dictionary, values); VCALL_LOCALMEM1R(Dictionary, duplicate); + VCALL_LOCALMEM2R(Dictionary, get); VCALL_LOCALMEM2(Array, set); VCALL_LOCALMEM1R(Array, get); @@ -1679,6 +1678,7 @@ void register_variant_methods() { ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, keys, varray()); ADDFUNC0R(DICTIONARY, ARRAY, Dictionary, values, varray()); ADDFUNC1R(DICTIONARY, DICTIONARY, Dictionary, duplicate, BOOL, "deep", varray(false)); + ADDFUNC2R(DICTIONARY, NIL, Dictionary, get, NIL, "key", NIL, "default", varray(Variant())); ADDFUNC0R(ARRAY, INT, Array, size, varray()); ADDFUNC0R(ARRAY, BOOL, Array, empty, varray()); @@ -1895,6 +1895,7 @@ void register_variant_methods() { _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Z", Vector3::AXIS_Z); _VariantCall::add_variant_constant(Variant::VECTOR3, "ZERO", Vector3(0, 0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "ONE", Vector3(1, 1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR3, "INF", Vector3(Math_INF, Math_INF, Math_INF)); _VariantCall::add_variant_constant(Variant::VECTOR3, "LEFT", Vector3(-1, 0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR3, "RIGHT", Vector3(1, 0, 0)); @@ -1904,6 +1905,7 @@ void register_variant_methods() { _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1)); _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR2, "ONE", Vector2(1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR2, "INF", Vector2(Math_INF, Math_INF)); _VariantCall::add_variant_constant(Variant::VECTOR2, "LEFT", Vector2(-1, 0)); _VariantCall::add_variant_constant(Variant::VECTOR2, "RIGHT", Vector2(1, 0)); diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 9afc31a772..9f172f0d57 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -521,7 +521,7 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, const Dictionary *arr_a = reinterpret_cast<const Dictionary *>(p_a._data._mem); const Dictionary *arr_b = reinterpret_cast<const Dictionary *>(p_b._data._mem); - _RETURN((*arr_a == *arr_b) == false); + _RETURN(*arr_a != *arr_b); } CASE_TYPE(math, OP_NOT_EQUAL, ARRAY) { @@ -2149,7 +2149,7 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) int idx = p_index; if (idx < 0) idx += 4; - if (idx >= 0 || idx < 4) { + if (idx >= 0 && idx < 4) { Color *v = reinterpret_cast<Color *>(_data._mem); (*v)[idx] = p_value; valid = true; @@ -2524,7 +2524,7 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { int idx = p_index; if (idx < 0) idx += 4; - if (idx >= 0 || idx < 4) { + if (idx >= 0 && idx < 4) { const Color *v = reinterpret_cast<const Color *>(_data._mem); valid = true; return (*v)[idx]; @@ -3521,7 +3521,7 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & //not as efficient but.. real_t va = a; real_t vb = b; - r_dst = (1.0 - c) * va + vb * c; + r_dst = va + (vb - va) * c; } else { r_dst = a; @@ -3542,13 +3542,13 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & case INT: { int64_t va = a._data._int; int64_t vb = b._data._int; - r_dst = int((1.0 - c) * va + vb * c); + r_dst = int(va + (vb - va) * c); } return; case REAL: { real_t va = a._data._real; real_t vb = b._data._real; - r_dst = (1.0 - c) * va + vb * c; + r_dst = va + (vb - va) * c; } return; case STRING: { @@ -3556,7 +3556,9 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & String sa = *reinterpret_cast<const String *>(a._data._mem); String sb = *reinterpret_cast<const String *>(b._data._mem); String dst; - int csize = sb.length() * c + sa.length() * (1.0 - c); + int sa_len = sa.length(); + int sb_len = sb.length(); + int csize = sa_len + (sb_len - sa_len) * c; if (csize == 0) { r_dst = ""; return; diff --git a/core/vmap.h b/core/vmap.h index 9fc99e636d..5f6d8190c6 100644 --- a/core/vmap.h +++ b/core/vmap.h @@ -36,22 +36,23 @@ template <class T, class V> class VMap { - - struct _Pair { +public: + struct Pair { T key; V value; - _FORCE_INLINE_ _Pair() {} + _FORCE_INLINE_ Pair() {} - _FORCE_INLINE_ _Pair(const T &p_key, const V &p_value) { + _FORCE_INLINE_ Pair(const T &p_key, const V &p_value) { key = p_key; value = p_value; } }; - CowData<_Pair> _cowdata; +private: + CowData<Pair> _cowdata; _FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const { @@ -61,7 +62,7 @@ class VMap { int low = 0; int high = _cowdata.size() - 1; - const _Pair *a = _cowdata.ptr(); + const Pair *a = _cowdata.ptr(); int middle = 0; #if DEBUG_ENABLED @@ -95,7 +96,7 @@ class VMap { int low = 0; int high = _cowdata.size() - 1; int middle; - const _Pair *a = _cowdata.ptr(); + const Pair *a = _cowdata.ptr(); while (low <= high) { middle = (low + high) / 2; @@ -121,7 +122,7 @@ public: _cowdata.get_m(pos).value = p_val; return pos; } - _cowdata.insert(pos, _Pair(p_key, p_val)); + _cowdata.insert(pos, Pair(p_key, p_val)); return pos; } @@ -152,12 +153,12 @@ public: _FORCE_INLINE_ int size() const { return _cowdata.size(); } _FORCE_INLINE_ bool empty() const { return _cowdata.empty(); } - const _Pair *get_array() const { + const Pair *get_array() const { return _cowdata.ptr(); } - _Pair *get_array() { + Pair *get_array() { return _cowdata.ptrw(); } |