diff options
66 files changed, 1243 insertions, 279 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index cb82dc7f8f..94da74cbda 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -1619,12 +1619,17 @@ Error _Directory::open(const String &p_path) { memdelete(d); } d = alt; + dir_open = true; return OK; } +bool _Directory::is_open() const { + return d && dir_open; +} + Error _Directory::list_dir_begin(bool p_skip_navigational, bool p_skip_hidden) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); _list_skip_navigational = p_skip_navigational; _list_skip_hidden = p_skip_hidden; @@ -1633,7 +1638,7 @@ Error _Directory::list_dir_begin(bool p_skip_navigational, bool p_skip_hidden) { } String _Directory::get_next() { - ERR_FAIL_COND_V_MSG(!d, "", "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use."); String next = d->get_next(); while (next != "" && ((_list_skip_navigational && (next == "." || next == "..")) || (_list_skip_hidden && d->current_is_hidden()))) { @@ -1643,42 +1648,49 @@ String _Directory::get_next() { } bool _Directory::current_is_dir() const { - ERR_FAIL_COND_V_MSG(!d, false, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), false, "Directory must be opened before use."); return d->current_is_dir(); } void _Directory::list_dir_end() { - ERR_FAIL_COND_MSG(!d, "Directory must be opened before use."); + ERR_FAIL_COND_MSG(!is_open(), "Directory must be opened before use."); d->list_dir_end(); } int _Directory::get_drive_count() { - ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use."); return d->get_drive_count(); } String _Directory::get_drive(int p_drive) { - ERR_FAIL_COND_V_MSG(!d, "", "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use."); return d->get_drive(p_drive); } int _Directory::get_current_drive() { - ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use."); return d->get_current_drive(); } Error _Directory::change_dir(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); - return d->change_dir(p_dir); + ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory is not configured properly."); + Error err = d->change_dir(p_dir); + + if (err != OK) { + return err; + } + dir_open = true; + + return OK; } String _Directory::get_current_dir() { - ERR_FAIL_COND_V_MSG(!d, "", "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use."); return d->get_current_dir(); } Error _Directory::make_dir(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); if (!p_dir.is_rel_path()) { DirAccess *d = DirAccess::create_for_path(p_dir); Error err = d->make_dir(p_dir); @@ -1689,7 +1701,7 @@ Error _Directory::make_dir(String p_dir) { } Error _Directory::make_dir_recursive(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); if (!p_dir.is_rel_path()) { DirAccess *d = DirAccess::create_for_path(p_dir); Error err = d->make_dir_recursive(p_dir); @@ -1700,8 +1712,7 @@ Error _Directory::make_dir_recursive(String p_dir) { } bool _Directory::file_exists(String p_file) { - ERR_FAIL_COND_V_MSG(!d, false, "Directory must be opened before use."); - + ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly."); if (!p_file.is_rel_path()) { return FileAccess::exists(p_file); } @@ -1710,30 +1721,29 @@ bool _Directory::file_exists(String p_file) { } bool _Directory::dir_exists(String p_dir) { - ERR_FAIL_COND_V_MSG(!d, false, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!d, false, "Directory is not configured properly."); if (!p_dir.is_rel_path()) { DirAccess *d = DirAccess::create_for_path(p_dir); bool exists = d->dir_exists(p_dir); memdelete(d); return exists; - - } else { - return d->dir_exists(p_dir); } + + return d->dir_exists(p_dir); } int _Directory::get_space_left() { - ERR_FAIL_COND_V_MSG(!d, 0, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use."); return d->get_space_left() / 1024 * 1024; //return value in megabytes, given binding is int } Error _Directory::copy(String p_from, String p_to) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); return d->copy(p_from, p_to); } Error _Directory::rename(String p_from, String p_to) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); if (!p_from.is_rel_path()) { DirAccess *d = DirAccess::create_for_path(p_from); Error err = d->rename(p_from, p_to); @@ -1745,7 +1755,7 @@ Error _Directory::rename(String p_from, String p_to) { } Error _Directory::remove(String p_name) { - ERR_FAIL_COND_V_MSG(!d, ERR_UNCONFIGURED, "Directory must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); if (!p_name.is_rel_path()) { DirAccess *d = DirAccess::create_for_path(p_name); Error err = d->remove(p_name); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index f9f5a4e7d7..a1fedf1bb8 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -457,6 +457,7 @@ VARIANT_ENUM_CAST(_File::CompressionMode); class _Directory : public Reference { GDCLASS(_Directory, Reference); DirAccess *d; + bool dir_open = false; protected: static void _bind_methods(); @@ -464,6 +465,8 @@ protected: public: Error open(const String &p_path); + bool is_open() const; + Error list_dir_begin(bool p_skip_navigational = false, bool p_skip_hidden = false); // This starts dir listing. String get_next(); bool current_is_dir() const; diff --git a/core/os/os.cpp b/core/os/os.cpp index 231069fcfb..dc8bd5ee69 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -163,6 +163,10 @@ bool OS::is_stdout_verbose() const { return _verbose_stdout; } +bool OS::is_stdout_debug_enabled() const { + return _debug_stdout; +} + void OS::dump_memory_to_file(const char *p_file) { //Memory::dump_static_mem_to_file(p_file); } diff --git a/core/os/os.h b/core/os/os.h index f21c0d4df7..48dae99188 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -50,6 +50,7 @@ class OS { bool low_processor_usage_mode = false; int low_processor_usage_mode_sleep_usec = 10000; bool _verbose_stdout = false; + bool _debug_stdout = false; String _local_clipboard; uint64_t _msec_splash; bool _no_window = false; @@ -222,6 +223,7 @@ public: virtual bool is_userfs_persistent() const { return true; } bool is_stdout_verbose() const; + bool is_stdout_debug_enabled() const; virtual void disable_crash_handler() {} virtual bool is_disable_crash_handler() const { return false; } diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 7e96735d67..3f9585c03c 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -144,6 +144,12 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { if (p_value.get_type() == Variant::NIL) { props.erase(p_name); + if (p_name.operator String().begins_with("autoload/")) { + String node_name = p_name.operator String().split("/")[1]; + if (autoloads.has(node_name)) { + remove_autoload(node_name); + } + } } else { if (p_name == CoreStringNames::get_singleton()->_custom_features) { Vector<String> custom_feature_array = String(p_value).split(","); @@ -181,6 +187,19 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { } else { props[p_name] = VariantContainer(p_value, last_order++); } + if (p_name.operator String().begins_with("autoload/")) { + String node_name = p_name.operator String().split("/")[1]; + AutoloadInfo autoload; + autoload.name = node_name; + String path = p_value; + if (path.begins_with("*")) { + autoload.is_singleton = true; + autoload.path = path.substr(1); + } else { + autoload.path = path; + } + add_autoload(autoload); + } } return true; @@ -945,6 +964,29 @@ bool ProjectSettings::has_custom_feature(const String &p_feature) const { return custom_features.has(p_feature); } +Map<StringName, ProjectSettings::AutoloadInfo> ProjectSettings::get_autoload_list() const { + return autoloads; +} + +void ProjectSettings::add_autoload(const AutoloadInfo &p_autoload) { + ERR_FAIL_COND_MSG(p_autoload.name == StringName(), "Trying to add autoload with no name."); + autoloads[p_autoload.name] = p_autoload; +} + +void ProjectSettings::remove_autoload(const StringName &p_autoload) { + ERR_FAIL_COND_MSG(!autoloads.has(p_autoload), "Trying to remove non-existent autoload."); + autoloads.erase(p_autoload); +} + +bool ProjectSettings::has_autoload(const StringName &p_autoload) const { + return autoloads.has(p_autoload); +} + +ProjectSettings::AutoloadInfo ProjectSettings::get_autoload(const StringName &p_name) const { + ERR_FAIL_COND_V_MSG(!autoloads.has(p_name), AutoloadInfo(), "Trying to get non-existent autoload."); + return autoloads[p_name]; +} + void ProjectSettings::_bind_methods() { ClassDB::bind_method(D_METHOD("has_setting", "name"), &ProjectSettings::has_setting); ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &ProjectSettings::set_setting); diff --git a/core/project_settings.h b/core/project_settings.h index 3ed80738a1..4aceafe3c0 100644 --- a/core/project_settings.h +++ b/core/project_settings.h @@ -47,6 +47,12 @@ public: NO_BUILTIN_ORDER_BASE = 1 << 16 }; + struct AutoloadInfo { + StringName name; + String path; + bool is_singleton = false; + }; + protected: struct VariantContainer { int order = 0; @@ -79,6 +85,8 @@ protected: Set<String> custom_features; Map<StringName, StringName> feature_overrides; + Map<StringName, AutoloadInfo> autoloads; + bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; @@ -148,6 +156,12 @@ public: bool has_custom_feature(const String &p_feature) const; + Map<StringName, AutoloadInfo> get_autoload_list() const; + void add_autoload(const AutoloadInfo &p_autoload); + void remove_autoload(const StringName &p_autoload); + bool has_autoload(const StringName &p_autoload) const; + AutoloadInfo get_autoload(const StringName &p_name) const; + ProjectSettings(); ~ProjectSettings(); }; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 308fa3c407..0aa1339401 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -701,6 +701,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedByteArray, uint8_t, remove); VCALL_PARRMEM1(PackedByteArray, uint8_t, append); VCALL_PARRMEM1(PackedByteArray, uint8_t, append_array); + VCALL_PARRMEM1R(PackedByteArray, uint8_t, has); + VCALL_PARRMEM0(PackedByteArray, uint8_t, sort); VCALL_PARRMEM0(PackedByteArray, uint8_t, invert); VCALL_PARRMEM2R(PackedByteArray, uint8_t, subarray); @@ -714,6 +716,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedInt32Array, int32_t, remove); VCALL_PARRMEM1(PackedInt32Array, int32_t, append); VCALL_PARRMEM1(PackedInt32Array, int32_t, append_array); + VCALL_PARRMEM1R(PackedInt32Array, int32_t, has); + VCALL_PARRMEM0(PackedInt32Array, int32_t, sort); VCALL_PARRMEM0(PackedInt32Array, int32_t, invert); VCALL_PARRMEM0R(PackedInt64Array, int64_t, size); @@ -726,6 +730,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedInt64Array, int64_t, remove); VCALL_PARRMEM1(PackedInt64Array, int64_t, append); VCALL_PARRMEM1(PackedInt64Array, int64_t, append_array); + VCALL_PARRMEM1R(PackedInt64Array, int64_t, has); + VCALL_PARRMEM0(PackedInt64Array, int64_t, sort); VCALL_PARRMEM0(PackedInt64Array, int64_t, invert); VCALL_PARRMEM0R(PackedFloat32Array, float, size); @@ -738,6 +744,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedFloat32Array, float, remove); VCALL_PARRMEM1(PackedFloat32Array, float, append); VCALL_PARRMEM1(PackedFloat32Array, float, append_array); + VCALL_PARRMEM1R(PackedFloat32Array, float, has); + VCALL_PARRMEM0(PackedFloat32Array, float, sort); VCALL_PARRMEM0(PackedFloat32Array, float, invert); VCALL_PARRMEM0R(PackedFloat64Array, double, size); @@ -750,6 +758,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedFloat64Array, double, remove); VCALL_PARRMEM1(PackedFloat64Array, double, append); VCALL_PARRMEM1(PackedFloat64Array, double, append_array); + VCALL_PARRMEM1R(PackedFloat64Array, double, has); + VCALL_PARRMEM0(PackedFloat64Array, double, sort); VCALL_PARRMEM0(PackedFloat64Array, double, invert); VCALL_PARRMEM0R(PackedStringArray, String, size); @@ -762,6 +772,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedStringArray, String, remove); VCALL_PARRMEM1(PackedStringArray, String, append); VCALL_PARRMEM1(PackedStringArray, String, append_array); + VCALL_PARRMEM1R(PackedStringArray, String, has); + VCALL_PARRMEM0(PackedStringArray, String, sort); VCALL_PARRMEM0(PackedStringArray, String, invert); VCALL_PARRMEM0R(PackedVector2Array, Vector2, size); @@ -774,6 +786,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedVector2Array, Vector2, remove); VCALL_PARRMEM1(PackedVector2Array, Vector2, append); VCALL_PARRMEM1(PackedVector2Array, Vector2, append_array); + VCALL_PARRMEM1R(PackedVector2Array, Vector2, has); + VCALL_PARRMEM0(PackedVector2Array, Vector2, sort); VCALL_PARRMEM0(PackedVector2Array, Vector2, invert); VCALL_PARRMEM0R(PackedVector3Array, Vector3, size); @@ -786,6 +800,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedVector3Array, Vector3, remove); VCALL_PARRMEM1(PackedVector3Array, Vector3, append); VCALL_PARRMEM1(PackedVector3Array, Vector3, append_array); + VCALL_PARRMEM1R(PackedVector3Array, Vector3, has); + VCALL_PARRMEM0(PackedVector3Array, Vector3, sort); VCALL_PARRMEM0(PackedVector3Array, Vector3, invert); VCALL_PARRMEM0R(PackedColorArray, Color, size); @@ -798,6 +814,8 @@ struct _VariantCall { VCALL_PARRMEM1(PackedColorArray, Color, remove); VCALL_PARRMEM1(PackedColorArray, Color, append); VCALL_PARRMEM1(PackedColorArray, Color, append_array); + VCALL_PARRMEM1R(PackedColorArray, Color, has); + VCALL_PARRMEM0(PackedColorArray, Color, sort); VCALL_PARRMEM0(PackedColorArray, Color, invert); #define VCALL_PTR0(m_type, m_method) \ @@ -2085,6 +2103,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_BYTE_ARRAY, NIL, PackedByteArray, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_BYTE_ARRAY, INT, PackedByteArray, insert, INT, "idx", INT, "byte", varray()); ADDFUNC1(PACKED_BYTE_ARRAY, NIL, PackedByteArray, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_BYTE_ARRAY, BOOL, PackedByteArray, has, INT, "value", varray()); + ADDFUNC0(PACKED_BYTE_ARRAY, NIL, PackedByteArray, sort, varray()); ADDFUNC0(PACKED_BYTE_ARRAY, NIL, PackedByteArray, invert, varray()); ADDFUNC2R(PACKED_BYTE_ARRAY, PACKED_BYTE_ARRAY, PackedByteArray, subarray, INT, "from", INT, "to", varray()); @@ -2103,6 +2123,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_INT32_ARRAY, NIL, PackedInt32Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_INT32_ARRAY, INT, PackedInt32Array, insert, INT, "idx", INT, "integer", varray()); ADDFUNC1(PACKED_INT32_ARRAY, NIL, PackedInt32Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_INT32_ARRAY, BOOL, PackedInt32Array, has, INT, "value", varray()); + ADDFUNC0(PACKED_INT32_ARRAY, NIL, PackedInt32Array, sort, varray()); ADDFUNC0(PACKED_INT32_ARRAY, NIL, PackedInt32Array, invert, varray()); ADDFUNC0R(PACKED_INT64_ARRAY, INT, PackedInt64Array, size, varray()); @@ -2114,6 +2136,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_INT64_ARRAY, NIL, PackedInt64Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_INT64_ARRAY, INT, PackedInt64Array, insert, INT, "idx", INT, "integer", varray()); ADDFUNC1(PACKED_INT64_ARRAY, NIL, PackedInt64Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_INT64_ARRAY, BOOL, PackedInt64Array, has, INT, "value", varray()); + ADDFUNC0(PACKED_INT64_ARRAY, NIL, PackedInt64Array, sort, varray()); ADDFUNC0(PACKED_INT64_ARRAY, NIL, PackedInt64Array, invert, varray()); ADDFUNC0R(PACKED_FLOAT32_ARRAY, INT, PackedFloat32Array, size, varray()); @@ -2125,6 +2149,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_FLOAT32_ARRAY, INT, PackedFloat32Array, insert, INT, "idx", FLOAT, "value", varray()); ADDFUNC1(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_FLOAT32_ARRAY, BOOL, PackedFloat32Array, has, FLOAT, "value", varray()); + ADDFUNC0(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, sort, varray()); ADDFUNC0(PACKED_FLOAT32_ARRAY, NIL, PackedFloat32Array, invert, varray()); ADDFUNC0R(PACKED_FLOAT64_ARRAY, INT, PackedFloat64Array, size, varray()); @@ -2136,6 +2162,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_FLOAT64_ARRAY, INT, PackedFloat64Array, insert, INT, "idx", FLOAT, "value", varray()); ADDFUNC1(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_FLOAT64_ARRAY, BOOL, PackedFloat64Array, has, FLOAT, "value", varray()); + ADDFUNC0(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, sort, varray()); ADDFUNC0(PACKED_FLOAT64_ARRAY, NIL, PackedFloat64Array, invert, varray()); ADDFUNC0R(PACKED_STRING_ARRAY, INT, PackedStringArray, size, varray()); @@ -2147,6 +2175,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_STRING_ARRAY, NIL, PackedStringArray, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_STRING_ARRAY, INT, PackedStringArray, insert, INT, "idx", STRING, "string", varray()); ADDFUNC1(PACKED_STRING_ARRAY, NIL, PackedStringArray, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_STRING_ARRAY, BOOL, PackedStringArray, has, STRING, "value", varray()); + ADDFUNC0(PACKED_STRING_ARRAY, NIL, PackedStringArray, sort, varray()); ADDFUNC0(PACKED_STRING_ARRAY, NIL, PackedStringArray, invert, varray()); ADDFUNC0R(PACKED_VECTOR2_ARRAY, INT, PackedVector2Array, size, varray()); @@ -2158,6 +2188,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_VECTOR2_ARRAY, INT, PackedVector2Array, insert, INT, "idx", VECTOR2, "vector2", varray()); ADDFUNC1(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_VECTOR2_ARRAY, BOOL, PackedVector2Array, has, VECTOR2, "value", varray()); + ADDFUNC0(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, sort, varray()); ADDFUNC0(PACKED_VECTOR2_ARRAY, NIL, PackedVector2Array, invert, varray()); ADDFUNC0R(PACKED_VECTOR3_ARRAY, INT, PackedVector3Array, size, varray()); @@ -2169,6 +2201,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_VECTOR3_ARRAY, INT, PackedVector3Array, insert, INT, "idx", VECTOR3, "vector3", varray()); ADDFUNC1(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_VECTOR3_ARRAY, BOOL, PackedVector3Array, has, VECTOR3, "value", varray()); + ADDFUNC0(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, sort, varray()); ADDFUNC0(PACKED_VECTOR3_ARRAY, NIL, PackedVector3Array, invert, varray()); ADDFUNC0R(PACKED_COLOR_ARRAY, INT, PackedColorArray, size, varray()); @@ -2180,6 +2214,8 @@ void register_variant_methods() { ADDFUNC1(PACKED_COLOR_ARRAY, NIL, PackedColorArray, remove, INT, "idx", varray()); ADDFUNC2R(PACKED_COLOR_ARRAY, INT, PackedColorArray, insert, INT, "idx", COLOR, "color", varray()); ADDFUNC1(PACKED_COLOR_ARRAY, NIL, PackedColorArray, resize, INT, "idx", varray()); + ADDFUNC1R(PACKED_COLOR_ARRAY, BOOL, PackedColorArray, has, COLOR, "value", varray()); + ADDFUNC0(PACKED_COLOR_ARRAY, NIL, PackedColorArray, sort, varray()); ADDFUNC0(PACKED_COLOR_ARRAY, NIL, PackedColorArray, invert, varray()); //pointerbased diff --git a/core/vector.h b/core/vector.h index 4c152fb084..5fb630c21c 100644 --- a/core/vector.h +++ b/core/vector.h @@ -92,6 +92,10 @@ public: void append_array(Vector<T> p_other); + bool has(const T &p_val) { + return find(p_val, 0) != -1; + } + template <class C> void sort_custom() { int len = _cowdata.size(); diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml index ed4257a809..a86dbfedde 100644 --- a/doc/classes/Directory.xml +++ b/doc/classes/Directory.xml @@ -5,7 +5,7 @@ </brief_description> <description> Directory type. It is used to manage directories and their content (not restricted to the project folder). - When creating a new [Directory], its default opened directory will be [code]res://[/code]. This may change in the future, so it is advised to always use [method open] to initialize your [Directory] where you want to operate, with explicit error checking. + When creating a new [Directory], it must be explicitly opened using [method open] before most methods can be used. However, [method file_exists] and [method dir_exists] can be used without opening a directory. If so, they use a path relative to [code]res://[/code]. Here is an example on how to iterate through the files of a directory: [codeblock] func dir_contents(path): @@ -63,6 +63,7 @@ </argument> <description> Returns whether the target directory exists. The argument can be relative to the current directory, or an absolute path. + If the [Directory] is not open, the path is relative to [code]res://[/code]. </description> </method> <method name="file_exists"> @@ -72,6 +73,7 @@ </argument> <description> Returns whether the target file exists. The argument can be relative to the current directory, or an absolute path. + If the [Directory] is not open, the path is relative to [code]res://[/code]. </description> </method> <method name="get_current_dir"> diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml index 53ca1fc6a9..0b0d71fccf 100644 --- a/doc/classes/HTTPRequest.xml +++ b/doc/classes/HTTPRequest.xml @@ -14,11 +14,19 @@ add_child(http_request) http_request.connect("request_completed", self, "_http_request_completed") - # Perform the HTTP request. The URL below returns some JSON as of writing. + # Perform a GET request. The URL below returns JSON as of writing. var error = http_request.request("https://httpbin.org/get") if error != OK: push_error("An error occurred in the HTTP request.") + # Perform a POST request. The URL below returns JSON as of writing. + # Note: Don't make simultaneous requests using a single HTTPRequest node. + # The snippet below is provided for reference only. + var body = {"name": "Godette"} + var error = http_request.request("https://httpbin.org/post", [], true, HTTPClient.METHOD_POST, body) + if error != OK: + push_error("An error occurred in the HTTP request.") + # Called when the HTTP request is completed. func _http_request_completed(result, response_code, headers, body): diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml index b08357e278..08f8558881 100644 --- a/doc/classes/PackedByteArray.xml +++ b/doc/classes/PackedByteArray.xml @@ -78,6 +78,15 @@ Returns a copy of the array's contents as [String]. Slower than [method get_string_from_ascii] but supports UTF-8 encoded data. Use this function if you are unsure about the source of the data. For user input this function should always be preferred. </description> </method> + <method name="has"> + <return type="bool"> + </return> + <argument index="0" name="value" type="int"> + </argument> + <description> + Returns [code]true[/code] if the array contains [code]value[/code]. + </description> + </method> <method name="hex_encode"> <return type="String"> </return> @@ -152,6 +161,13 @@ Returns the size of the array. </description> </method> + <method name="sort"> + <return type="void"> + </return> + <description> + Sorts the elements of the array in ascending order. + </description> + </method> <method name="subarray"> <return type="PackedByteArray"> </return> diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml index 06228e4dac..ec087e1b39 100644 --- a/doc/classes/PackedColorArray.xml +++ b/doc/classes/PackedColorArray.xml @@ -44,6 +44,15 @@ Returns [code]true[/code] if the array is empty. </description> </method> + <method name="has"> + <return type="bool"> + </return> + <argument index="0" name="value" type="Color"> + </argument> + <description> + Returns [code]true[/code] if the array contains [code]value[/code]. + </description> + </method> <method name="insert"> <return type="int"> </return> @@ -107,6 +116,13 @@ Returns the size of the array. </description> </method> + <method name="sort"> + <return type="void"> + </return> + <description> + Sorts the elements of the array in ascending order. + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/PackedFloat32Array.xml b/doc/classes/PackedFloat32Array.xml index ee82586cdb..a6b726944b 100644 --- a/doc/classes/PackedFloat32Array.xml +++ b/doc/classes/PackedFloat32Array.xml @@ -45,6 +45,15 @@ Returns [code]true[/code] if the array is empty. </description> </method> + <method name="has"> + <return type="bool"> + </return> + <argument index="0" name="value" type="float"> + </argument> + <description> + Returns [code]true[/code] if the array contains [code]value[/code]. + </description> + </method> <method name="insert"> <return type="int"> </return> @@ -108,6 +117,13 @@ Returns the size of the array. </description> </method> + <method name="sort"> + <return type="void"> + </return> + <description> + Sorts the elements of the array in ascending order. + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml index ce2300c65a..f867cda3b6 100644 --- a/doc/classes/PackedFloat64Array.xml +++ b/doc/classes/PackedFloat64Array.xml @@ -45,6 +45,15 @@ Returns [code]true[/code] if the array is empty. </description> </method> + <method name="has"> + <return type="bool"> + </return> + <argument index="0" name="value" type="float"> + </argument> + <description> + Returns [code]true[/code] if the array contains [code]value[/code]. + </description> + </method> <method name="insert"> <return type="int"> </return> @@ -108,6 +117,13 @@ Returns the size of the array. </description> </method> + <method name="sort"> + <return type="void"> + </return> + <description> + Sorts the elements of the array in ascending order. + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/PackedInt32Array.xml b/doc/classes/PackedInt32Array.xml index 176c624956..b796d9cacb 100644 --- a/doc/classes/PackedInt32Array.xml +++ b/doc/classes/PackedInt32Array.xml @@ -45,6 +45,15 @@ Returns [code]true[/code] if the array is empty. </description> </method> + <method name="has"> + <return type="bool"> + </return> + <argument index="0" name="value" type="int"> + </argument> + <description> + Returns [code]true[/code] if the array contains [code]value[/code]. + </description> + </method> <method name="insert"> <return type="int"> </return> @@ -108,6 +117,13 @@ Returns the array size. </description> </method> + <method name="sort"> + <return type="void"> + </return> + <description> + Sorts the elements of the array in ascending order. + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml index d8a8071590..3d0d9a1360 100644 --- a/doc/classes/PackedInt64Array.xml +++ b/doc/classes/PackedInt64Array.xml @@ -45,6 +45,15 @@ Returns [code]true[/code] if the array is empty. </description> </method> + <method name="has"> + <return type="bool"> + </return> + <argument index="0" name="value" type="int"> + </argument> + <description> + Returns [code]true[/code] if the array contains [code]value[/code]. + </description> + </method> <method name="insert"> <return type="int"> </return> @@ -108,6 +117,13 @@ Returns the array size. </description> </method> + <method name="sort"> + <return type="void"> + </return> + <description> + Sorts the elements of the array in ascending order. + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml index 2d70dea012..bb56330248 100644 --- a/doc/classes/PackedScene.xml +++ b/doc/classes/PackedScene.xml @@ -7,6 +7,13 @@ A simplified interface to a scene file. Provides access to operations and checks that can be performed on the scene resource itself. Can be used to save a node to a file. When saving, the node as well as all the node it owns get saved (see [code]owner[/code] property on [Node]). [b]Note:[/b] The node doesn't need to own itself. + [b]Example of loading a saved scene:[/b] + [codeblock] + # Use `load()` instead of `preload()` if the path isn't known at compile-time. + var scene = preload("res://scene.tscn").instance() + # Add the node as a child of the node the script is attached to. + add_child(scene) + [/codeblock] [b]Example of saving a node with different owners:[/b] The following example creates 3 objects: [code]Node2D[/code] ([code]node[/code]), [code]RigidBody2D[/code] ([code]rigid[/code]) and [code]CollisionObject2D[/code] ([code]collision[/code]). [code]collision[/code] is a child of [code]rigid[/code] which is a child of [code]node[/code]. Only [code]rigid[/code] is owned by [code]node[/code] and [code]pack[/code] will therefore only save those two nodes, but not [code]collision[/code]. [codeblock] # Create the objects. diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml index 9526f5899d..f36af66d6d 100644 --- a/doc/classes/PackedStringArray.xml +++ b/doc/classes/PackedStringArray.xml @@ -44,6 +44,15 @@ Returns [code]true[/code] if the array is empty. </description> </method> + <method name="has"> + <return type="bool"> + </return> + <argument index="0" name="value" type="String"> + </argument> + <description> + Returns [code]true[/code] if the array contains [code]value[/code]. + </description> + </method> <method name="insert"> <return type="int"> </return> @@ -107,6 +116,13 @@ Returns the size of the array. </description> </method> + <method name="sort"> + <return type="void"> + </return> + <description> + Sorts the elements of the array in ascending order. + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml index 87f202357c..ecc535e488 100644 --- a/doc/classes/PackedVector2Array.xml +++ b/doc/classes/PackedVector2Array.xml @@ -44,6 +44,15 @@ Returns [code]true[/code] if the array is empty. </description> </method> + <method name="has"> + <return type="bool"> + </return> + <argument index="0" name="value" type="Vector2"> + </argument> + <description> + Returns [code]true[/code] if the array contains [code]value[/code]. + </description> + </method> <method name="insert"> <return type="int"> </return> @@ -107,6 +116,13 @@ Returns the size of the array. </description> </method> + <method name="sort"> + <return type="void"> + </return> + <description> + Sorts the elements of the array in ascending order. + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml index 7bfa684ff5..f268fbcc83 100644 --- a/doc/classes/PackedVector3Array.xml +++ b/doc/classes/PackedVector3Array.xml @@ -44,6 +44,15 @@ Returns [code]true[/code] if the array is empty. </description> </method> + <method name="has"> + <return type="bool"> + </return> + <argument index="0" name="value" type="Vector3"> + </argument> + <description> + Returns [code]true[/code] if the array contains [code]value[/code]. + </description> + </method> <method name="insert"> <return type="int"> </return> @@ -107,6 +116,13 @@ Returns the size of the array. </description> </method> + <method name="sort"> + <return type="void"> + </return> + <description> + Sorts the elements of the array in ascending order. + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml index 5bc34772c8..0aa40dffb3 100644 --- a/doc/classes/Resource.xml +++ b/doc/classes/Resource.xml @@ -23,7 +23,8 @@ <argument index="0" name="subresources" type="bool" default="false"> </argument> <description> - Duplicates the resource, returning a new resource. By default, sub-resources are shared between resource copies for efficiency, this can be changed by passing [code]true[/code] to the [code]subresources[/code] argument. + Duplicates the resource, returning a new resource. By default, sub-resources are shared between resource copies for efficiency. This can be changed by passing [code]true[/code] to the [code]subresources[/code] argument which will copy the subresources. + [b]Note:[/b] If [code]subresources[/code] is [code]true[/code], this method will only perform a shallow copy. Nested resources within subresources will not be duplicated and will still be shared. </description> </method> <method name="get_local_scene" qualifiers="const"> diff --git a/doc/classes/Timer.xml b/doc/classes/Timer.xml index c1e5987a06..5d684755fa 100644 --- a/doc/classes/Timer.xml +++ b/doc/classes/Timer.xml @@ -5,6 +5,7 @@ </brief_description> <description> Counts down a specified interval and emits a signal on reaching 0. Can be set to repeat or "one-shot" mode. + [b]Note:[/b] To create an one-shot timer without instantiating a node, use [method SceneTree.create_timer]. </description> <tutorials> </tutorials> diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 6eef04b87f..4dd66c06e6 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -2566,9 +2566,7 @@ Vector<uint8_t> RasterizerStorageGLES2::mesh_surface_get_array(RID p_mesh, int p ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<uint8_t>()); Surface *surface = mesh->surfaces[p_surface]; -#ifndef TOOLS_ENABLED - ERR_PRINT("OpenGL ES 2.0 does not allow retrieving mesh array data"); -#endif + return surface->data; } @@ -2612,7 +2610,7 @@ Vector<Vector<uint8_t>> RasterizerStorageGLES2::mesh_surface_get_blend_shapes(RI ERR_FAIL_COND_V(!mesh, Vector<Vector<uint8_t>>()); ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<Vector<uint8_t>>()); #ifndef TOOLS_ENABLED - ERR_PRINT("OpenGL ES 2.0 does not allow retrieving mesh array data"); + ERR_PRINT("OpenGL ES 2.0 does not allow retrieving blend shape data"); #endif return mesh->surfaces[p_surface]->blend_shape_data; diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index 8af58a7ed7..79924b849c 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -50,7 +50,7 @@ Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force f->close(); } const uint8_t *reader = file_buffer.ptr(); - return PNGDriverCommon::png_to_image(reader, buffer_size, p_image); + return PNGDriverCommon::png_to_image(reader, buffer_size, p_force_linear, p_image); } void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const { @@ -61,7 +61,8 @@ Ref<Image> ImageLoaderPNG::load_mem_png(const uint8_t *p_png, int p_size) { Ref<Image> img; img.instance(); - Error err = PNGDriverCommon::png_to_image(p_png, p_size, img); + // the value of p_force_linear does not matter since it only applies to 16 bit + Error err = PNGDriverCommon::png_to_image(p_png, p_size, false, img); ERR_FAIL_COND_V(err, Ref<Image>()); return img; diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp index 77d5e68826..d3e187c501 100644 --- a/drivers/png/png_driver_common.cpp +++ b/drivers/png/png_driver_common.cpp @@ -58,7 +58,7 @@ static bool check_error(const png_image &image) { return false; } -Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) { +Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear, Ref<Image> p_image) { png_image png_img; zeromem(&png_img, sizeof(png_img)); png_img.version = PNG_IMAGE_VERSION; @@ -99,6 +99,11 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) { return ERR_UNAVAILABLE; } + if (!p_force_linear) { + // assume 16 bit pngs without sRGB or gAMA chunks are in sRGB format + png_img.flags |= PNG_IMAGE_FLAG_16BIT_sRGB; + } + const png_uint_32 stride = PNG_IMAGE_ROW_STRIDE(png_img); Vector<uint8_t> buffer; Error err = buffer.resize(PNG_IMAGE_BUFFER_SIZE(png_img, stride)); diff --git a/drivers/png/png_driver_common.h b/drivers/png/png_driver_common.h index 12129f034e..2099ddc536 100644 --- a/drivers/png/png_driver_common.h +++ b/drivers/png/png_driver_common.h @@ -36,7 +36,7 @@ namespace PNGDriverCommon { // Attempt to load png from buffer (p_source, p_size) into p_image -Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image); +Error png_to_image(const uint8_t *p_source, size_t p_size, bool p_force_linear, Ref<Image> p_image); // Append p_image, as a png, to p_buffer. // Contents of p_buffer is unspecified if error returned. diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 2653ac1cdb..b8153907a9 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -67,7 +67,11 @@ Error DirAccessWindows::list_dir_begin() { list_dir_end(); p->h = FindFirstFileExW((current_dir + "\\*").c_str(), FindExInfoStandard, &p->fu, FindExSearchNameMatch, nullptr, 0); - return (p->h == INVALID_HANDLE_VALUE) ? ERR_CANT_OPEN : OK; + if (p->h == INVALID_HANDLE_VALUE) { + return ERR_CANT_OPEN; + } + + return OK; } String DirAccessWindows::get_next() { diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index b73a27214d..70747b4956 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -108,22 +108,25 @@ void FindReplaceBar::_notification(int p_what) { void FindReplaceBar::_unhandled_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; - if (k.is_valid()) { - if (k->is_pressed() && (text_edit->has_focus() || vbc_lineedit->is_a_parent_of(get_focus_owner()))) { - bool accepted = true; - - switch (k->get_keycode()) { - case KEY_ESCAPE: { - _hide_bar(); - } break; - default: { - accepted = false; - } break; - } + if (!k.is_valid() || !k->is_pressed()) { + return; + } - if (accepted) { - accept_event(); - } + Control *focus_owner = get_focus_owner(); + if (text_edit->has_focus() || (focus_owner && vbc_lineedit->is_a_parent_of(focus_owner))) { + bool accepted = true; + + switch (k->get_keycode()) { + case KEY_ESCAPE: { + _hide_bar(); + } break; + default: { + accepted = false; + } break; + } + + if (accepted) { + accept_event(); } } } diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index da0ff9f18f..4cd4f68fa2 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -477,6 +477,8 @@ void EditorAutoloadSettings::update_autoload() { info.node->queue_delete(); info.node = nullptr; } + + ProjectSettings::get_singleton()->remove_autoload(info.name); } // Load new/changed autoloads @@ -503,6 +505,12 @@ void EditorAutoloadSettings::update_autoload() { } } + ProjectSettings::AutoloadInfo prop_info; + prop_info.name = info->name; + prop_info.path = info->path; + prop_info.is_singleton = info->is_singleton; + ProjectSettings::get_singleton()->add_autoload(prop_info); + if (!info->in_editor && !info->is_singleton) { // No reason to keep this node memdelete(info->node); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index e367ed4989..a5edcf5c22 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -533,6 +533,7 @@ bool EditorFileSystem::_update_scan_actions() { if (_test_for_reimport(full_path, false)) { //must reimport reimports.push_back(full_path); + reimports.append_array(_get_dependencies(full_path)); } else { //must not reimport, all was good //update modified times, to avoid reimport diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 74c516caeb..fe68797483 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1225,20 +1225,25 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { _find_node_types(editor_data.get_edited_scene_root(), c2d, c3d); - bool is2d; - if (c3d < c2d) { - is2d = true; - } else { - is2d = false; - } save.step(TTR("Creating Thumbnail"), 1); //current view? Ref<Image> img; - if (is2d) { + // If neither 3D or 2D nodes are present, make a 1x1 black texture. + // We cannot fallback on the 2D editor, because it may not have been used yet, + // which would result in an invalid texture. + if (c3d == 0 && c2d == 0) { + img.instance(); + img->create(1, 1, 0, Image::FORMAT_RGB8); + } else if (c3d < c2d) { img = scene_root->get_texture()->get_data(); } else { - img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_data(); + // The 3D editor may be disabled as a feature, but scenes can still be opened. + // This check prevents the preview from regenerating in case those scenes are then saved. + Ref<EditorFeatureProfile> profile = feature_profile_manager->get_current_profile(); + if (profile.is_valid() && !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)) { + img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_data(); + } } if (img.is_valid()) { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 66f0155c6a..8386d44e69 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -537,11 +537,14 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected)); if (current) { + Ref<Script> script = current->get_edited_resource(); if (p_save) { - _menu_option(FILE_SAVE); + // Do not try to save internal scripts + if (!(script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1)) { + _menu_option(FILE_SAVE); + } } - Ref<Script> script = current->get_edited_resource(); if (script != nullptr) { previous_scripts.push_back(script->get_path()); notify_script_close(script); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 1c9dadc0dd..9304683d77 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -343,16 +343,11 @@ void ScriptTextEditor::_set_theme_for_script() { } //colorize singleton autoloads (as types, just as engine singletons are) - List<PropertyInfo> props; - ProjectSettings::get_singleton()->get_property_list(&props); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; - if (!s.begins_with("autoload/")) { - continue; - } - String path = ProjectSettings::get_singleton()->get(s); - if (path.begins_with("*")) { - text_edit->add_keyword_color(s.get_slice("/", 1), colors_cache.usertype_color); + Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); + for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { + const ProjectSettings::AutoloadInfo &info = E->value(); + if (info.is_singleton) { + text_edit->add_keyword_color(info.name, colors_cache.usertype_color); } } @@ -942,12 +937,11 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c emit_signal("go_to_help", "class_global:" + result.class_name + ":" + result.class_member); } break; } - } else if (ProjectSettings::get_singleton()->has_setting("autoload/" + p_symbol)) { - //check for Autoload scenes - String path = ProjectSettings::get_singleton()->get("autoload/" + p_symbol); - if (path.begins_with("*")) { - path = path.substr(1, path.length()); - EditorNode::get_singleton()->load_scene(path); + } else if (ProjectSettings::get_singleton()->has_autoload(p_symbol)) { + // Check for Autoload scenes. + const ProjectSettings::AutoloadInfo &info = ProjectSettings::get_singleton()->get_autoload(p_symbol); + if (info.is_singleton) { + EditorNode::get_singleton()->load_scene(info.path); } } else if (p_symbol.is_rel_path()) { // Every symbol other than absolute path is relative path so keep this condition at last. @@ -974,7 +968,7 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) { } ScriptLanguage::LookupResult result; - if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK || ProjectSettings::get_singleton()->has_setting("autoload/" + p_symbol)) { + if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK || (ProjectSettings::get_singleton()->has_autoload(p_symbol) && ProjectSettings::get_singleton()->get_autoload(p_symbol).is_singleton)) { text_edit->set_highlighted_word(p_symbol); } else if (p_symbol.is_rel_path()) { String path = _get_absolute_path(p_symbol); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 5184793760..1880fd5112 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -2004,6 +2004,14 @@ void ProjectManager::_open_selected_projects() { args.push_back("--editor"); + if (OS::get_singleton()->is_stdout_debug_enabled()) { + args.push_back("--debug"); + } + + if (OS::get_singleton()->is_stdout_verbose()) { + args.push_back("--verbose"); + } + if (OS::get_singleton()->is_disable_crash_handler()) { args.push_back("--disable-crash-handler"); } diff --git a/main/main.cpp b/main/main.cpp index 608b4a7c4d..7492d3d6c9 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -836,6 +836,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "-d" || I->get() == "--debug") { debug_uri = "local://"; + OS::get_singleton()->_debug_stdout = true; #if defined(DEBUG_ENABLED) && !defined(SERVER_ENABLED) } else if (I->get() == "--debug-collisions") { debug_collisions = true; @@ -1792,46 +1793,26 @@ bool Main::start() { if (!project_manager && !editor) { // game if (game_path != "" || script != "") { //autoload - List<PropertyInfo> props; - ProjectSettings::get_singleton()->get_property_list(&props); + Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); //first pass, add the constants so they exist before any script is loaded - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; - if (!s.begins_with("autoload/")) { - continue; - } - String name = s.get_slicec('/', 1); - String path = ProjectSettings::get_singleton()->get(s); - bool global_var = false; - if (path.begins_with("*")) { - global_var = true; - } + for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { + const ProjectSettings::AutoloadInfo &info = E->get(); - if (global_var) { + if (info.is_singleton) { for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->add_global_constant(name, Variant()); + ScriptServer::get_language(i)->add_global_constant(info.name, Variant()); } } } //second pass, load into global constants List<Node *> to_add; - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; - if (!s.begins_with("autoload/")) { - continue; - } - String name = s.get_slicec('/', 1); - String path = ProjectSettings::get_singleton()->get(s); - bool global_var = false; - if (path.begins_with("*")) { - global_var = true; - path = path.substr(1, path.length() - 1); - } + for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { + const ProjectSettings::AutoloadInfo &info = E->get(); - RES res = ResourceLoader::load(path); - ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + path); + RES res = ResourceLoader::load(info.path); + ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path); Node *n = nullptr; if (res->is_class("PackedScene")) { Ref<PackedScene> ps = res; @@ -1840,7 +1821,7 @@ bool Main::start() { Ref<Script> script_res = res; StringName ibt = script_res->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "Node"); - ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + path); + ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path); Object *obj = ClassDB::instance(ibt); @@ -1850,15 +1831,15 @@ bool Main::start() { n->set_script(script_res); } - ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + path); - n->set_name(name); + ERR_CONTINUE_MSG(!n, "Path in autoload not a node or script: " + info.path); + n->set_name(info.name); //defer so references are all valid on _ready() to_add.push_back(n); - if (global_var) { + if (info.is_singleton) { for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->add_global_constant(name, n); + ScriptServer::get_language(i)->add_global_constant(info.name, n); } } } diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index 8c92ae2a7c..54dda2563d 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D07CD44D1C5D589C00B7FB28 /* Images.xcassets */; }; D0BCFE4618AEBDA2004A7AAE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE4418AEBDA2004A7AAE /* InfoPlist.strings */; }; D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE7718AEBFEB004A7AAE /* $binary.pck */; }; + $pbx_launch_screen_build_reference /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -41,6 +42,7 @@ D0BCFE4318AEBDA2004A7AAE /* $binary-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "$binary-Info.plist"; sourceTree = "<group>"; }; D0BCFE4518AEBDA2004A7AAE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; }; D0BCFE7718AEBFEB004A7AAE /* $binary.pck */ = {isa = PBXFileReference; lastKnownFileType = file; path = "$binary.pck"; sourceTree = "<group>"; }; + $pbx_launch_screen_file_reference /* End PBXFileReference section */ $additional_pbx_files @@ -92,6 +94,7 @@ D0BCFE4118AEBDA2004A7AAE /* $binary */ = { isa = PBXGroup; children = ( + $pbx_launch_screen_copy_files 1FF4C1881F584E6300A41E41 /* $binary.entitlements */, D07CD44D1C5D589C00B7FB28 /* Images.xcassets */, D0BCFE4218AEBDA2004A7AAE /* Supporting Files */, @@ -247,6 +250,7 @@ files = ( D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */, D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */, + $pbx_launch_screen_build_phase D0BCFE4618AEBDA2004A7AAE /* InfoPlist.strings in Resources */, $additional_pbx_resources_build ); @@ -367,7 +371,7 @@ buildSettings = { ARCHS = "$godot_archs"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + $pbx_launch_image_usage_setting CODE_SIGN_ENTITLEMENTS = "$binary/$binary.entitlements"; CODE_SIGN_IDENTITY = "$code_sign_identity_debug"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_debug"; @@ -397,7 +401,7 @@ buildSettings = { ARCHS = "$godot_archs"; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + $pbx_launch_image_usage_setting CODE_SIGN_ENTITLEMENTS = "$binary/$binary.entitlements"; CODE_SIGN_IDENTITY = "$code_sign_identity_release"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "$code_sign_identity_release"; diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/Contents.json b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/Contents.json new file mode 100644 index 0000000000..1e63e78eda --- /dev/null +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "splash@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "splash@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.png Binary files differnew file mode 100644 index 0000000000..766b0b66ef --- /dev/null +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@2x.png diff --git a/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.png b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.png Binary files differnew file mode 100644 index 0000000000..766b0b66ef --- /dev/null +++ b/misc/dist/ios_xcode/godot_ios/Images.xcassets/SplashImage.imageset/splash@3x.png diff --git a/misc/dist/ios_xcode/godot_ios/Launch Screen.storyboard b/misc/dist/ios_xcode/godot_ios/Launch Screen.storyboard new file mode 100644 index 0000000000..3a7752a669 --- /dev/null +++ b/misc/dist/ios_xcode/godot_ios/Launch Screen.storyboard @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> + <device id="retina6_1" orientation="portrait" appearance="light"/> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/> + <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <scenes> + <!--View Controller--> + <scene sceneID="EHf-IW-A2E"> + <objects> + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> + <rect key="frame" x="0.0" y="0.0" width="414" height="896"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="$launch_screen_image_mode" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="SplashImage" translatesAutoresizingMaskIntoConstraints="NO" id="tjZ-vn-Lsv"> + <rect key="frame" x="0.0" y="0.0" width="414" height="896"/> + </imageView> + </subviews> + <color key="backgroundColor" $launch_screen_background_color colorSpace="custom" customColorSpace="sRGB"/> + <constraints> + <constraint firstItem="tjZ-vn-Lsv" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="Ak7-I4-yrQ"/> + <constraint firstAttribute="trailing" secondItem="tjZ-vn-Lsv" secondAttribute="trailing" id="Fon-JO-5cz"/> + <constraint firstItem="tjZ-vn-Lsv" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="bkx-rj-PKc"/> + <constraint firstAttribute="bottom" secondItem="tjZ-vn-Lsv" secondAttribute="bottom" id="yjq-MJ-tym"/> + </constraints> + <viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/> + </view> + </viewController> + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> + </objects> + <point key="canvasLocation" x="52.173913043478265" y="375"/> + </scene> + </scenes> + <resources> + <image name="SplashImage" width="266.66665649414062" height="200"/> + </resources> +</document> diff --git a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist index e0cad2e7d1..e9d22f6b4d 100644 --- a/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist +++ b/misc/dist/ios_xcode/godot_ios/godot_ios-Info.plist @@ -57,5 +57,6 @@ $interface_orientations </array> $additional_plist_content + $plist_launch_screen_name </dict> </plist> diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp index e5e5f81d2a..01f068780d 100644 --- a/modules/bullet/area_bullet.cpp +++ b/modules/bullet/area_bullet.cpp @@ -164,7 +164,7 @@ void AreaBullet::main_shape_changed() { btGhost->setCollisionShape(get_main_shape()); } -void AreaBullet::reload_body() { +void AreaBullet::do_reload_body() { if (space) { space->remove_area(this); space->add_area(this); @@ -178,13 +178,15 @@ void AreaBullet::set_space(SpaceBullet *p_space) { isScratched = false; // Remove this object form the physics world + space->unregister_collision_object(this); space->remove_area(this); } space = p_space; if (space) { - space->add_area(this); + space->register_collision_object(this); + reload_body(); } } diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h index c0bcc858fe..12272092f7 100644 --- a/modules/bullet/area_bullet.h +++ b/modules/bullet/area_bullet.h @@ -140,7 +140,7 @@ public: _FORCE_INLINE_ int get_spOv_priority() { return spOv_priority; } virtual void main_shape_changed(); - virtual void reload_body(); + virtual void do_reload_body(); virtual void set_space(SpaceBullet *p_space); virtual void dispatch_callbacks(); diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index f397c53344..8f64c11867 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -561,14 +561,14 @@ void BulletPhysicsServer3D::body_clear_shapes(RID p_body) { } void BulletPhysicsServer3D::body_attach_object_instance_id(RID p_body, ObjectID p_id) { - CollisionObjectBullet *body = get_collisin_object(p_body); + CollisionObjectBullet *body = get_collision_object(p_body); ERR_FAIL_COND(!body); body->set_instance_id(p_id); } ObjectID BulletPhysicsServer3D::body_get_object_instance_id(RID p_body) const { - CollisionObjectBullet *body = get_collisin_object(p_body); + CollisionObjectBullet *body = get_collision_object(p_body); ERR_FAIL_COND_V(!body, ObjectID()); return body->get_instance_id(); @@ -1557,6 +1557,13 @@ void BulletPhysicsServer3D::sync() { } void BulletPhysicsServer3D::flush_queries() { + if (!active) { + return; + } + + for (int i = 0; i < active_spaces_count; ++i) { + active_spaces[i]->flush_queries(); + } } void BulletPhysicsServer3D::finish() { @@ -1567,7 +1574,17 @@ int BulletPhysicsServer3D::get_process_info(ProcessInfo p_info) { return 0; } -CollisionObjectBullet *BulletPhysicsServer3D::get_collisin_object(RID p_object) const { +SpaceBullet *BulletPhysicsServer3D::get_space(RID p_rid) const { + ERR_FAIL_COND_V_MSG(space_owner.owns(p_rid) == false, nullptr, "The RID is not valid."); + return space_owner.getornull(p_rid); +} + +ShapeBullet *BulletPhysicsServer3D::get_shape(RID p_rid) const { + ERR_FAIL_COND_V_MSG(shape_owner.owns(p_rid) == false, nullptr, "The RID is not valid."); + return shape_owner.getornull(p_rid); +} + +CollisionObjectBullet *BulletPhysicsServer3D::get_collision_object(RID p_object) const { if (rigid_body_owner.owns(p_object)) { return rigid_body_owner.getornull(p_object); } @@ -1577,15 +1594,20 @@ CollisionObjectBullet *BulletPhysicsServer3D::get_collisin_object(RID p_object) if (soft_body_owner.owns(p_object)) { return soft_body_owner.getornull(p_object); } - return nullptr; + ERR_FAIL_V_MSG(nullptr, "The RID is no valid."); } -RigidCollisionObjectBullet *BulletPhysicsServer3D::get_rigid_collisin_object(RID p_object) const { +RigidCollisionObjectBullet *BulletPhysicsServer3D::get_rigid_collision_object(RID p_object) const { if (rigid_body_owner.owns(p_object)) { return rigid_body_owner.getornull(p_object); } if (area_owner.owns(p_object)) { return area_owner.getornull(p_object); } - return nullptr; + ERR_FAIL_V_MSG(nullptr, "The RID is no valid."); +} + +JointBullet *BulletPhysicsServer3D::get_joint(RID p_rid) const { + ERR_FAIL_COND_V_MSG(joint_owner.owns(p_rid) == false, nullptr, "The RID is not valid."); + return joint_owner.getornull(p_rid); } diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index 8e8b33a4b8..a8c4f6d0b2 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -405,11 +405,11 @@ public: virtual int get_process_info(ProcessInfo p_info); - CollisionObjectBullet *get_collisin_object(RID p_object) const; - RigidCollisionObjectBullet *get_rigid_collisin_object(RID p_object) const; - - /// Internal APIs -public: + SpaceBullet *get_space(RID p_rid) const; + ShapeBullet *get_shape(RID p_rid) const; + CollisionObjectBullet *get_collision_object(RID p_object) const; + RigidCollisionObjectBullet *get_rigid_collision_object(RID p_object) const; + JointBullet *get_joint(RID p_rid) const; }; #endif diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp index a3158a15e5..dd208965bd 100644 --- a/modules/bullet/collision_object_bullet.cpp +++ b/modules/bullet/collision_object_bullet.cpp @@ -79,7 +79,7 @@ btTransform CollisionObjectBullet::ShapeWrapper::get_adjusted_transform() const } void CollisionObjectBullet::ShapeWrapper::claim_bt_shape(const btVector3 &body_scale) { - if (!bt_shape) { + if (bt_shape == nullptr) { if (active) { bt_shape = shape->create_bt_shape(scale * body_scale); } else { @@ -88,6 +88,13 @@ void CollisionObjectBullet::ShapeWrapper::claim_bt_shape(const btVector3 &body_s } } +void CollisionObjectBullet::ShapeWrapper::release_bt_shape() { + if (bt_shape != nullptr) { + shape->destroy_bt_shape(bt_shape); + bt_shape = nullptr; + } +} + CollisionObjectBullet::CollisionObjectBullet(Type p_type) : RIDBullet(), type(p_type) {} @@ -158,6 +165,13 @@ bool CollisionObjectBullet::has_collision_exception(const CollisionObjectBullet return !bt_collision_object->checkCollideWith(p_otherCollisionObject->bt_collision_object); } +void CollisionObjectBullet::prepare_object_for_dispatch() { + if (need_body_reload) { + do_reload_body(); + need_body_reload = false; + } +} + void CollisionObjectBullet::set_collision_enabled(bool p_enabled) { collisionsEnabled = p_enabled; if (collisionsEnabled) { @@ -319,16 +333,28 @@ bool RigidCollisionObjectBullet::is_shape_disabled(int p_index) { return !shapes[p_index].active; } +void RigidCollisionObjectBullet::prepare_object_for_dispatch() { + if (need_shape_reload) { + do_reload_shapes(); + need_shape_reload = false; + } + CollisionObjectBullet::prepare_object_for_dispatch(); +} + void RigidCollisionObjectBullet::shape_changed(int p_shape_index) { ShapeWrapper &shp = shapes.write[p_shape_index]; if (shp.bt_shape == mainShape) { mainShape = nullptr; } - bulletdelete(shp.bt_shape); + shp.release_bt_shape(); reload_shapes(); } void RigidCollisionObjectBullet::reload_shapes() { + need_shape_reload = true; +} + +void RigidCollisionObjectBullet::do_reload_shapes() { if (mainShape && mainShape->isCompound()) { // Destroy compound bulletdelete(mainShape); @@ -336,41 +362,39 @@ void RigidCollisionObjectBullet::reload_shapes() { mainShape = nullptr; - ShapeWrapper *shpWrapper; const int shape_count = shapes.size(); + ShapeWrapper *shapes_ptr = shapes.ptrw(); - // Reset shape if required + // Reset all shapes if required if (force_shape_reset) { for (int i(0); i < shape_count; ++i) { - shpWrapper = &shapes.write[i]; - bulletdelete(shpWrapper->bt_shape); + shapes_ptr[i].release_bt_shape(); } force_shape_reset = false; } const btVector3 body_scale(get_bt_body_scale()); - // Try to optimize by not using compound if (1 == shape_count) { - shpWrapper = &shapes.write[0]; - btTransform transform = shpWrapper->get_adjusted_transform(); + // Is it possible to optimize by not using compound? + btTransform transform = shapes_ptr[0].get_adjusted_transform(); if (transform.getOrigin().isZero() && transform.getBasis() == transform.getBasis().getIdentity()) { - shpWrapper->claim_bt_shape(body_scale); - mainShape = shpWrapper->bt_shape; + shapes_ptr[0].claim_bt_shape(body_scale); + mainShape = shapes_ptr[0].bt_shape; main_shape_changed(); + // Nothing more to do return; } } - // Optimization not possible use a compound shape + // Optimization not possible use a compound shape. btCompoundShape *compoundShape = bulletnew(btCompoundShape(enableDynamicAabbTree, shape_count)); for (int i(0); i < shape_count; ++i) { - shpWrapper = &shapes.write[i]; - shpWrapper->claim_bt_shape(body_scale); - btTransform scaled_shape_transform(shpWrapper->get_adjusted_transform()); + shapes_ptr[i].claim_bt_shape(body_scale); + btTransform scaled_shape_transform(shapes_ptr[i].get_adjusted_transform()); scaled_shape_transform.getOrigin() *= body_scale; - compoundShape->addChildShape(scaled_shape_transform, shpWrapper->bt_shape); + compoundShape->addChildShape(scaled_shape_transform, shapes_ptr[i].bt_shape); } compoundShape->recalculateLocalAabb(); @@ -389,5 +413,5 @@ void RigidCollisionObjectBullet::internal_shape_destroy(int p_index, bool p_perm if (shp.bt_shape == mainShape) { mainShape = nullptr; } - bulletdelete(shp.bt_shape); + shp.release_bt_shape(); } diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h index f1423a69e4..ac74661f24 100644 --- a/modules/bullet/collision_object_bullet.h +++ b/modules/bullet/collision_object_bullet.h @@ -70,11 +70,12 @@ public: struct ShapeWrapper { ShapeBullet *shape = nullptr; - btCollisionShape *bt_shape = nullptr; btTransform transform; btVector3 scale; bool active = true; + btCollisionShape *bt_shape = nullptr; + public: ShapeWrapper() {} ShapeWrapper(ShapeBullet *p_shape, const btTransform &p_transform, bool p_active) : @@ -107,6 +108,7 @@ public: btTransform get_adjusted_transform() const; void claim_bt_shape(const btVector3 &body_scale); + void release_bt_shape(); }; protected: @@ -124,6 +126,8 @@ protected: VSet<RID> exceptions; + bool need_body_reload = true; + /// This array is used to know all areas where this Object is overlapped in /// New area is added when overlap with new area (AreaBullet::addOverlap), then is removed when it exit (CollisionObjectBullet::onExitArea) /// This array is used mainly to know which area hold the pointer of this object @@ -131,6 +135,9 @@ protected: bool isTransformChanged = false; public: + bool is_in_world = false; + +public: CollisionObjectBullet(Type p_type); virtual ~CollisionObjectBullet(); @@ -183,13 +190,21 @@ public: return collisionLayer & p_other->collisionMask || p_other->collisionLayer & collisionMask; } - virtual void reload_body() = 0; + bool need_reload_body() const { + return need_body_reload; + } + + void reload_body() { + need_body_reload = true; + } + virtual void do_reload_body() = 0; virtual void set_space(SpaceBullet *p_space) = 0; _FORCE_INLINE_ SpaceBullet *get_space() const { return space; } virtual void on_collision_checker_start() = 0; virtual void on_collision_checker_end() = 0; + virtual void prepare_object_for_dispatch(); virtual void dispatch_callbacks() = 0; void set_collision_enabled(bool p_enabled); @@ -215,6 +230,7 @@ class RigidCollisionObjectBullet : public CollisionObjectBullet, public ShapeOwn protected: btCollisionShape *mainShape = nullptr; Vector<ShapeWrapper> shapes; + bool need_shape_reload = true; public: RigidCollisionObjectBullet(Type p_type) : @@ -246,8 +262,12 @@ public: void set_shape_disabled(int p_index, bool p_disabled); bool is_shape_disabled(int p_index); + virtual void prepare_object_for_dispatch(); + virtual void shape_changed(int p_shape_index); - virtual void reload_shapes(); + void reload_shapes(); + bool need_reload_shapes() const { return need_shape_reload; } + virtual void do_reload_shapes(); virtual void main_shape_changed() = 0; virtual void body_scale_changed(); diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 6cfbe18a64..8ff27cda30 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -237,7 +237,7 @@ void RigidBodyBullet::KinematicUtilities::copyAllOwnerShapes() { case PhysicsServer3D::SHAPE_CYLINDER: case PhysicsServer3D::SHAPE_CONVEX_POLYGON: case PhysicsServer3D::SHAPE_RAY: { - shapes.write[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); + shapes.write[i].shape = static_cast<btConvexShape *>(shape_wrapper->shape->internal_create_bt_shape(owner_scale * shape_wrapper->scale, safe_margin)); } break; default: WARN_PRINT("This shape is not supported for kinematic collision."); @@ -307,7 +307,7 @@ void RigidBodyBullet::main_shape_changed() { set_continuous_collision_detection(is_continuous_collision_detection_enabled()); // Reset } -void RigidBodyBullet::reload_body() { +void RigidBodyBullet::do_reload_body() { if (space) { space->remove_rigid_body(this); if (get_main_shape()) { @@ -325,13 +325,15 @@ void RigidBodyBullet::set_space(SpaceBullet *p_space) { assert_no_constraints(); // Remove this object form the physics world + space->unregister_collision_object(this); space->remove_rigid_body(this); } space = p_space; if (space) { - space->add_rigid_body(this); + space->register_collision_object(this); + reload_body(); } } @@ -803,8 +805,8 @@ const btTransform &RigidBodyBullet::get_transform__bullet() const { } } -void RigidBodyBullet::reload_shapes() { - RigidCollisionObjectBullet::reload_shapes(); +void RigidBodyBullet::do_reload_shapes() { + RigidCollisionObjectBullet::do_reload_shapes(); const btScalar invMass = btBody->getInvMass(); const btScalar mass = invMass == 0 ? 0 : 1 / invMass; diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index ddc9d2916a..135497b897 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -236,7 +236,7 @@ public: _FORCE_INLINE_ btRigidBody *get_bt_rigid_body() { return btBody; } virtual void main_shape_changed(); - virtual void reload_body(); + virtual void do_reload_body(); virtual void set_space(SpaceBullet *p_space); virtual void dispatch_callbacks(); @@ -315,7 +315,7 @@ public: virtual void set_transform__bullet(const btTransform &p_global_transform); virtual const btTransform &get_transform__bullet() const; - virtual void reload_shapes(); + virtual void do_reload_shapes(); virtual void on_enter_area(AreaBullet *p_area); virtual void on_exit_area(AreaBullet *p_area); diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp index d53f1e7d17..f4550c2024 100644 --- a/modules/bullet/shape_bullet.cpp +++ b/modules/bullet/shape_bullet.cpp @@ -46,9 +46,15 @@ @author AndreaCatania */ -ShapeBullet::ShapeBullet() {} +ShapeBullet::ShapeBullet() { +} -ShapeBullet::~ShapeBullet() {} +ShapeBullet::~ShapeBullet() { + if (default_shape != nullptr) { + bulletdelete(default_shape); + default_shape = nullptr; + } +} btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale, real_t p_extra_edge) { btVector3 s; @@ -56,6 +62,22 @@ btCollisionShape *ShapeBullet::create_bt_shape(const Vector3 &p_implicit_scale, return create_bt_shape(s, p_extra_edge); } +btCollisionShape *ShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { + if (p_extra_edge == 0.0 && (p_implicit_scale - btVector3(1, 1, 1)).length2() <= CMP_EPSILON) { + return default_shape; + } + + return internal_create_bt_shape(p_implicit_scale, p_extra_edge); +} + +void ShapeBullet::destroy_bt_shape(btCollisionShape *p_shape) const { + if (p_shape != default_shape && p_shape != old_default_shape) { + if (likely(p_shape != nullptr)) { + bulletdelete(p_shape); + } + } +} + btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const { p_btShape->setUserPointer(const_cast<ShapeBullet *>(this)); p_btShape->setMargin(margin); @@ -63,10 +85,21 @@ btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const { } void ShapeBullet::notifyShapeChanged() { + // Store the old shape ptr so to not lose the reference pointer. + old_default_shape = default_shape; + // Create the new default shape with the new data. + default_shape = internal_create_bt_shape(btVector3(1, 1, 1)); + for (Map<ShapeOwnerBullet *, int>::Element *E = owners.front(); E; E = E->next()) { ShapeOwnerBullet *owner = static_cast<ShapeOwnerBullet *>(E->key()); owner->shape_changed(owner->find_shape(this)); } + + if (old_default_shape) { + // At this point now one has the old default shape; just delete it. + bulletdelete(old_default_shape); + old_default_shape = nullptr; + } } void ShapeBullet::add_owner(ShapeOwnerBullet *p_owner) { @@ -186,7 +219,7 @@ void PlaneShapeBullet::setup(const Plane &p_plane) { notifyShapeChanged(); } -btCollisionShape *PlaneShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { +btCollisionShape *PlaneShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { btVector3 btPlaneNormal; G_TO_B(plane.normal, btPlaneNormal); return prepare(PlaneShapeBullet::create_shape_plane(btPlaneNormal, plane.d)); @@ -214,7 +247,7 @@ void SphereShapeBullet::setup(real_t p_radius) { notifyShapeChanged(); } -btCollisionShape *SphereShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { +btCollisionShape *SphereShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { return prepare(ShapeBullet::create_shape_sphere(radius * p_implicit_scale[0] + p_extra_edge)); } @@ -241,7 +274,7 @@ void BoxShapeBullet::setup(const Vector3 &p_half_extents) { notifyShapeChanged(); } -btCollisionShape *BoxShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { +btCollisionShape *BoxShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { return prepare(ShapeBullet::create_shape_box((half_extents * p_implicit_scale) + btVector3(p_extra_edge, p_extra_edge, p_extra_edge))); } @@ -274,7 +307,7 @@ void CapsuleShapeBullet::setup(real_t p_height, real_t p_radius) { notifyShapeChanged(); } -btCollisionShape *CapsuleShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { +btCollisionShape *CapsuleShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { return prepare(ShapeBullet::create_shape_capsule(radius * p_implicit_scale[0] + p_extra_edge, height * p_implicit_scale[1] + p_extra_edge)); } @@ -307,7 +340,7 @@ void CylinderShapeBullet::setup(real_t p_height, real_t p_radius) { notifyShapeChanged(); } -btCollisionShape *CylinderShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { +btCollisionShape *CylinderShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin) { return prepare(ShapeBullet::create_shape_cylinder(radius * p_implicit_scale[0] + p_margin, height * p_implicit_scale[1] + p_margin)); } @@ -349,7 +382,7 @@ void ConvexPolygonShapeBullet::setup(const Vector<Vector3> &p_vertices) { notifyShapeChanged(); } -btCollisionShape *ConvexPolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { +btCollisionShape *ConvexPolygonShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { if (!vertices.size()) { // This is necessary since 0 vertices return prepare(ShapeBullet::create_shape_empty()); @@ -431,7 +464,7 @@ void ConcavePolygonShapeBullet::setup(Vector<Vector3> p_faces) { notifyShapeChanged(); } -btCollisionShape *ConcavePolygonShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { +btCollisionShape *ConcavePolygonShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { btCollisionShape *cs = ShapeBullet::create_shape_concave(meshShape); if (!cs) { // This is necessary since if 0 faces the creation of concave return null @@ -555,7 +588,7 @@ void HeightMapShapeBullet::setup(Vector<real_t> &p_heights, int p_width, int p_d notifyShapeChanged(); } -btCollisionShape *HeightMapShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { +btCollisionShape *HeightMapShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { btCollisionShape *cs(ShapeBullet::create_shape_height_field(heights, width, depth, min_height, max_height)); cs->setLocalScaling(p_implicit_scale); prepare(cs); @@ -588,6 +621,6 @@ void RayShapeBullet::setup(real_t p_length, bool p_slips_on_slope) { notifyShapeChanged(); } -btCollisionShape *RayShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { +btCollisionShape *RayShapeBullet::internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) { return prepare(ShapeBullet::create_shape_ray(length * p_implicit_scale[1] + p_extra_edge, slips_on_slope)); } diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h index a35a1d8a18..6ca4d36a23 100644 --- a/modules/bullet/shape_bullet.h +++ b/modules/bullet/shape_bullet.h @@ -53,6 +53,10 @@ class ShapeBullet : public RIDBullet { Map<ShapeOwnerBullet *, int> owners; real_t margin = 0.04; + // Contains the default shape. + btCollisionShape *default_shape = nullptr; + btCollisionShape *old_default_shape = nullptr; + protected: /// return self btCollisionShape *prepare(btCollisionShape *p_btShape) const; @@ -63,7 +67,11 @@ public: virtual ~ShapeBullet(); btCollisionShape *create_bt_shape(const Vector3 &p_implicit_scale, real_t p_extra_edge = 0); - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0) = 0; + btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); + + void destroy_bt_shape(btCollisionShape *p_shape) const; + + virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0) = 0; void add_owner(ShapeOwnerBullet *p_owner); void remove_owner(ShapeOwnerBullet *p_owner, bool p_permanentlyFromThisBody = false); @@ -102,7 +110,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); + virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(const Plane &p_plane); @@ -118,7 +126,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); + virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(real_t p_radius); @@ -134,7 +142,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); + virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(const Vector3 &p_half_extents); @@ -152,7 +160,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); + virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(real_t p_height, real_t p_radius); @@ -170,7 +178,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); + virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_margin = 0); private: void setup(real_t p_height, real_t p_radius); @@ -186,7 +194,7 @@ public: void get_vertices(Vector<Vector3> &out_vertices); virtual Variant get_data() const; virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); + virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(const Vector<Vector3> &p_vertices); @@ -204,7 +212,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); + virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(Vector<Vector3> p_faces); @@ -223,7 +231,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); + virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); @@ -239,7 +247,7 @@ public: virtual void set_data(const Variant &p_data); virtual Variant get_data() const; virtual PhysicsServer3D::ShapeType get_type() const; - virtual btCollisionShape *create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); + virtual btCollisionShape *internal_create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge = 0); private: void setup(real_t p_length, bool p_slips_on_slope); diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index 6794d6c313..3fccd3d8a2 100644 --- a/modules/bullet/soft_body_bullet.cpp +++ b/modules/bullet/soft_body_bullet.cpp @@ -41,7 +41,7 @@ SoftBodyBullet::SoftBodyBullet() : SoftBodyBullet::~SoftBodyBullet() { } -void SoftBodyBullet::reload_body() { +void SoftBodyBullet::do_reload_body() { if (space) { space->remove_soft_body(this); space->add_soft_body(this); @@ -51,13 +51,15 @@ void SoftBodyBullet::reload_body() { void SoftBodyBullet::set_space(SpaceBullet *p_space) { if (space) { isScratched = false; + space->unregister_collision_object(this); space->remove_soft_body(this); } space = p_space; if (space) { - space->add_soft_body(this); + space->register_collision_object(this); + reload_body(); } } diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h index da8a2412ed..ba968f4271 100644 --- a/modules/bullet/soft_body_bullet.h +++ b/modules/bullet/soft_body_bullet.h @@ -87,7 +87,7 @@ public: SoftBodyBullet(); ~SoftBodyBullet(); - virtual void reload_body(); + virtual void do_reload_body(); virtual void set_space(SpaceBullet *p_space); virtual void dispatch_callbacks() {} diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index cfe8cd5322..70e137b16d 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -127,7 +127,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale_abs(), p_margin); if (!btShape->isConvex()) { - bulletdelete(btShape); + shape->destroy_bt_shape(btShape); ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); return 0; } @@ -147,7 +147,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra btQuery.m_closestDistanceThreshold = 0; space->dynamicsWorld->contactTest(&collision_object, btQuery); - bulletdelete(btConvex); + shape->destroy_bt_shape(btShape); return btQuery.m_count; } @@ -167,7 +167,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale(), p_margin); if (!btShape->isConvex()) { - bulletdelete(btShape); + shape->destroy_bt_shape(btShape); ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); return false; } @@ -206,7 +206,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf r_closest_unsafe = 1.0f; } - bulletdelete(bt_convex_shape); + shape->destroy_bt_shape(btShape); return true; // Mean success } @@ -221,7 +221,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform & btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), p_margin); if (!btShape->isConvex()) { - bulletdelete(btShape); + shape->destroy_bt_shape(btShape); ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); return false; } @@ -242,7 +242,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform & space->dynamicsWorld->contactTest(&collision_object, btQuery); r_result_count = btQuery.m_count; - bulletdelete(btConvex); + shape->destroy_bt_shape(btShape); return btQuery.m_count; } @@ -253,7 +253,7 @@ bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_sh btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), p_margin); if (!btShape->isConvex()) { - bulletdelete(btShape); + shape->destroy_bt_shape(btShape); ERR_PRINT("The shape is not a convex shape, then is not supported: shape type: " + itos(shape->get_type())); return false; } @@ -273,7 +273,7 @@ bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_sh btQuery.m_closestDistanceThreshold = 0; space->dynamicsWorld->contactTest(&collision_object, btQuery); - bulletdelete(btConvex); + shape->destroy_bt_shape(btShape); if (btQuery.m_collided) { if (btCollisionObject::CO_RIGID_BODY == btQuery.m_rest_info_collision_object->getInternalType()) { @@ -286,7 +286,7 @@ bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_sh } Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const { - RigidCollisionObjectBullet *rigid_object = space->get_physics_server()->get_rigid_collisin_object(p_object); + RigidCollisionObjectBullet *rigid_object = space->get_physics_server()->get_rigid_collision_object(p_object); ERR_FAIL_COND_V(!rigid_object, Vector3()); btVector3 out_closest_point(0, 0, 0); @@ -349,9 +349,11 @@ SpaceBullet::~SpaceBullet() { } void SpaceBullet::flush_queries() { - const btCollisionObjectArray &colObjArray = dynamicsWorld->getCollisionObjectArray(); - for (int i = colObjArray.size() - 1; 0 <= i; --i) { - static_cast<CollisionObjectBullet *>(colObjArray[i]->getUserPointer())->dispatch_callbacks(); + const int size = collision_objects.size(); + CollisionObjectBullet **objects = collision_objects.ptrw(); + for (int i = 0; i < size; i += 1) { + objects[i]->prepare_object_for_dispatch(); + objects[i]->dispatch_callbacks(); } } @@ -448,16 +450,30 @@ real_t SpaceBullet::get_param(PhysicsServer3D::SpaceParameter p_param) { } void SpaceBullet::add_area(AreaBullet *p_area) { +#ifdef TOOLS_ENABLED + // This never happen, and there is no way for the user to trigger it. + // If in future a bug is introduced into this bullet integration and this + // function is called twice, the crash will notify the developer that will + // fix it even before do the eventual PR. + CRASH_COND(p_area->is_in_world); +#endif areas.push_back(p_area); dynamicsWorld->addCollisionObject(p_area->get_bt_ghost(), p_area->get_collision_layer(), p_area->get_collision_mask()); + p_area->is_in_world = true; } void SpaceBullet::remove_area(AreaBullet *p_area) { - areas.erase(p_area); - dynamicsWorld->removeCollisionObject(p_area->get_bt_ghost()); + if (p_area->is_in_world) { + areas.erase(p_area); + dynamicsWorld->removeCollisionObject(p_area->get_bt_ghost()); + p_area->is_in_world = false; + } } void SpaceBullet::reload_collision_filters(AreaBullet *p_area) { + if (p_area->is_in_world == false) { + return; + } btGhostObject *ghost_object = p_area->get_bt_ghost(); btBroadphaseProxy *ghost_proxy = ghost_object->getBroadphaseHandle(); @@ -467,24 +483,46 @@ void SpaceBullet::reload_collision_filters(AreaBullet *p_area) { dynamicsWorld->refreshBroadphaseProxy(ghost_object); } +void SpaceBullet::register_collision_object(CollisionObjectBullet *p_object) { + collision_objects.push_back(p_object); +} + +void SpaceBullet::unregister_collision_object(CollisionObjectBullet *p_object) { + collision_objects.erase(p_object); +} + void SpaceBullet::add_rigid_body(RigidBodyBullet *p_body) { +#ifdef TOOLS_ENABLED + // This never happen, and there is no way for the user to trigger it. + // If in future a bug is introduced into this bullet integration and this + // function is called twice, the crash will notify the developer that will + // fix it even before do the eventual PR. + CRASH_COND(p_body->is_in_world); +#endif if (p_body->is_static()) { dynamicsWorld->addCollisionObject(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); } else { dynamicsWorld->addRigidBody(p_body->get_bt_rigid_body(), p_body->get_collision_layer(), p_body->get_collision_mask()); p_body->scratch_space_override_modificator(); } + p_body->is_in_world = true; } void SpaceBullet::remove_rigid_body(RigidBodyBullet *p_body) { - if (p_body->is_static()) { - dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body()); - } else { - dynamicsWorld->removeRigidBody(p_body->get_bt_rigid_body()); + if (p_body->is_in_world) { + if (p_body->is_static()) { + dynamicsWorld->removeCollisionObject(p_body->get_bt_rigid_body()); + } else { + dynamicsWorld->removeRigidBody(p_body->get_bt_rigid_body()); + } + p_body->is_in_world = false; } } void SpaceBullet::reload_collision_filters(RigidBodyBullet *p_body) { + if (p_body->is_in_world == false) { + return; + } btRigidBody *rigid_body = p_body->get_bt_rigid_body(); btBroadphaseProxy *body_proxy = rigid_body->getBroadphaseProxy(); @@ -541,10 +579,6 @@ void SpaceBullet::remove_all_collision_objects() { } } -void onBulletPreTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) { - static_cast<SpaceBullet *>(p_dynamicsWorld->getWorldUserInfo())->flush_queries(); -} - void onBulletTickCallback(btDynamicsWorld *p_dynamicsWorld, btScalar timeStep) { const btCollisionObjectArray &colObjArray = p_dynamicsWorld->getCollisionObjectArray(); @@ -612,7 +646,6 @@ void SpaceBullet::create_empty_world(bool p_create_soft_world) { dynamicsWorld->setWorldUserInfo(this); - dynamicsWorld->setInternalTickCallback(onBulletPreTickCallback, this, true); dynamicsWorld->setInternalTickCallback(onBulletTickCallback, this, false); dynamicsWorld->getBroadphase()->getOverlappingPairCache()->setInternalGhostPairCallback(ghostPairCallback); // Setup ghost check dynamicsWorld->getPairCache()->setOverlapFilterCallback(godotFilterCallback); diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 5ff421ef52..ae4dc30274 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -110,6 +110,7 @@ class SpaceBullet : public RIDBullet { real_t linear_damp = 0.0; real_t angular_damp = 0.0; + Vector<CollisionObjectBullet *> collision_objects; Vector<AreaBullet *> areas; Vector<Vector3> contactDebug; @@ -124,9 +125,12 @@ public: real_t get_delta_time() { return delta_time; } void step(real_t p_delta_time); - _FORCE_INLINE_ btBroadphaseInterface *get_broadphase() { return broadphase; } - _FORCE_INLINE_ btCollisionDispatcher *get_dispatcher() { return dispatcher; } - _FORCE_INLINE_ btSoftBodyWorldInfo *get_soft_body_world_info() { return soft_body_world_info; } + _FORCE_INLINE_ btBroadphaseInterface *get_broadphase() const { return broadphase; } + _FORCE_INLINE_ btDefaultCollisionConfiguration *get_collision_configuration() const { return collisionConfiguration; } + _FORCE_INLINE_ btCollisionDispatcher *get_dispatcher() const { return dispatcher; } + _FORCE_INLINE_ btConstraintSolver *get_solver() const { return solver; } + _FORCE_INLINE_ btDiscreteDynamicsWorld *get_dynamic_world() const { return dynamicsWorld; } + _FORCE_INLINE_ btSoftBodyWorldInfo *get_soft_body_world_info() const { return soft_body_world_info; } _FORCE_INLINE_ bool is_using_soft_world() { return soft_body_world_info; } /// Used to set some parameters to Bullet world @@ -147,6 +151,9 @@ public: void remove_area(AreaBullet *p_area); void reload_collision_filters(AreaBullet *p_area); + void register_collision_object(CollisionObjectBullet *p_object); + void unregister_collision_object(CollisionObjectBullet *p_object); + void add_rigid_body(RigidBodyBullet *p_body); void remove_rigid_body(RigidBodyBullet *p_body); void reload_collision_filters(RigidBodyBullet *p_body); diff --git a/modules/gdnative/gdnative/packed_arrays.cpp b/modules/gdnative/gdnative/packed_arrays.cpp index fc71d50289..de93c1d9b3 100644 --- a/modules/gdnative/gdnative/packed_arrays.cpp +++ b/modules/gdnative/gdnative/packed_arrays.cpp @@ -104,6 +104,16 @@ godot_error GDAPI godot_packed_byte_array_insert(godot_packed_byte_array *p_self return (godot_error)self->insert(p_idx, p_data); } +godot_bool GDAPI godot_packed_byte_array_has(godot_packed_byte_array *p_self, const uint8_t p_value) { + Vector<uint8_t> *self = (Vector<uint8_t> *)p_self; + return (godot_bool)self->has(p_value); +} + +void GDAPI godot_packed_byte_array_sort(godot_packed_byte_array *p_self) { + Vector<uint8_t> *self = (Vector<uint8_t> *)p_self; + self->sort(); +} + void GDAPI godot_packed_byte_array_invert(godot_packed_byte_array *p_self) { Vector<uint8_t> *self = (Vector<uint8_t> *)p_self; self->invert(); @@ -198,6 +208,16 @@ godot_error GDAPI godot_packed_int32_array_insert(godot_packed_int32_array *p_se return (godot_error)self->insert(p_idx, p_data); } +godot_bool GDAPI godot_packed_int32_array_has(godot_packed_int32_array *p_self, const int32_t p_value) { + Vector<int32_t> *self = (Vector<int32_t> *)p_self; + return (godot_bool)self->has(p_value); +} + +void GDAPI godot_packed_int32_array_sort(godot_packed_int32_array *p_self) { + Vector<int32_t> *self = (Vector<int32_t> *)p_self; + self->sort(); +} + void GDAPI godot_packed_int32_array_invert(godot_packed_int32_array *p_self) { Vector<int32_t> *self = (Vector<int32_t> *)p_self; self->invert(); @@ -292,6 +312,16 @@ godot_error GDAPI godot_packed_int64_array_insert(godot_packed_int64_array *p_se return (godot_error)self->insert(p_idx, p_data); } +godot_bool GDAPI godot_packed_int64_array_has(godot_packed_int64_array *p_self, const int64_t p_value) { + Vector<int64_t> *self = (Vector<int64_t> *)p_self; + return (godot_bool)self->has(p_value); +} + +void GDAPI godot_packed_int64_array_sort(godot_packed_int64_array *p_self) { + Vector<int64_t> *self = (Vector<int64_t> *)p_self; + self->sort(); +} + void GDAPI godot_packed_int64_array_invert(godot_packed_int64_array *p_self) { Vector<int64_t> *self = (Vector<int64_t> *)p_self; self->invert(); @@ -386,6 +416,16 @@ godot_error GDAPI godot_packed_float32_array_insert(godot_packed_float32_array * return (godot_error)self->insert(p_idx, p_data); } +godot_bool GDAPI godot_packed_float32_array_has(godot_packed_float32_array *p_self, const float p_value) { + Vector<float> *self = (Vector<float> *)p_self; + return (godot_bool)self->has(p_value); +} + +void GDAPI godot_packed_float32_array_sort(godot_packed_float32_array *p_self) { + Vector<float> *self = (Vector<float> *)p_self; + self->sort(); +} + void GDAPI godot_packed_float32_array_invert(godot_packed_float32_array *p_self) { Vector<float> *self = (Vector<float> *)p_self; self->invert(); @@ -480,6 +520,16 @@ godot_error GDAPI godot_packed_float64_array_insert(godot_packed_float64_array * return (godot_error)self->insert(p_idx, p_data); } +godot_bool GDAPI godot_packed_float64_array_has(godot_packed_float64_array *p_self, const double p_value) { + Vector<double> *self = (Vector<double> *)p_self; + return (godot_bool)self->has(p_value); +} + +void GDAPI godot_packed_float64_array_sort(godot_packed_float64_array *p_self) { + Vector<double> *self = (Vector<double> *)p_self; + self->sort(); +} + void GDAPI godot_packed_float64_array_invert(godot_packed_float64_array *p_self) { Vector<double> *self = (Vector<double> *)p_self; self->invert(); @@ -576,6 +626,17 @@ godot_error GDAPI godot_packed_string_array_insert(godot_packed_string_array *p_ return (godot_error)self->insert(p_idx, s); } +godot_bool GDAPI godot_packed_string_array_has(godot_packed_string_array *p_self, const godot_string *p_value) { + Vector<String> *self = (Vector<String> *)p_self; + String &s = *(String *)p_value; + return (godot_bool)self->has(s); +} + +void GDAPI godot_packed_string_array_sort(godot_packed_string_array *p_self) { + Vector<String> *self = (Vector<String> *)p_self; + self->sort(); +} + void GDAPI godot_packed_string_array_invert(godot_packed_string_array *p_self) { Vector<String> *self = (Vector<String> *)p_self; self->invert(); @@ -678,6 +739,17 @@ godot_error GDAPI godot_packed_vector2_array_insert(godot_packed_vector2_array * return (godot_error)self->insert(p_idx, s); } +godot_bool GDAPI godot_packed_vector2_array_has(godot_packed_vector2_array *p_self, const godot_vector2 *p_value) { + Vector<Vector2> *self = (Vector<Vector2> *)p_self; + Vector2 &v = *(Vector2 *)p_value; + return (godot_bool)self->has(v); +} + +void GDAPI godot_packed_vector2_array_sort(godot_packed_vector2_array *p_self) { + Vector<Vector2> *self = (Vector<Vector2> *)p_self; + self->sort(); +} + void GDAPI godot_packed_vector2_array_invert(godot_packed_vector2_array *p_self) { Vector<Vector2> *self = (Vector<Vector2> *)p_self; self->invert(); @@ -779,6 +851,17 @@ godot_error GDAPI godot_packed_vector3_array_insert(godot_packed_vector3_array * return (godot_error)self->insert(p_idx, s); } +godot_bool GDAPI godot_packed_vector3_array_has(godot_packed_vector3_array *p_self, const godot_vector3 *p_value) { + Vector<Vector3> *self = (Vector<Vector3> *)p_self; + Vector3 &v = *(Vector3 *)p_value; + return (godot_bool)self->has(v); +} + +void GDAPI godot_packed_vector3_array_sort(godot_packed_vector3_array *p_self) { + Vector<Vector3> *self = (Vector<Vector3> *)p_self; + self->sort(); +} + void GDAPI godot_packed_vector3_array_invert(godot_packed_vector3_array *p_self) { Vector<Vector3> *self = (Vector<Vector3> *)p_self; self->invert(); @@ -880,6 +963,17 @@ godot_error GDAPI godot_packed_color_array_insert(godot_packed_color_array *p_se return (godot_error)self->insert(p_idx, s); } +godot_bool GDAPI godot_packed_color_array_has(godot_packed_color_array *p_self, const godot_color *p_value) { + Vector<Color> *self = (Vector<Color> *)p_self; + Color &c = *(Color *)p_value; + return (godot_bool)self->has(c); +} + +void GDAPI godot_packed_color_array_sort(godot_packed_color_array *p_self) { + Vector<Color> *self = (Vector<Color> *)p_self; + self->sort(); +} + void GDAPI godot_packed_color_array_invert(godot_packed_color_array *p_self) { Vector<Color> *self = (Vector<Color> *)p_self; self->invert(); diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 1284ebbd66..eb122089b6 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -918,42 +918,42 @@ ["const godot_variant **", "p_arguments"], ["godot_int", "p_argcount"] ] - }, + }, { "name": "godot_callable_is_null", "return_type": "godot_bool", "arguments": [ ["const godot_callable *", "p_self"] ] - }, + }, { "name": "godot_callable_is_custom", "return_type": "godot_bool", "arguments": [ ["const godot_callable *", "p_self"] ] - }, + }, { "name": "godot_callable_is_standard", "return_type": "godot_bool", "arguments": [ ["const godot_callable *", "p_self"] ] - }, + }, { "name": "godot_callable_get_object", "return_type": "godot_object *", "arguments": [ ["const godot_callable *", "p_self"] ] - }, + }, { "name": "godot_callable_get_object_id", "return_type": "uint64_t", "arguments": [ ["const godot_callable *", "p_self"] ] - }, + }, { "name": "godot_callable_get_method", "return_type": "godot_string_name", @@ -1093,14 +1093,14 @@ "arguments": [ ["const godot_signal *", "p_self"] ] - }, + }, { "name": "godot_signal_as_string", "return_type": "godot_string", "arguments": [ ["const godot_signal *", "p_self"] ] - }, + }, { "name": "godot_signal_operator_equal", "return_type": "godot_bool", @@ -1108,7 +1108,7 @@ ["const godot_signal *", "p_self"], ["const godot_signal *", "p_other"] ] - }, + }, { "name": "godot_signal_operator_less", "return_type": "godot_bool", @@ -1671,6 +1671,21 @@ ] }, { + "name": "godot_packed_byte_array_has", + "return_type": "godot_bool", + "arguments": [ + ["godot_packed_byte_array *", "p_self"], + ["const uint8_t", "p_value"] + ] + }, + { + "name": "godot_packed_byte_array_sort", + "return_type": "void", + "arguments": [ + ["godot_packed_byte_array *", "p_self"] + ] + }, + { "name": "godot_packed_byte_array_invert", "return_type": "void", "arguments": [ @@ -1802,6 +1817,21 @@ ] }, { + "name": "godot_packed_int32_array_has", + "return_type": "godot_bool", + "arguments": [ + ["godot_packed_int32_array *", "p_self"], + ["const int32_t", "p_value"] + ] + }, + { + "name": "godot_packed_int32_array_sort", + "return_type": "void", + "arguments": [ + ["godot_packed_int32_array *", "p_self"] + ] + }, + { "name": "godot_packed_int32_array_invert", "return_type": "void", "arguments": [ @@ -1933,6 +1963,21 @@ ] }, { + "name": "godot_packed_int64_array_has", + "return_type": "godot_bool", + "arguments": [ + ["godot_packed_int64_array *", "p_self"], + ["const int64_t", "p_value"] + ] + }, + { + "name": "godot_packed_int64_array_sort", + "return_type": "void", + "arguments": [ + ["godot_packed_int64_array *", "p_self"] + ] + }, + { "name": "godot_packed_int64_array_invert", "return_type": "void", "arguments": [ @@ -2064,6 +2109,21 @@ ] }, { + "name": "godot_packed_float32_array_has", + "return_type": "godot_bool", + "arguments": [ + ["godot_packed_float32_array *", "p_self"], + ["const float", "p_value"] + ] + }, + { + "name": "godot_packed_float32_array_sort", + "return_type": "void", + "arguments": [ + ["godot_packed_float32_array *", "p_self"] + ] + }, + { "name": "godot_packed_float32_array_invert", "return_type": "void", "arguments": [ @@ -2195,6 +2255,21 @@ ] }, { + "name": "godot_packed_float64_array_has", + "return_type": "godot_bool", + "arguments": [ + ["godot_packed_float64_array *", "p_self"], + ["const double", "p_value"] + ] + }, + { + "name": "godot_packed_float64_array_sort", + "return_type": "void", + "arguments": [ + ["godot_packed_float64_array *", "p_self"] + ] + }, + { "name": "godot_packed_float64_array_invert", "return_type": "void", "arguments": [ @@ -2326,6 +2401,21 @@ ] }, { + "name": "godot_packed_string_array_has", + "return_type": "godot_bool", + "arguments": [ + ["godot_packed_string_array *", "p_self"], + ["const godot_string *", "p_value"] + ] + }, + { + "name": "godot_packed_string_array_sort", + "return_type": "void", + "arguments": [ + ["godot_packed_string_array *", "p_self"] + ] + }, + { "name": "godot_packed_string_array_invert", "return_type": "void", "arguments": [ @@ -2457,6 +2547,21 @@ ] }, { + "name": "godot_packed_vector2_array_has", + "return_type": "godot_bool", + "arguments": [ + ["godot_packed_vector2_array *", "p_self"], + ["const godot_vector2 *", "p_value"] + ] + }, + { + "name": "godot_packed_vector2_array_sort", + "return_type": "void", + "arguments": [ + ["godot_packed_vector2_array *", "p_self"] + ] + }, + { "name": "godot_packed_vector2_array_invert", "return_type": "void", "arguments": [ @@ -2588,6 +2693,21 @@ ] }, { + "name": "godot_packed_vector3_array_has", + "return_type": "godot_bool", + "arguments": [ + ["godot_packed_vector3_array *", "p_self"], + ["const godot_vector3 *", "p_value"] + ] + }, + { + "name": "godot_packed_vector3_array_sort", + "return_type": "void", + "arguments": [ + ["godot_packed_vector3_array *", "p_self"] + ] + }, + { "name": "godot_packed_vector3_array_invert", "return_type": "void", "arguments": [ @@ -2719,6 +2839,21 @@ ] }, { + "name": "godot_packed_color_array_has", + "return_type": "godot_bool", + "arguments": [ + ["godot_packed_color_array *", "p_self"], + ["const godot_color *", "p_value"] + ] + }, + { + "name": "godot_packed_color_array_sort", + "return_type": "void", + "arguments": [ + ["godot_packed_color_array *", "p_self"] + ] + }, + { "name": "godot_packed_color_array_invert", "return_type": "void", "arguments": [ @@ -2748,7 +2883,7 @@ ["godot_packed_color_array *", "p_self"], ["const godot_int", "p_size"] ] - }, + }, { "name": "godot_packed_color_array_ptr", "return_type": "const godot_color *", @@ -5463,7 +5598,7 @@ ["godot_variant *", "r_dest"], ["const godot_packed_int64_array *", "p_pia"] ] - }, + }, { "name": "godot_variant_new_packed_float32_array", "return_type": "void", diff --git a/modules/gdnative/include/gdnative/packed_arrays.h b/modules/gdnative/include/gdnative/packed_arrays.h index 87d467a5b8..6a1727d76f 100644 --- a/modules/gdnative/include/gdnative/packed_arrays.h +++ b/modules/gdnative/include/gdnative/packed_arrays.h @@ -167,6 +167,10 @@ void GDAPI godot_packed_byte_array_append_array(godot_packed_byte_array *p_self, godot_error GDAPI godot_packed_byte_array_insert(godot_packed_byte_array *p_self, const godot_int p_idx, const uint8_t p_data); +godot_bool GDAPI godot_packed_byte_array_has(godot_packed_byte_array *p_self, const uint8_t p_value); + +void GDAPI godot_packed_byte_array_sort(godot_packed_byte_array *p_self); + void GDAPI godot_packed_byte_array_invert(godot_packed_byte_array *p_self); void GDAPI godot_packed_byte_array_push_back(godot_packed_byte_array *p_self, const uint8_t p_data); @@ -199,6 +203,10 @@ void GDAPI godot_packed_int32_array_append_array(godot_packed_int32_array *p_sel godot_error GDAPI godot_packed_int32_array_insert(godot_packed_int32_array *p_self, const godot_int p_idx, const int32_t p_data); +godot_bool GDAPI godot_packed_int32_array_has(godot_packed_int32_array *p_self, const int32_t p_value); + +void GDAPI godot_packed_int32_array_sort(godot_packed_int32_array *p_self); + void GDAPI godot_packed_int32_array_invert(godot_packed_int32_array *p_self); void GDAPI godot_packed_int32_array_push_back(godot_packed_int32_array *p_self, const int32_t p_data); @@ -231,6 +239,10 @@ void GDAPI godot_packed_int64_array_append_array(godot_packed_int64_array *p_sel godot_error GDAPI godot_packed_int64_array_insert(godot_packed_int64_array *p_self, const godot_int p_idx, const int64_t p_data); +godot_bool GDAPI godot_packed_int64_array_has(godot_packed_int64_array *p_self, const int64_t p_value); + +void GDAPI godot_packed_int64_array_sort(godot_packed_int64_array *p_self); + void GDAPI godot_packed_int64_array_invert(godot_packed_int64_array *p_self); void GDAPI godot_packed_int64_array_push_back(godot_packed_int64_array *p_self, const int64_t p_data); @@ -263,6 +275,10 @@ void GDAPI godot_packed_float32_array_append_array(godot_packed_float32_array *p godot_error GDAPI godot_packed_float32_array_insert(godot_packed_float32_array *p_self, const godot_int p_idx, const float p_data); +godot_bool GDAPI godot_packed_float32_array_has(godot_packed_float32_array *p_self, const float p_value); + +void GDAPI godot_packed_float32_array_sort(godot_packed_float32_array *p_self); + void GDAPI godot_packed_float32_array_invert(godot_packed_float32_array *p_self); void GDAPI godot_packed_float32_array_push_back(godot_packed_float32_array *p_self, const float p_data); @@ -295,6 +311,10 @@ void GDAPI godot_packed_float64_array_append_array(godot_packed_float64_array *p godot_error GDAPI godot_packed_float64_array_insert(godot_packed_float64_array *p_self, const godot_int p_idx, const double p_data); +godot_bool GDAPI godot_packed_float64_array_has(godot_packed_float64_array *p_self, const double p_value); + +void GDAPI godot_packed_float64_array_sort(godot_packed_float64_array *p_self); + void GDAPI godot_packed_float64_array_invert(godot_packed_float64_array *p_self); void GDAPI godot_packed_float64_array_push_back(godot_packed_float64_array *p_self, const double p_data); @@ -327,6 +347,10 @@ void GDAPI godot_packed_string_array_append_array(godot_packed_string_array *p_s godot_error GDAPI godot_packed_string_array_insert(godot_packed_string_array *p_self, const godot_int p_idx, const godot_string *p_data); +godot_bool GDAPI godot_packed_string_array_has(godot_packed_string_array *p_self, const godot_string *p_value); + +void GDAPI godot_packed_string_array_sort(godot_packed_string_array *p_self); + void GDAPI godot_packed_string_array_invert(godot_packed_string_array *p_self); void GDAPI godot_packed_string_array_push_back(godot_packed_string_array *p_self, const godot_string *p_data); @@ -359,6 +383,10 @@ void GDAPI godot_packed_vector2_array_append_array(godot_packed_vector2_array *p godot_error GDAPI godot_packed_vector2_array_insert(godot_packed_vector2_array *p_self, const godot_int p_idx, const godot_vector2 *p_data); +godot_bool GDAPI godot_packed_vector2_array_has(godot_packed_vector2_array *p_self, const godot_vector2 *p_value); + +void GDAPI godot_packed_vector2_array_sort(godot_packed_vector2_array *p_self); + void GDAPI godot_packed_vector2_array_invert(godot_packed_vector2_array *p_self); void GDAPI godot_packed_vector2_array_push_back(godot_packed_vector2_array *p_self, const godot_vector2 *p_data); @@ -391,6 +419,10 @@ void GDAPI godot_packed_vector3_array_append_array(godot_packed_vector3_array *p godot_error GDAPI godot_packed_vector3_array_insert(godot_packed_vector3_array *p_self, const godot_int p_idx, const godot_vector3 *p_data); +godot_bool GDAPI godot_packed_vector3_array_has(godot_packed_vector3_array *p_self, const godot_vector3 *p_value); + +void GDAPI godot_packed_vector3_array_sort(godot_packed_vector3_array *p_self); + void GDAPI godot_packed_vector3_array_invert(godot_packed_vector3_array *p_self); void GDAPI godot_packed_vector3_array_push_back(godot_packed_vector3_array *p_self, const godot_vector3 *p_data); @@ -423,6 +455,10 @@ void GDAPI godot_packed_color_array_append_array(godot_packed_color_array *p_sel godot_error GDAPI godot_packed_color_array_insert(godot_packed_color_array *p_self, const godot_int p_idx, const godot_color *p_data); +godot_bool GDAPI godot_packed_color_array_has(godot_packed_color_array *p_self, const godot_color *p_value); + +void GDAPI godot_packed_color_array_sort(godot_packed_color_array *p_self); + void GDAPI godot_packed_color_array_invert(godot_packed_color_array *p_self); void GDAPI godot_packed_color_array_push_back(godot_packed_color_array *p_self, const godot_color *p_data); diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 53e760ffa7..388df63dba 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -55,6 +55,8 @@ Ref<ResourceFormatSaverGDScript> resource_saver_gd; #include "language_server/gdscript_language_server.h" #endif // !GDSCRIPT_NO_LSP +Ref<GDScriptEditorTranslationParserPlugin> gdscript_translation_parser_plugin; + class EditorExportGDScript : public EditorExportPlugin { GDCLASS(EditorExportGDScript, EditorExportPlugin); @@ -167,7 +169,6 @@ void register_gdscript_types() { ScriptEditor::register_create_syntax_highlighter_function(GDScriptSyntaxHighlighter::create); EditorNode::add_init_callback(_editor_init); - Ref<GDScriptEditorTranslationParserPlugin> gdscript_translation_parser_plugin; gdscript_translation_parser_plugin.instance(); EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); #endif // TOOLS_ENABLED @@ -185,4 +186,9 @@ void unregister_gdscript_types() { ResourceSaver::remove_resource_format_saver(resource_saver_gd); resource_saver_gd.unref(); + +#ifdef TOOLS_ENABLED + EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); + gdscript_translation_parser_plugin.unref(); +#endif // TOOLS_ENABLED } diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp index df1547607d..942c6d26a6 100644 --- a/modules/mono/editor/code_completion.cpp +++ b/modules/mono/editor/code_completion.cpp @@ -123,16 +123,11 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr case CompletionKind::NODE_PATHS: { { // AutoLoads - List<PropertyInfo> props; - ProjectSettings::get_singleton()->get_property_list(&props); + Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - String s = E->get().name; - if (!s.begins_with("autoload/")) { - continue; - } - String name = s.get_slice("/", 1); - suggestions.push_back(quoted("/root/" + name)); + for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { + const ProjectSettings::AutoloadInfo &info = E->value(); + suggestions.push_back(quoted("/root/" + String(info.name))); } } diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 4393a4ae9f..038f6e1038 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -92,7 +92,8 @@ class EditorExportPlatformIOS : public EditorExportPlatform { String _get_linker_flags(); String _get_cpp_code(); void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug); - Error _export_loading_screens(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir); + Error _export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir); + Error _export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir); Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir); Vector<ExportArchitecture> _get_supported_architectures(); @@ -255,6 +256,13 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with retina display + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale To Fit,Scale To Fill,Scale"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color())); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "launch_screens/generate_missing"), false)); for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { @@ -274,6 +282,12 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ "ad-hoc", "enterprise" }; + static const String storyboard_image_scale_mode[] = { + "center", + "scaleAspectFit", + "scaleAspectFill", + "scaleToFill" + }; String str; String strnew; str.parse_utf8((const char *)pfile.ptr(), pfile.size()); @@ -390,6 +404,60 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_ } else if (lines[i].find("$photolibrary_usage_description") != -1) { String description = p_preset->get("privacy/photolibrary_usage_description"); strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n"; + } else if (lines[i].find("$plist_launch_screen_name") != -1) { + bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); + String value = is_on ? "<key>UILaunchStoryboardName</key>\n<string>Launch Screen</string>" : ""; + strnew += lines[i].replace("$plist_launch_screen_name", value) + "\n"; + } else if (lines[i].find("$pbx_launch_screen_file_reference") != -1) { + bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); + String value = is_on ? "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"<group>\"; };" : ""; + strnew += lines[i].replace("$pbx_launch_screen_file_reference", value) + "\n"; + } else if (lines[i].find("$pbx_launch_screen_copy_files") != -1) { + bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); + String value = is_on ? "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */," : ""; + strnew += lines[i].replace("$pbx_launch_screen_copy_files", value) + "\n"; + } else if (lines[i].find("$pbx_launch_screen_build_phase") != -1) { + bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); + String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */," : ""; + strnew += lines[i].replace("$pbx_launch_screen_build_phase", value) + "\n"; + } else if (lines[i].find("$pbx_launch_screen_build_reference") != -1) { + bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); + String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };" : ""; + strnew += lines[i].replace("$pbx_launch_screen_build_reference", value) + "\n"; + } else if (lines[i].find("$pbx_launch_image_usage_setting") != -1) { + bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); + String value = is_on ? "" : "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;"; + strnew += lines[i].replace("$pbx_launch_image_usage_setting", value) + "\n"; + } else if (lines[i].find("$launch_screen_image_mode") != -1) { + int image_scale_mode = p_preset->get("storyboard/image_scale_mode"); + String value; + + switch (image_scale_mode) { + case 0: { + String logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image"); + bool is_on = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize"); + // If custom logo is not specified, Godot does not scale default one, so we should do the same. + value = (is_on && logo_path.length() > 0) ? "scaleAspectFit" : "center"; + } break; + default: { + value = storyboard_image_scale_mode[image_scale_mode - 1]; + } + } + + strnew += lines[i].replace("$launch_screen_image_mode", value) + "\n"; + } else if (lines[i].find("$launch_screen_background_color") != -1) { + bool use_custom = p_preset->get("storyboard/use_custom_bg_color"); + Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : ProjectSettings::get_singleton()->get("application/boot_splash/bg_color"); + const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\""; + + Dictionary value_dictionary; + value_dictionary["red"] = color.r; + value_dictionary["green"] = color.g; + value_dictionary["blue"] = color.b; + value_dictionary["alpha"] = color.a; + String value = value_format.format(value_dictionary, "$_"); + + strnew += lines[i].replace("$launch_screen_background_color", value) + "\n"; } else { strnew += lines[i] + "\n"; } @@ -591,7 +659,75 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr return OK; } -Error EditorExportPlatformIOS::_export_loading_screens(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) { +Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) { + const String custom_launch_image_2x = p_preset->get("storyboard/custom_image@2x"); + const String custom_launch_image_3x = p_preset->get("storyboard/custom_image@3x"); + + if (custom_launch_image_2x.length() > 0 && custom_launch_image_3x.length() > 0) { + Ref<Image> image; + String image_path = p_dest_dir.plus_file("splash@2x.png"); + image.instance(); + Error err = image->load(custom_launch_image_2x); + + if (err) { + image.unref(); + return err; + } + + if (image->save_png(image_path) != OK) { + return ERR_FILE_CANT_WRITE; + } + + image.unref(); + image_path = p_dest_dir.plus_file("splash@3x.png"); + image.instance(); + err = image->load(custom_launch_image_3x); + + if (err) { + image.unref(); + return err; + } + + if (image->save_png(image_path) != OK) { + return ERR_FILE_CANT_WRITE; + } + } else { + Ref<Image> splash; + + const String splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image"); + + if (!splash_path.empty()) { + splash.instance(); + const Error err = splash->load(splash_path); + if (err) { + splash.unref(); + } + } + + if (splash.is_null()) { + splash = Ref<Image>(memnew(Image(boot_splash_png))); + } + + // Using same image for both @2x and @3x + // because Godot's own boot logo uses single image for all resolutions. + // Also not using @1x image, because devices using this image variant + // are not supported by iOS 9, which is minimal target. + const String splash_png_path_2x = p_dest_dir.plus_file("splash@2x.png"); + const String splash_png_path_3x = p_dest_dir.plus_file("splash@3x.png"); + + if (splash->save_png(splash_png_path_2x) != OK) { + return ERR_FILE_CANT_WRITE; + } + + if (splash->save_png(splash_png_path_3x) != OK) { + return ERR_FILE_CANT_WRITE; + } + } + + return OK; +} + +Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) { DirAccess *da = DirAccess::open(p_dest_dir); ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'."); @@ -892,6 +1028,8 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, Vector<IOSExportAsset> &r_exported_assets) { DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + String binary_name = p_out_dir.get_file().get_basename(); + ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'."); for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) { String asset = p_assets[f_idx]; @@ -917,32 +1055,35 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir String destination_dir; String destination; String asset_path; + bool create_framework = false; if (p_is_framework && asset.ends_with(".dylib")) { // For iOS we need to turn .dylib into .framework // to be able to send application to AppStore - destination_dir = p_out_dir.plus_file("dylibs").plus_file(base_dir); + asset_path = String("dylibs").plus_file(base_dir); String file_name = asset.get_basename().get_file(); String framework_name = file_name + ".framework"; - destination_dir = destination_dir.plus_file(framework_name); + asset_path = asset_path.plus_file(framework_name); + destination_dir = p_out_dir.plus_file(asset_path); destination = destination_dir.plus_file(file_name); - asset_path = destination_dir; create_framework = true; } else if (p_is_framework && (asset.ends_with(".framework") || asset.ends_with(".xcframework"))) { - destination_dir = p_out_dir.plus_file("dylibs").plus_file(base_dir); + asset_path = String("dylibs").plus_file(base_dir); String file_name = asset.get_file(); - destination = destination_dir.plus_file(file_name); - asset_path = destination; + asset_path = asset_path.plus_file(file_name); + destination_dir = p_out_dir.plus_file(asset_path); + destination = destination_dir; } else { - destination_dir = p_out_dir.plus_file(base_dir); + asset_path = base_dir; String file_name = asset.get_file(); - destination = destination_dir.plus_file(file_name); - asset_path = destination; + destination_dir = p_out_dir.plus_file(asset_path); + asset_path = asset_path.plus_file(file_name); + destination = p_out_dir.plus_file(asset_path); } if (!filesystem_da->dir_exists(destination_dir)) { @@ -960,7 +1101,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir memdelete(filesystem_da); return err; } - IOSExportAsset exported_asset = { asset_path, p_is_framework }; + IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework }; r_exported_assets.push_back(exported_asset); if (create_framework) { @@ -1006,7 +1147,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir String info_plist = info_plist_format.replace("$name", file_name); - FileAccess *f = FileAccess::open(asset_path.plus_file("Info.plist"), FileAccess::WRITE); + FileAccess *f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE); if (f) { f->store_string(info_plist); f->close(); @@ -1172,6 +1313,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p files_to_parse.insert("godot_ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata"); files_to_parse.insert("godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme"); files_to_parse.insert("godot_ios/godot_ios.entitlements"); + files_to_parse.insert("godot_ios/Launch Screen.storyboard"); IOSConfigData config_data = { pkg_name, @@ -1347,7 +1489,43 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p return err; } - err = _export_loading_screens(p_preset, dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/"); + bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard"); + + String launch_image_path = dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/"; + String splash_image_path = dest_dir + binary_name + "/Images.xcassets/SplashImage.imageset/"; + + DirAccess *launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + + if (!launch_screen_da) { + return ERR_CANT_CREATE; + } + + if (use_storyboard) { + print_line("Using Launch Storyboard"); + + if (launch_screen_da->change_dir(launch_image_path) == OK) { + launch_screen_da->erase_contents_recursive(); + launch_screen_da->remove(launch_image_path); + } + + err = _export_loading_screen_file(p_preset, splash_image_path); + } else { + print_line("Using Launch Images"); + + const String launch_screen_path = dest_dir + binary_name + "/Launch Screen.storyboard"; + + launch_screen_da->remove(launch_screen_path); + + if (launch_screen_da->change_dir(splash_image_path) == OK) { + launch_screen_da->erase_contents_recursive(); + launch_screen_da->remove(splash_image_path); + } + + err = _export_loading_screen_images(p_preset, launch_image_path); + } + + memdelete(launch_screen_da); + if (err) { return err; } diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index b7b750a975..07ecd5d2c6 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -2465,7 +2465,7 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent wd_window.transient_parent = INVALID_WINDOW_ID; wd_parent.transient_children.erase(p_window); - [wd_window.window_object setParentWindow:nil]; + [wd_parent.window_object removeChildWindow:wd_window.window_object]; } else { ERR_FAIL_COND(!windows.has(p_parent)); ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent"); @@ -2474,7 +2474,7 @@ void DisplayServerOSX::window_set_transient(WindowID p_window, WindowID p_parent wd_window.transient_parent = p_parent; wd_parent.transient_children.insert(p_window); - [wd_window.window_object setParentWindow:wd_parent.window_object]; + [wd_parent.window_object addChildWindow:wd_window.window_object ordered:NSWindowAbove]; } } diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 40d988ff9f..bf69a8598d 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -84,7 +84,7 @@ void Path3D::_bind_methods() { ////////////// -void PathFollow3D::_update_transform() { +void PathFollow3D::_update_transform(bool p_update_xyz_rot) { if (!path) { return; } @@ -156,45 +156,47 @@ void PathFollow3D::_update_transform() { t.origin = pos; - Vector3 t_prev = (pos - c->interpolate_baked(offset - delta_offset, cubic)).normalized(); - Vector3 t_cur = (c->interpolate_baked(offset + delta_offset, cubic) - pos).normalized(); - - Vector3 axis = t_prev.cross(t_cur); - float dot = t_prev.dot(t_cur); - float angle = Math::acos(CLAMP(dot, -1, 1)); - - if (likely(!Math::is_zero_approx(angle))) { - if (rotation_mode == ROTATION_Y) { - // assuming we're referring to global Y-axis. is this correct? - axis.x = 0; - axis.z = 0; - } else if (rotation_mode == ROTATION_XY) { - axis.z = 0; - } else if (rotation_mode == ROTATION_XYZ) { - // all components are allowed - } + if (p_update_xyz_rot) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree + Vector3 t_prev = (pos - c->interpolate_baked(offset - delta_offset, cubic)).normalized(); + Vector3 t_cur = (c->interpolate_baked(offset + delta_offset, cubic) - pos).normalized(); + + Vector3 axis = t_prev.cross(t_cur); + float dot = t_prev.dot(t_cur); + float angle = Math::acos(CLAMP(dot, -1, 1)); + + if (likely(!Math::is_zero_approx(angle))) { + if (rotation_mode == ROTATION_Y) { + // assuming we're referring to global Y-axis. is this correct? + axis.x = 0; + axis.z = 0; + } else if (rotation_mode == ROTATION_XY) { + axis.z = 0; + } else if (rotation_mode == ROTATION_XYZ) { + // all components are allowed + } - if (likely(!Math::is_zero_approx(axis.length()))) { - t.rotate_basis(axis.normalized(), angle); + if (likely(!Math::is_zero_approx(axis.length()))) { + t.rotate_basis(axis.normalized(), angle); + } } - } - // do the additional tilting - float tilt_angle = c->interpolate_baked_tilt(offset); - Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct?? - - if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) { - if (rotation_mode == ROTATION_Y) { - tilt_axis.x = 0; - tilt_axis.z = 0; - } else if (rotation_mode == ROTATION_XY) { - tilt_axis.z = 0; - } else if (rotation_mode == ROTATION_XYZ) { - // all components are allowed - } + // do the additional tilting + float tilt_angle = c->interpolate_baked_tilt(offset); + Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct?? + + if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) { + if (rotation_mode == ROTATION_Y) { + tilt_axis.x = 0; + tilt_axis.z = 0; + } else if (rotation_mode == ROTATION_XY) { + tilt_axis.z = 0; + } else if (rotation_mode == ROTATION_XYZ) { + // all components are allowed + } - if (likely(!Math::is_zero_approx(tilt_axis.length()))) { - t.rotate_basis(tilt_axis.normalized(), tilt_angle); + if (likely(!Math::is_zero_approx(tilt_axis.length()))) { + t.rotate_basis(tilt_axis.normalized(), tilt_angle); + } } } @@ -213,7 +215,7 @@ void PathFollow3D::_notification(int p_what) { if (parent) { path = Object::cast_to<Path3D>(parent); if (path) { - _update_transform(); + _update_transform(false); } } diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index 7f227a8a6f..9c50bd4906 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -75,7 +75,7 @@ private: bool loop; RotationMode rotation_mode; - void _update_transform(); + void _update_transform(bool p_update_xyz_rot = true); protected: virtual void _validate_property(PropertyInfo &property) const; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index ae30972558..81f33d74fe 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -893,7 +893,12 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) { } if (exclusive_child != nullptr) { - exclusive_child->grab_focus(); + Window *focus_target = exclusive_child; + while (focus_target->exclusive_child != nullptr) { + focus_target->grab_focus(); + focus_target = focus_target->exclusive_child; + } + focus_target->grab_focus(); if (!is_embedding_subwindows()) { //not embedding, no need for event return; diff --git a/thirdparty/misc/stb_vorbis.c b/thirdparty/misc/stb_vorbis.c index b0d79b1724..52c9c666a2 100644 --- a/thirdparty/misc/stb_vorbis.c +++ b/thirdparty/misc/stb_vorbis.c @@ -3630,6 +3630,7 @@ static int start_decoder(vorb *f) //file vendor len = get32_packet(f); f->vendor = (char*)setup_malloc(f, sizeof(char) * (len+1)); + if (f->vendor == NULL) return error(f, VORBIS_outofmem); for(i=0; i < len; ++i) { f->vendor[i] = get8_packet(f); } @@ -3637,10 +3638,12 @@ static int start_decoder(vorb *f) //user comments f->comment_list_length = get32_packet(f); f->comment_list = (char**)setup_malloc(f, sizeof(char*) * (f->comment_list_length)); + if (f->comment_list == NULL) return error(f, VORBIS_outofmem); for(i=0; i < f->comment_list_length; ++i) { len = get32_packet(f); f->comment_list[i] = (char*)setup_malloc(f, sizeof(char) * (len+1)); + if (f->comment_list[i] == NULL) return error(f, VORBIS_outofmem); for(j=0; j < len; ++j) { f->comment_list[i][j] = get8_packet(f); |