diff options
Diffstat (limited to 'core')
50 files changed, 548 insertions, 162 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index f6828ea76a..67de156fc3 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -792,7 +792,7 @@ Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const { size_t imonth = 0; - while (dayno >= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]) { + while ((unsigned long)dayno >= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]) { dayno -= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]; imonth++; } @@ -1093,6 +1093,11 @@ void _OS::alert(const String &p_alert, const String &p_title) { OS::get_singleton()->alert(p_alert, p_title); } +bool _OS::request_permission(const String &p_name) { + + return OS::get_singleton()->request_permission(p_name); +} + _OS *_OS::singleton = NULL; void _OS::_bind_methods() { @@ -1265,6 +1270,8 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_power_seconds_left"), &_OS::get_power_seconds_left); ClassDB::bind_method(D_METHOD("get_power_percent_left"), &_OS::get_power_percent_left); + ClassDB::bind_method(D_METHOD("request_permission", "name"), &_OS::request_permission); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "clipboard"), "set_clipboard", "get_clipboard"); ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen"), "set_current_screen", "get_current_screen"); ADD_PROPERTY(PropertyInfo(Variant::INT, "exit_code"), "set_exit_code", "get_exit_code"); @@ -1901,18 +1908,18 @@ bool _File::file_exists(const String &p_name) const { return FileAccess::exists(p_name); } -void _File::store_var(const Variant &p_var) { +void _File::store_var(const Variant &p_var, bool p_full_objects) { ERR_FAIL_COND(!f); int len; - Error err = encode_variant(p_var, NULL, len); + Error err = encode_variant(p_var, NULL, len, p_full_objects); ERR_FAIL_COND(err != OK); PoolVector<uint8_t> buff; buff.resize(len); PoolVector<uint8_t>::Write w = buff.write(); - err = encode_variant(p_var, &w[0], len); + err = encode_variant(p_var, &w[0], len, p_full_objects); ERR_FAIL_COND(err != OK); w = PoolVector<uint8_t>::Write(); @@ -1920,7 +1927,7 @@ void _File::store_var(const Variant &p_var) { store_buffer(buff); } -Variant _File::get_var() const { +Variant _File::get_var(bool p_allow_objects) const { ERR_FAIL_COND_V(!f, Variant()); uint32_t len = get_32(); @@ -1930,7 +1937,7 @@ Variant _File::get_var() const { PoolVector<uint8_t>::Read r = buff.read(); Variant v; - Error err = decode_variant(v, &r[0], len); + Error err = decode_variant(v, &r[0], len, NULL, p_allow_objects); ERR_FAIL_COND_V(err != OK, Variant()); return v; @@ -1973,7 +1980,7 @@ void _File::_bind_methods() { ClassDB::bind_method(D_METHOD("get_endian_swap"), &_File::get_endian_swap); ClassDB::bind_method(D_METHOD("set_endian_swap", "enable"), &_File::set_endian_swap); ClassDB::bind_method(D_METHOD("get_error"), &_File::get_error); - ClassDB::bind_method(D_METHOD("get_var"), &_File::get_var); + ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &_File::get_var, DEFVAL(false)); ClassDB::bind_method(D_METHOD("store_8", "value"), &_File::store_8); ClassDB::bind_method(D_METHOD("store_16", "value"), &_File::store_16); @@ -1986,7 +1993,7 @@ void _File::_bind_methods() { ClassDB::bind_method(D_METHOD("store_line", "line"), &_File::store_line); ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &_File::store_csv_line, DEFVAL(",")); ClassDB::bind_method(D_METHOD("store_string", "string"), &_File::store_string); - ClassDB::bind_method(D_METHOD("store_var", "value"), &_File::store_var); + ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &_File::store_var, DEFVAL(false)); ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &_File::store_pascal_string); ClassDB::bind_method(D_METHOD("get_pascal_string"), &_File::get_pascal_string); @@ -2216,17 +2223,17 @@ _Marshalls *_Marshalls::get_singleton() { return singleton; } -String _Marshalls::variant_to_base64(const Variant &p_var) { +String _Marshalls::variant_to_base64(const Variant &p_var, bool p_full_objects) { int len; - Error err = encode_variant(p_var, NULL, len); + Error err = encode_variant(p_var, NULL, len, p_full_objects); ERR_FAIL_COND_V(err != OK, ""); PoolVector<uint8_t> buff; buff.resize(len); PoolVector<uint8_t>::Write w = buff.write(); - err = encode_variant(p_var, &w[0], len); + err = encode_variant(p_var, &w[0], len, p_full_objects); ERR_FAIL_COND_V(err != OK, ""); int b64len = len / 3 * 4 + 4 + 1; @@ -2242,7 +2249,7 @@ String _Marshalls::variant_to_base64(const Variant &p_var) { return ret; }; -Variant _Marshalls::base64_to_variant(const String &p_str) { +Variant _Marshalls::base64_to_variant(const String &p_str, bool p_allow_objects) { int strlen = p_str.length(); CharString cstr = p_str.ascii(); @@ -2254,7 +2261,7 @@ Variant _Marshalls::base64_to_variant(const String &p_str) { int len = base64_decode((char *)(&w[0]), (char *)cstr.get_data(), strlen); Variant v; - Error err = decode_variant(v, &w[0], len); + Error err = decode_variant(v, &w[0], len, NULL, p_allow_objects); ERR_FAIL_COND_V(err != OK, Variant()); return v; @@ -2333,8 +2340,8 @@ String _Marshalls::base64_to_utf8(const String &p_str) { void _Marshalls::_bind_methods() { - ClassDB::bind_method(D_METHOD("variant_to_base64", "variant"), &_Marshalls::variant_to_base64); - ClassDB::bind_method(D_METHOD("base64_to_variant", "base64_str"), &_Marshalls::base64_to_variant); + ClassDB::bind_method(D_METHOD("variant_to_base64", "variant", "full_objects"), &_Marshalls::variant_to_base64, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("base64_to_variant", "base64_str", "allow_objects"), &_Marshalls::base64_to_variant, DEFVAL(false)); ClassDB::bind_method(D_METHOD("raw_to_base64", "array"), &_Marshalls::raw_to_base64); ClassDB::bind_method(D_METHOD("base64_to_raw", "base64_str"), &_Marshalls::base64_to_raw); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index f3bc4644d8..1c26d9b144 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -356,6 +356,8 @@ public: bool has_feature(const String &p_feature) const; + bool request_permission(const String &p_name); + static _OS *get_singleton() { return singleton; } _OS(); @@ -461,7 +463,7 @@ public: double get_double() const; real_t get_real() const; - Variant get_var() const; + Variant get_var(bool p_allow_objects = false) const; PoolVector<uint8_t> get_buffer(int p_length) const; ///< get an array of bytes String get_line() const; @@ -498,7 +500,7 @@ public: void store_buffer(const PoolVector<uint8_t> &p_buffer); ///< store an array of bytes - void store_var(const Variant &p_var); + void store_var(const Variant &p_var, bool p_full_objects = false); bool file_exists(const String &p_name) const; ///< return true if a file exists @@ -567,8 +569,8 @@ protected: public: static _Marshalls *get_singleton(); - String variant_to_base64(const Variant &p_var); - Variant base64_to_variant(const String &p_str); + String variant_to_base64(const Variant &p_var, bool p_full_objects = false); + Variant base64_to_variant(const String &p_str, bool p_allow_objects = false); String raw_to_base64(const PoolVector<uint8_t> &p_arr); PoolVector<uint8_t> base64_to_raw(const String &p_str); diff --git a/core/error_macros.h b/core/error_macros.h index 3aa8ed4596..ca5ccd24cf 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -310,6 +310,16 @@ extern bool _err_error_exists; _err_error_exists = false; \ } +#define ERR_PRINT_ONCE(m_string) \ + { \ + static bool first_print = true; \ + if (first_print) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_string); \ + _err_error_exists = false; \ + first_print = false; \ + } \ + } + /** Print a warning string. */ @@ -325,6 +335,16 @@ extern bool _err_error_exists; _err_error_exists = false; \ } +#define WARN_PRINT_ONCE(m_string) \ + { \ + static bool first_print = true; \ + if (first_print) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_string, ERR_HANDLER_WARNING); \ + _err_error_exists = false; \ + first_print = false; \ + } \ + } + #define WARN_DEPRECATED \ { \ static volatile bool warning_shown = false; \ diff --git a/core/image.cpp b/core/image.cpp index 5a287ca50e..f547d7e973 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -735,6 +735,10 @@ static void _overlay(const uint8_t *__restrict p_src, uint8_t *__restrict p_dst, } } +bool Image::is_size_po2() const { + return uint32_t(width) == next_power_of_2(width) && uint32_t(height) == next_power_of_2(height); +} + void Image::resize_to_po2(bool p_square) { if (!_can_modify(format)) { diff --git a/core/image.h b/core/image.h index 872b84d565..69a42f169a 100644 --- a/core/image.h +++ b/core/image.h @@ -223,6 +223,7 @@ public: void resize(int p_width, int p_height, Interpolation p_interpolation = INTERPOLATE_BILINEAR); void shrink_x2(); void expand_x2_hq2x(); + bool is_size_po2() const; /** * Crop the image to a specific size, if larger, then the image is filled by black */ diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index c97b8cafac..d38d09c6bb 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -272,7 +272,7 @@ int FileAccessPack::get_buffer(uint8_t *p_dst, int p_length) const { if (eof) return 0; - int64_t to_read = p_length; + uint64_t to_read = p_length; if (to_read + pos > pf.size) { eof = true; to_read = int64_t(pf.size) - int64_t(pos); diff --git a/core/io/logger.cpp b/core/io/logger.cpp index eeb82bfce4..9175f6a262 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -39,7 +39,7 @@ // va_copy, otherwise you have to use the internal version (__va_copy). #if !defined(va_copy) #if defined(__GNUC__) -#define va_copy(d, s) __va_copy(d, s) +#define va_copy(d, s) __va_copy((d), (s)) #else #define va_copy(d, s) ((d) = (s)) #endif diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 5087a63b68..363460311c 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -794,7 +794,7 @@ static void _encode_string(const String &p_string, uint8_t *&buf, int &r_len) { } } -Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_object_as_id) { +Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects) { uint8_t *buf = r_buffer; @@ -819,7 +819,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } } break; case Variant::OBJECT: { - if (p_object_as_id) { + if (!p_full_objects) { flags |= ENCODE_FLAG_OBJECT_AS_ID; } } break; @@ -1086,22 +1086,8 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } break; case Variant::OBJECT: { - if (p_object_as_id) { + if (p_full_objects) { - if (buf) { - - Object *obj = p_variant; - ObjectID id = 0; - if (obj && ObjectDB::instance_validate(obj)) { - id = obj->get_instance_id(); - } - - encode_uint64(id, buf); - } - - r_len += 8; - - } else { Object *obj = p_variant; if (!obj) { if (buf) { @@ -1139,7 +1125,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo _encode_string(E->get().name, buf, r_len); int len; - Error err = encode_variant(obj->get(E->get().name), buf, len, p_object_as_id); + Error err = encode_variant(obj->get(E->get().name), buf, len, p_full_objects); if (err) return err; ERR_FAIL_COND_V(len % 4, ERR_BUG); @@ -1148,6 +1134,19 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo buf += len; } } + } else { + if (buf) { + + Object *obj = p_variant; + ObjectID id = 0; + if (obj && ObjectDB::instance_validate(obj)) { + id = obj->get_instance_id(); + } + + encode_uint64(id, buf); + } + + r_len += 8; } } break; @@ -1180,14 +1179,14 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len++; //pad */ int len; - encode_variant(E->get(), buf, len, p_object_as_id); + encode_variant(E->get(), buf, len, p_full_objects); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) buf += len; Variant *v = d.getptr(E->get()); ERR_FAIL_COND_V(!v, ERR_BUG); - encode_variant(*v, buf, len, p_object_as_id); + encode_variant(*v, buf, len, p_full_objects); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) @@ -1209,7 +1208,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo for (int i = 0; i < v.size(); i++) { int len; - encode_variant(v.get(i), buf, len, p_object_as_id); + encode_variant(v.get(i), buf, len, p_full_objects); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; if (buf) diff --git a/core/io/marshalls.h b/core/io/marshalls.h index 11c4b2c98e..f361c29754 100644 --- a/core/io/marshalls.h +++ b/core/io/marshalls.h @@ -199,7 +199,7 @@ public: EncodedObjectAsID(); }; -Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL, bool p_allow_objects = true); -Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_object_as_id = false); +Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = NULL, bool p_allow_objects = false); +Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_full_objects = false); #endif diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 7680d47620..f74f076c65 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -46,7 +46,8 @@ _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_mas case MultiplayerAPI::RPC_MODE_MASTERSYNC: { if (is_master) r_skip_rpc = true; // I am the master, so skip remote call. - } // Do not break, fall over to other sync. + FALLTHROUGH; + } case MultiplayerAPI::RPC_MODE_REMOTESYNC: case MultiplayerAPI::RPC_MODE_PUPPETSYNC: { // Call it, sync always results in a local call. @@ -64,7 +65,7 @@ _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_mas return false; } -_FORCE_INLINE_ bool _can_call_mode(Node *p_node, MultiplayerAPI::RPCMode mode, int p_remote_id) { +_FORCE_INLINE_ bool _can_call_mode(MultiplayerAPI::RPCMode mode, int p_node_master, int p_remote_id) { switch (mode) { case MultiplayerAPI::RPC_MODE_DISABLED: { @@ -76,11 +77,11 @@ _FORCE_INLINE_ bool _can_call_mode(Node *p_node, MultiplayerAPI::RPCMode mode, i } break; case MultiplayerAPI::RPC_MODE_MASTERSYNC: case MultiplayerAPI::RPC_MODE_MASTER: { - return p_node->is_network_master(); + return p_node_master == NetworkedMultiplayerPeer::TARGET_PEER_SERVER; } break; case MultiplayerAPI::RPC_MODE_PUPPETSYNC: case MultiplayerAPI::RPC_MODE_PUPPET: { - return !p_node->is_network_master() && p_remote_id == p_node->get_network_master(); + return p_node_master != NetworkedMultiplayerPeer::TARGET_PEER_SERVER && p_remote_id == p_node_master; } break; } @@ -282,8 +283,9 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_name); } - ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); - ERR_FAIL_COND(!_can_call_mode(p_node, rpc_mode, p_from)); + int node_master_id = p_node->get_network_master(); + ERR_EXPLAIN("RPC '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(node_master_id) + "."); + ERR_FAIL_COND(!_can_call_mode(rpc_mode, p_from, node_master_id)); int argc = p_packet[p_offset]; Vector<Variant> args; @@ -299,7 +301,7 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ ERR_FAIL_COND(p_offset >= p_packet_len); int vlen; - Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen); + Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Invalid packet received. Unable to decode RPC argument."); ERR_FAIL_COND(err != OK); @@ -331,11 +333,12 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p rset_mode = p_node->get_script_instance()->get_rset_mode(p_name); } - ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + "."); - ERR_FAIL_COND(!_can_call_mode(p_node, rset_mode, p_from)); + int node_master_id = p_node->get_network_master(); + ERR_EXPLAIN("RSET '" + String(p_name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(node_master_id) + "."); + ERR_FAIL_COND(!_can_call_mode(rset_mode, p_from, node_master_id)); Variant value; - Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset); + Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Invalid packet received. Unable to decode RSET value."); ERR_FAIL_COND(err != OK); @@ -526,11 +529,11 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p if (p_set) { // Set argument. - Error err = encode_variant(*p_arg[0], NULL, len); + Error err = encode_variant(*p_arg[0], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); - encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len); + encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ofs += len; } else { @@ -539,11 +542,11 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p packet_cache.write[ofs] = p_argcount; ofs += 1; for (int i = 0; i < p_argcount; i++) { - Error err = encode_variant(*p_arg[i], NULL, len); + Error err = encode_variant(*p_arg[i], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ERR_EXPLAIN("Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); ERR_FAIL_COND(err != OK); MAKE_ROOM(ofs + len); - encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len); + encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ofs += len; } } @@ -818,6 +821,16 @@ Vector<int> MultiplayerAPI::get_network_connected_peers() const { return ret; } +void MultiplayerAPI::set_allow_object_decoding(bool p_enable) { + + allow_object_decoding = p_enable; +} + +bool MultiplayerAPI::is_object_decoding_allowed() const { + + return allow_object_decoding; +} + void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE)); @@ -838,6 +851,10 @@ void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &MultiplayerAPI::get_network_connected_peers); ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &MultiplayerAPI::set_refuse_new_network_connections); ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &MultiplayerAPI::is_refusing_new_network_connections); + ClassDB::bind_method(D_METHOD("set_allow_object_decoding", "enable"), &MultiplayerAPI::set_allow_object_decoding); + ClassDB::bind_method(D_METHOD("is_object_decoding_allowed"), &MultiplayerAPI::is_object_decoding_allowed); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); @@ -859,7 +876,8 @@ void MultiplayerAPI::_bind_methods() { BIND_ENUM_CONSTANT(RPC_MODE_PUPPETSYNC); } -MultiplayerAPI::MultiplayerAPI() { +MultiplayerAPI::MultiplayerAPI() : + allow_object_decoding(false) { rpc_sender_id = 0; root_node = NULL; clear(); diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index a9cf77aaba..779dd043bd 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -63,6 +63,7 @@ private: int last_send_cache_id; Vector<uint8_t> packet_cache; Node *root_node; + bool allow_object_decoding; protected: static void _bind_methods(); @@ -126,6 +127,9 @@ public: void set_refuse_new_network_connections(bool p_refuse); bool is_refusing_new_network_connections() const; + void set_allow_object_decoding(bool p_enable); + bool is_object_decoding_allowed() const; + MultiplayerAPI(); ~MultiplayerAPI(); }; diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index d7bfdbbb37..c77c81f9e2 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -79,7 +79,7 @@ Error PacketPeer::put_packet_buffer(const PoolVector<uint8_t> &p_buffer) { return put_packet(&r[0], len); } -Error PacketPeer::get_var(Variant &r_variant) { +Error PacketPeer::get_var(Variant &r_variant, bool p_allow_objects) { const uint8_t *buffer; int buffer_size; @@ -87,13 +87,13 @@ Error PacketPeer::get_var(Variant &r_variant) { if (err) return err; - return decode_variant(r_variant, buffer, buffer_size, NULL, allow_object_decoding); + return decode_variant(r_variant, buffer, buffer_size, NULL, p_allow_objects || allow_object_decoding); } -Error PacketPeer::put_var(const Variant &p_packet) { +Error PacketPeer::put_var(const Variant &p_packet, bool p_full_objects) { int len; - Error err = encode_variant(p_packet, NULL, len, !allow_object_decoding); // compute len first + Error err = encode_variant(p_packet, NULL, len, p_full_objects || allow_object_decoding); // compute len first if (err) return err; @@ -102,15 +102,15 @@ Error PacketPeer::put_var(const Variant &p_packet) { uint8_t *buf = (uint8_t *)alloca(len); ERR_FAIL_COND_V(!buf, ERR_OUT_OF_MEMORY); - err = encode_variant(p_packet, buf, len, !allow_object_decoding); + err = encode_variant(p_packet, buf, len, p_full_objects || allow_object_decoding); ERR_FAIL_COND_V(err, err); return put_packet(buf, len); } -Variant PacketPeer::_bnd_get_var() { +Variant PacketPeer::_bnd_get_var(bool p_allow_objects) { Variant var; - get_var(var); + get_var(var, p_allow_objects); return var; }; @@ -132,8 +132,8 @@ Error PacketPeer::_get_packet_error() const { void PacketPeer::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_var"), &PacketPeer::_bnd_get_var); - ClassDB::bind_method(D_METHOD("put_var", "var"), &PacketPeer::put_var); + ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &PacketPeer::_bnd_get_var, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("put_var", "var", "full_objects"), &PacketPeer::put_var, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_packet"), &PacketPeer::_get_packet); ClassDB::bind_method(D_METHOD("put_packet", "buffer"), &PacketPeer::_put_packet); ClassDB::bind_method(D_METHOD("get_packet_error"), &PacketPeer::_get_packet_error); diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h index 48c50eb76b..6475e4fed9 100644 --- a/core/io/packet_peer.h +++ b/core/io/packet_peer.h @@ -39,8 +39,7 @@ class PacketPeer : public Reference { GDCLASS(PacketPeer, Reference); - Variant _bnd_get_var(); - void _bnd_put_var(const Variant &p_var); + Variant _bnd_get_var(bool p_allow_objects = false); static void _bind_methods(); @@ -64,8 +63,8 @@ public: virtual Error get_packet_buffer(PoolVector<uint8_t> &r_buffer); virtual Error put_packet_buffer(const PoolVector<uint8_t> &p_buffer); - virtual Error get_var(Variant &r_variant); - virtual Error put_var(const Variant &p_packet); + virtual Error get_var(Variant &r_variant, bool p_allow_objects = false); + virtual Error put_var(const Variant &p_packet, bool p_full_objects = false); void set_allow_object_decoding(bool p_enable); bool is_object_decoding_allowed() const; diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index 69907a710a..b5fa412576 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -183,6 +183,11 @@ void ResourceFormatImporter::get_recognized_extensions_for_type(const String &p_ } } +bool ResourceFormatImporter::exists(const String &p_path) const { + + return FileAccess::exists(p_path + ".import"); +} + bool ResourceFormatImporter::recognize_path(const String &p_path, const String &p_for_type) const { return FileAccess::exists(p_path + ".import"); diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index 1d27d4dec3..1c146c33d7 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -68,6 +68,8 @@ public: virtual Variant get_resource_metadata(const String &p_path) const; virtual bool is_import_valid(const String &p_path) const; virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); + virtual bool is_imported(const String &p_path) const { return recognize_path(p_path); } + virtual bool exists(const String &p_path) const; virtual bool can_be_imported(const String &p_path) const; virtual int get_import_order(const String &p_path) const; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 98309048bb..e4b694b64f 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -633,6 +633,31 @@ bool ResourceLoader::is_import_valid(const String &p_path) { return false; //not found } +bool ResourceLoader::is_imported(const String &p_path) { + + String path = _path_remap(p_path); + + String local_path; + if (path.is_rel_path()) + local_path = "res://" + path; + else + local_path = ProjectSettings::get_singleton()->localize_path(path); + + for (int i = 0; i < loader_count; i++) { + + if (!loader[i]->recognize_path(local_path)) + continue; + /* + if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) + continue; + */ + + return loader[i]->is_imported(p_path); + } + + return false; //not found +} + void ResourceLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { String path = _path_remap(p_path); @@ -921,7 +946,7 @@ void ResourceLoader::add_custom_loaders() { for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { StringName class_name = E->get(); - StringName base_class = ScriptServer::get_global_class_base(class_name); + StringName base_class = ScriptServer::get_global_class_native_base(class_name); if (base_class == custom_loader_base_class) { String path = ScriptServer::get_global_class_path(class_name); diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 70eb1a3de0..ca7610a0d2 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -79,6 +79,7 @@ public: virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map); virtual bool is_import_valid(const String &p_path) const { return true; } + virtual bool is_imported(const String &p_path) const { return false; } virtual int get_import_order(const String &p_path) const { return 0; } virtual ~ResourceFormatLoader() {} @@ -154,6 +155,7 @@ public: static void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); static Error rename_dependencies(const String &p_path, const Map<String, String> &p_map); static bool is_import_valid(const String &p_path); + static bool is_imported(const String &p_path); static int get_import_order(const String &p_path); static void set_timestamp_on_load(bool p_timestamp) { timestamp_on_load = p_timestamp; } diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index c992e2bf94..0cecca904d 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -249,7 +249,7 @@ void ResourceSaver::add_custom_savers() { for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { StringName class_name = E->get(); - StringName base_class = ScriptServer::get_global_class_base(class_name); + StringName base_class = ScriptServer::get_global_class_native_base(class_name); if (base_class == custom_saver_base_class) { String path = ScriptServer::get_global_class_path(class_name); diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp index 3042c0f60a..6ad24a5f3a 100644 --- a/core/io/stream_peer.cpp +++ b/core/io/stream_peer.cpp @@ -221,14 +221,14 @@ void StreamPeer::put_utf8_string(const String &p_string) { put_u32(cs.length()); put_data((const uint8_t *)cs.get_data(), cs.length()); } -void StreamPeer::put_var(const Variant &p_variant) { +void StreamPeer::put_var(const Variant &p_variant, bool p_full_objects) { int len = 0; Vector<uint8_t> buf; - encode_variant(p_variant, NULL, len); + encode_variant(p_variant, NULL, len, p_full_objects); buf.resize(len); put_32(len); - encode_variant(p_variant, buf.ptrw(), len); + encode_variant(p_variant, buf.ptrw(), len, p_full_objects); put_data(buf.ptr(), buf.size()); } @@ -359,7 +359,7 @@ String StreamPeer::get_utf8_string(int p_bytes) { ret.parse_utf8((const char *)buf.ptr(), buf.size()); return ret; } -Variant StreamPeer::get_var() { +Variant StreamPeer::get_var(bool p_allow_objects) { int len = get_32(); Vector<uint8_t> var; @@ -369,7 +369,7 @@ Variant StreamPeer::get_var() { ERR_FAIL_COND_V(err != OK, Variant()); Variant ret; - decode_variant(ret, var.ptr(), len); + decode_variant(ret, var.ptr(), len, NULL, p_allow_objects); return ret; } @@ -398,7 +398,7 @@ void StreamPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("put_double", "value"), &StreamPeer::put_double); ClassDB::bind_method(D_METHOD("put_string", "value"), &StreamPeer::put_string); ClassDB::bind_method(D_METHOD("put_utf8_string", "value"), &StreamPeer::put_utf8_string); - ClassDB::bind_method(D_METHOD("put_var", "value"), &StreamPeer::put_var); + ClassDB::bind_method(D_METHOD("put_var", "value", "full_objects"), &StreamPeer::put_var, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_8"), &StreamPeer::get_8); ClassDB::bind_method(D_METHOD("get_u8"), &StreamPeer::get_u8); @@ -412,7 +412,7 @@ void StreamPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_double"), &StreamPeer::get_double); ClassDB::bind_method(D_METHOD("get_string", "bytes"), &StreamPeer::get_string, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_utf8_string", "bytes"), &StreamPeer::get_utf8_string, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("get_var"), &StreamPeer::get_var); + ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &StreamPeer::get_var, DEFVAL(false)); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian_enabled"); } diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h index 059ccd016c..65e70995ad 100644 --- a/core/io/stream_peer.h +++ b/core/io/stream_peer.h @@ -73,7 +73,7 @@ public: void put_double(double p_val); void put_string(const String &p_string); void put_utf8_string(const String &p_string); - void put_var(const Variant &p_variant); + void put_var(const Variant &p_variant, bool p_full_objects = false); uint8_t get_u8(); int8_t get_8(); @@ -87,7 +87,7 @@ public: double get_double(); String get_string(int p_bytes = -1); String get_utf8_string(int p_bytes = -1); - Variant get_var(); + Variant get_var(bool p_allow_objects = false); StreamPeer() { big_endian = false; } }; diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 8816e3639a..82b2f7006d 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -557,11 +557,23 @@ void Basis::set_euler_yxz(const Vector3 &p_euler) { *this = ymat * xmat * zmat; } -bool Basis::is_equal_approx(const Basis &a, const Basis &b) const { +bool Basis::is_equal_approx(const Basis &a, const Basis &b,real_t p_epsilon) const { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - if (!Math::is_equal_approx_ratio(a.elements[i][j], b.elements[i][j], UNIT_EPSILON)) + if (!Math::is_equal_approx(a.elements[i][j], b.elements[i][j], p_epsilon)) + return false; + } + } + + return true; +} + +bool Basis::is_equal_approx_ratio(const Basis &a, const Basis &b,real_t p_epsilon) const { + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (!Math::is_equal_approx_ratio(a.elements[i][j], b.elements[i][j], p_epsilon)) return false; } } @@ -605,12 +617,14 @@ Basis::operator String() const { Quat Basis::get_quat() const { +#ifdef MATH_CHECKS + if (!is_rotation()) { + ERR_EXPLAIN("Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quat() or call orthonormalized() instead."); + ERR_FAIL_V(Quat()); + } +#endif /* Allow getting a quaternion from an unnormalized transform */ Basis m = *this; - m.elements[0].normalize(); - m.elements[1].normalize(); - m.elements[2].normalize(); - real_t trace = m.elements[0][0] + m.elements[1][1] + m.elements[2][2]; real_t temp[4]; diff --git a/core/math/basis.h b/core/math/basis.h index 128e56b494..aa0ddb280f 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -133,7 +133,8 @@ public: return elements[0][2] * v[0] + elements[1][2] * v[1] + elements[2][2] * v[2]; } - bool is_equal_approx(const Basis &a, const Basis &b) const; + bool is_equal_approx(const Basis &a, const Basis &b, real_t p_epsilon=CMP_EPSILON) const; + bool is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon=UNIT_EPSILON) const; bool operator==(const Basis &p_matrix) const; bool operator!=(const Basis &p_matrix) const; diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 99251d80e3..708054e4ab 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -164,10 +164,10 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) { case TEXT_PRINTRAW: case VAR_TO_STR: case STR_TO_VAR: - case VAR_TO_BYTES: - case BYTES_TO_VAR: case TYPE_EXISTS: return 1; + case VAR_TO_BYTES: + case BYTES_TO_VAR: case MATH_ATAN2: case MATH_FMOD: case MATH_FPOSMOD: @@ -696,8 +696,9 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant case VAR_TO_BYTES: { PoolByteArray barr; + bool full_objects = *p_inputs[1]; int len; - Error err = encode_variant(*p_inputs[0], NULL, len); + Error err = encode_variant(*p_inputs[0], NULL, len, full_objects); if (err) { r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; @@ -709,7 +710,7 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant barr.resize(len); { PoolByteArray::Write w = barr.write(); - encode_variant(*p_inputs[0], w.ptr(), len); + encode_variant(*p_inputs[0], w.ptr(), len, full_objects); } *r_return = barr; } break; @@ -724,10 +725,11 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant } PoolByteArray varr = *p_inputs[0]; + bool allow_objects = *p_inputs[1]; Variant ret; { PoolByteArray::Read r = varr.read(); - Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); + Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects); if (err != OK) { r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format."); r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp index 12c88f43b3..a84b5a16c7 100644 --- a/core/math/geometry.cpp +++ b/core/math/geometry.cpp @@ -31,6 +31,7 @@ #include "geometry.h" #include "core/print_string.h" +#include "thirdparty/misc/triangulator.h" /* this implementation is very inefficient, commenting unless bugs happen. See the other one. bool Geometry::is_point_in_polygon(const Vector2 &p_point, const Vector<Vector2> &p_polygon) { @@ -514,7 +515,7 @@ static inline void _build_faces(uint8_t ***p_cell_status, int x, int y, int z, i Vector3(1,1,1), }; */ -#define vert(m_idx) Vector3((m_idx & 4) >> 2, (m_idx & 2) >> 1, m_idx & 1) +#define vert(m_idx) Vector3(((m_idx)&4) >> 2, ((m_idx)&2) >> 1, (m_idx)&1) static const uint8_t indices[6][4] = { { 7, 6, 4, 5 }, @@ -737,6 +738,40 @@ PoolVector<Face3> Geometry::wrap_geometry(PoolVector<Face3> p_array, real_t *p_e return wrapped_faces; } +Vector<Vector<Vector2> > Geometry::decompose_polygon_in_convex(Vector<Point2> polygon) { + Vector<Vector<Vector2> > decomp; + List<TriangulatorPoly> in_poly, out_poly; + + TriangulatorPoly inp; + inp.Init(polygon.size()); + for (int i = 0; i < polygon.size(); i++) { + inp.GetPoint(i) = polygon[i]; + } + inp.SetOrientation(TRIANGULATOR_CCW); + in_poly.push_back(inp); + TriangulatorPartition tpart; + if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed! + ERR_PRINT("Convex decomposing failed!"); + return decomp; + } + + decomp.resize(out_poly.size()); + int idx = 0; + for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) { + TriangulatorPoly &tp = I->get(); + + decomp.write[idx].resize(tp.GetNumPoints()); + + for (int i = 0; i < tp.GetNumPoints(); i++) { + decomp.write[idx].write[i] = tp.GetPoint(i); + } + + idx++; + } + + return decomp; +} + Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes) { MeshData mesh; diff --git a/core/math/geometry.h b/core/math/geometry.h index f927a63ed5..4b478b6b16 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -950,6 +950,8 @@ public: return H; } + static Vector<Vector<Vector2> > decompose_polygon_in_convex(Vector<Point2> polygon); + static MeshData build_convex_mesh(const PoolVector<Plane> &p_planes); static PoolVector<Plane> build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis = Vector3::AXIS_Z); static PoolVector<Plane> build_box_planes(const Vector3 &p_extents); diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 17112d8940..6ac6839827 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -249,11 +249,11 @@ public: static float random(float from, float to); static real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); } - static _ALWAYS_INLINE_ bool is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON) { + static _ALWAYS_INLINE_ bool is_equal_approx_ratio(real_t a, real_t b, real_t epsilon = CMP_EPSILON, real_t min_epsilon = CMP_EPSILON) { // this is an approximate way to check that numbers are close, as a ratio of their average size // helps compare approximate numbers that may be very big or very small real_t diff = abs(a - b); - if (diff == 0.0) { + if (diff == 0.0 || diff < min_epsilon) { return true; } real_t avg_size = (abs(a) + abs(b)) / 2.0; diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index bc2b4e6fe0..fc2eb1454d 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -36,8 +36,6 @@ uint32_t QuickHull::debug_stop_after = 0xFFFFFFFF; Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_mesh) { - static const real_t over_tolerance = 0.0001; - /* CREATE AABB VOLUME */ AABB aabb; @@ -180,6 +178,8 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me faces.push_back(f); } + real_t over_tolerance = 3 * UNIT_EPSILON * (aabb.size.x + aabb.size.y + aabb.size.z); + /* COMPUTE AVAILABLE VERTICES */ for (int i = 0; i < p_points.size(); i++) { diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h index 2e659cab6e..a445a47cbe 100644 --- a/core/math/quick_hull.h +++ b/core/math/quick_hull.h @@ -64,7 +64,7 @@ public: struct Face { Plane plane; - int vertices[3]; + uint32_t vertices[3]; Vector<int> points_over; bool operator<(const Face &p_face) const { diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp index 8bbcca88fe..8351bd138e 100644 --- a/core/math/random_pcg.cpp +++ b/core/math/random_pcg.cpp @@ -32,24 +32,24 @@ #include "core/os/os.h" -RandomPCG::RandomPCG(uint64_t seed, uint64_t inc) : - pcg() { - pcg.state = seed; - pcg.inc = inc; +RandomPCG::RandomPCG(uint64_t p_seed, uint64_t p_inc) : + pcg(), + current_inc(p_inc) { + seed(p_seed); } void RandomPCG::randomize() { seed(OS::get_singleton()->get_ticks_usec() * pcg.state + PCG_DEFAULT_INC_64); } -double RandomPCG::random(double from, double to) { +double RandomPCG::random(double p_from, double p_to) { unsigned int r = rand(); double ret = (double)r / (double)RANDOM_MAX; - return (ret) * (to - from) + from; + return (ret) * (p_to - p_from) + p_from; } -float RandomPCG::random(float from, float to) { +float RandomPCG::random(float p_from, float p_to) { unsigned int r = rand(); float ret = (float)r / (float)RANDOM_MAX; - return (ret) * (to - from) + from; + return (ret) * (p_to - p_from) + p_from; } diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h index 2a69d43904..cd721ef4d1 100644 --- a/core/math/random_pcg.h +++ b/core/math/random_pcg.h @@ -37,28 +37,33 @@ class RandomPCG { pcg32_random_t pcg; + uint64_t current_seed; // seed with this to get the same state + uint64_t current_inc; public: static const uint64_t DEFAULT_SEED = 12047754176567800795U; static const uint64_t DEFAULT_INC = PCG_DEFAULT_INC_64; static const uint64_t RANDOM_MAX = 0xFFFFFFFF; - RandomPCG(uint64_t seed = DEFAULT_SEED, uint64_t inc = PCG_DEFAULT_INC_64); + RandomPCG(uint64_t p_seed = DEFAULT_SEED, uint64_t p_inc = DEFAULT_INC); - _FORCE_INLINE_ void seed(uint64_t seed) { - pcg.state = seed; - pcg32_random_r(&pcg); // Force changing internal state to avoid initial 0 + _FORCE_INLINE_ void seed(uint64_t p_seed) { + current_seed = p_seed; + pcg32_srandom_r(&pcg, current_seed, current_inc); } - _FORCE_INLINE_ uint64_t get_seed() { return pcg.state; } + _FORCE_INLINE_ uint64_t get_seed() { return current_seed; } void randomize(); - _FORCE_INLINE_ uint32_t rand() { return pcg32_random_r(&pcg); } + _FORCE_INLINE_ uint32_t rand() { + current_seed = pcg.state; + return pcg32_random_r(&pcg); + } _FORCE_INLINE_ double randd() { return (double)rand() / (double)RANDOM_MAX; } _FORCE_INLINE_ float randf() { return (float)rand() / (float)RANDOM_MAX; } - double random(double from, double to); - float random(float from, float to); - real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); } + double random(double p_from, double p_to); + float random(float p_from, float p_to); + real_t random(int p_from, int p_to) { return (real_t)random((real_t)p_from, (real_t)p_to); } }; #endif // RANDOM_PCG_H diff --git a/core/object.cpp b/core/object.cpp index c46ecc5193..8b693f039c 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -832,23 +832,22 @@ void Object::setvar(const Variant &p_key, const Variant &p_value, bool *r_valid) } Variant Object::callv(const StringName &p_method, const Array &p_args) { + const Variant **argptrs = NULL; - if (p_args.size() == 0) { - return call(p_method); - } - - Vector<Variant> args; - args.resize(p_args.size()); - Vector<const Variant *> argptrs; - argptrs.resize(p_args.size()); - - for (int i = 0; i < p_args.size(); i++) { - args.write[i] = p_args[i]; - argptrs.write[i] = &args[i]; + if (p_args.size() > 0) { + argptrs = (const Variant **)alloca(sizeof(Variant *) * p_args.size()); + for (int i = 0; i < p_args.size(); i++) { + argptrs[i] = &p_args[i]; + } } Variant::CallError ce; - return call(p_method, (const Variant **)argptrs.ptr(), p_args.size(), ce); + Variant ret = call(p_method, argptrs, p_args.size(), ce); + if (ce.error != Variant::CallError::CALL_OK) { + ERR_EXPLAIN("Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce)); + ERR_FAIL_V(Variant()); + } + return ret; } Variant Object::call(const StringName &p_name, VARIANT_ARG_DECLARE) { diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index d1f8236898..39d9f45bd7 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -409,6 +409,23 @@ int FileAccess::get_buffer(uint8_t *p_dst, int p_length) const { return i; } +String FileAccess::get_as_utf8_string() const { + PoolVector<uint8_t> sourcef; + int len = get_len(); + sourcef.resize(len + 1); + + PoolVector<uint8_t>::Write w = sourcef.write(); + int r = get_buffer(w.ptr(), len); + ERR_FAIL_COND_V(r != len, String()); + w[len] = 0; + + String s; + if (s.parse_utf8((const char *)w.ptr())) { + return String(); + } + return s; +} + void FileAccess::store_16(uint16_t p_dest) { uint8_t a, b; diff --git a/core/os/file_access.h b/core/os/file_access.h index 7bfbf6e7f0..c65b75369c 100644 --- a/core/os/file_access.h +++ b/core/os/file_access.h @@ -113,6 +113,7 @@ public: virtual String get_line() const; virtual String get_token() const; virtual Vector<String> get_csv_line(const String &p_delim = ",") const; + virtual String get_as_utf8_string() const; /**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac) * It's not about the current CPU type but file formats. diff --git a/core/os/input.cpp b/core/os/input.cpp index cf11ba3c6d..caa9fb1493 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -91,6 +91,7 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Input::set_default_cursor_shape, DEFVAL(CURSOR_ARROW)); ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event); + ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input); BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE); BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN); diff --git a/core/os/input.h b/core/os/input.h index b354acd961..c8b80b28d0 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -132,6 +132,9 @@ public: virtual int get_joy_axis_index_from_string(String p_axis) = 0; virtual void parse_input_event(const Ref<InputEvent> &p_event) = 0; + virtual void accumulate_input_event(const Ref<InputEvent> &p_event) = 0; + virtual void flush_accumulated_events() = 0; + virtual void set_use_accumulated_input(bool p_enable) = 0; Input(); }; diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 24ec8a1963..25a5c2afeb 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -33,6 +33,9 @@ #include "core/input_map.h" #include "core/os/keyboard.h" +const int InputEvent::DEVICE_ID_TOUCH_MOUSE = -1; +const int InputEvent::DEVICE_ID_INTERNAL = -2; + void InputEvent::set_device(int p_device) { device = p_device; } @@ -122,6 +125,8 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("is_action_type"), &InputEvent::is_action_type); + ClassDB::bind_method(D_METHOD("accumulate", "with_event"), &InputEvent::accumulate); + ClassDB::bind_method(D_METHOD("xformed_by", "xform", "local_ofs"), &InputEvent::xformed_by, DEFVAL(Vector2())); ADD_PROPERTY(PropertyInfo(Variant::INT, "device"), "set_device", "get_device"); @@ -620,6 +625,44 @@ String InputEventMouseMotion::as_text() const { return "InputEventMouseMotion : button_mask=" + button_mask_string + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + ")"; } +bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) { + + Ref<InputEventMouseMotion> motion = p_event; + if (motion.is_null()) + return false; + + if (is_pressed() != motion->is_pressed()) { + return false; + } + + if (get_button_mask() != motion->get_button_mask()) { + return false; + } + + if (get_shift() != motion->get_shift()) { + return false; + } + + if (get_control() != motion->get_control()) { + return false; + } + + if (get_alt() != motion->get_alt()) { + return false; + } + + if (get_metakey() != motion->get_metakey()) { + return false; + } + + set_position(motion->get_position()); + set_global_position(motion->get_global_position()); + set_speed(motion->get_speed()); + relative += motion->get_relative(); + + return true; +} + void InputEventMouseMotion::_bind_methods() { ClassDB::bind_method(D_METHOD("set_relative", "relative"), &InputEventMouseMotion::set_relative); diff --git a/core/os/input_event.h b/core/os/input_event.h index a6a7012298..ba01516519 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -165,6 +165,9 @@ protected: static void _bind_methods(); public: + static const int DEVICE_ID_TOUCH_MOUSE; + static const int DEVICE_ID_INTERNAL; + void set_device(int p_device); int get_device() const; @@ -186,6 +189,7 @@ public: virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; virtual bool is_action_type() const; + virtual bool accumulate(const Ref<InputEvent> &p_event) { return false; } InputEvent(); }; @@ -351,6 +355,8 @@ public: virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; virtual String as_text() const; + virtual bool accumulate(const Ref<InputEvent> &p_event); + InputEventMouseMotion(); }; diff --git a/core/os/main_loop.h b/core/os/main_loop.h index bfdf92acfa..ad734d3fc8 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -51,21 +51,19 @@ protected: public: enum { - NOTIFICATION_WM_MOUSE_ENTER = 2, - NOTIFICATION_WM_MOUSE_EXIT = 3, - NOTIFICATION_WM_FOCUS_IN = 4, - NOTIFICATION_WM_FOCUS_OUT = 5, - NOTIFICATION_WM_QUIT_REQUEST = 6, - NOTIFICATION_WM_GO_BACK_REQUEST = 7, - NOTIFICATION_WM_UNFOCUS_REQUEST = 8, - NOTIFICATION_OS_MEMORY_WARNING = 9, - // Note: NOTIFICATION_TRANSLATION_CHANGED and NOTIFICATION_WM_ABOUT used to have id=10 and id=11 but these - // conflict with NOTIFICATION_ENTER_TREE (id=10) and NOTIFICATION_EXIT_TREE (id=11), so id=90 and id=91 - // fixes this issue. - NOTIFICATION_TRANSLATION_CHANGED = 90, - NOTIFICATION_WM_ABOUT = 91, - NOTIFICATION_CRASH = 92, - NOTIFICATION_OS_IME_UPDATE = 93, + //make sure these are replicated in Node + NOTIFICATION_WM_MOUSE_ENTER = 1002, + NOTIFICATION_WM_MOUSE_EXIT = 1003, + NOTIFICATION_WM_FOCUS_IN = 1004, + NOTIFICATION_WM_FOCUS_OUT = 1005, + NOTIFICATION_WM_QUIT_REQUEST = 1006, + NOTIFICATION_WM_GO_BACK_REQUEST = 1007, + NOTIFICATION_WM_UNFOCUS_REQUEST = 1008, + NOTIFICATION_OS_MEMORY_WARNING = 1009, + NOTIFICATION_TRANSLATION_CHANGED = 1010, + NOTIFICATION_WM_ABOUT = 1011, + NOTIFICATION_CRASH = 1012, + NOTIFICATION_OS_IME_UPDATE = 1013, }; virtual void input_event(const Ref<InputEvent> &p_event); diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp index 0d7ad23d68..7cb7ae130f 100644 --- a/core/os/midi_driver.cpp +++ b/core/os/midi_driver.cpp @@ -75,6 +75,11 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_ if (length >= 3) { event->set_pitch(data[1]); event->set_velocity(data[2]); + + if (event->get_message() == MIDI_MESSAGE_NOTE_ON && event->get_velocity() == 0) { + // https://www.midi.org/forum/228-writing-midi-software-send-note-off,-or-zero-velocity-note-on + event->set_message(MIDI_MESSAGE_NOTE_OFF); + } } break; diff --git a/core/os/os.h b/core/os/os.h index d6541034fd..d02d5a2c84 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -518,6 +518,9 @@ public: bool is_restart_on_exit_set() const; List<String> get_restart_on_exit_arguments() const; + virtual bool request_permission(const String &p_name) { return true; } + + virtual void process_and_drop_events() {} OS(); virtual ~OS(); }; diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp index 6c17f42b13..99bed829c1 100644 --- a/core/packed_data_container.cpp +++ b/core/packed_data_container.cpp @@ -114,7 +114,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b } else { Variant v; - Error rerr = decode_variant(v, p_buf + p_ofs, datalen - p_ofs, NULL); + Error rerr = decode_variant(v, p_buf + p_ofs, datalen - p_ofs, NULL, false); if (rerr != OK) { @@ -249,9 +249,9 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd uint32_t pos = tmpdata.size(); int len; - encode_variant(p_data, NULL, len); + encode_variant(p_data, NULL, len, false); tmpdata.resize(tmpdata.size() + len); - encode_variant(p_data, &tmpdata.write[pos], len); + encode_variant(p_data, &tmpdata.write[pos], len, false); return pos; } break; diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 6b4895d688..8c9a3dbcd4 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -501,7 +501,7 @@ Error ProjectSettings::_load_settings_binary(const String p_path) { d.resize(vlen); f->get_buffer(d.ptrw(), vlen); Variant value; - err = decode_variant(value, d.ptr(), d.size()); + err = decode_variant(value, d.ptr(), d.size(), NULL, false); ERR_EXPLAIN("Error decoding property: " + key); ERR_CONTINUE(err != OK); set(key, value); @@ -656,7 +656,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str file->store_string(key); int len; - err = encode_variant(p_custom_features, NULL, len); + err = encode_variant(p_custom_features, NULL, len, false); if (err != OK) { memdelete(file); ERR_FAIL_V(err); @@ -665,7 +665,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str Vector<uint8_t> buff; buff.resize(len); - err = encode_variant(p_custom_features, buff.ptrw(), len); + err = encode_variant(p_custom_features, buff.ptrw(), len, false); if (err != OK) { memdelete(file); ERR_FAIL_V(err); @@ -694,7 +694,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str file->store_string(key); int len; - err = encode_variant(value, NULL, len); + err = encode_variant(value, NULL, len, false); if (err != OK) memdelete(file); ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA); @@ -702,7 +702,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str Vector<uint8_t> buff; buff.resize(len); - err = encode_variant(value, buff.ptrw(), len); + err = encode_variant(value, buff.ptrw(), len, false); if (err != OK) memdelete(file); ERR_FAIL_COND_V(err != OK, ERR_INVALID_DATA); @@ -1185,6 +1185,9 @@ ProjectSettings::ProjectSettings() { Compression::gzip_level = GLOBAL_DEF("compression/formats/gzip/compression_level", Z_DEFAULT_COMPRESSION); custom_prop_info["compression/formats/gzip/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1"); + // Would ideally be defined in an Android-specific file, but then it doesn't appear in the docs + GLOBAL_DEF("android/modules", ""); + using_datapack = false; } diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 3ed25f118d..e7ff7a3aef 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -311,6 +311,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) } else { OS::get_singleton()->delay_usec(10000); + OS::get_singleton()->process_and_drop_events(); } } diff --git a/core/script_language.cpp b/core/script_language.cpp index f0310ffc31..4a6f904f9d 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -190,6 +190,14 @@ StringName ScriptServer::get_global_class_base(const String &p_class) { ERR_FAIL_COND_V(!global_classes.has(p_class), String()); return global_classes[p_class].base; } +StringName ScriptServer::get_global_class_native_base(const String &p_class) { + ERR_FAIL_COND_V(!global_classes.has(p_class), String()); + String base = global_classes[p_class].base; + while (global_classes.has(base)) { + base = global_classes[base].base; + } + return base; +} void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) { const StringName *K = NULL; List<StringName> classes; @@ -409,6 +417,11 @@ bool PlaceHolderScriptInstance::get(const StringName &p_name, Variant &r_ret) co return true; } + if (constants.has(p_name)) { + r_ret = constants[p_name]; + return true; + } + if (!script->is_placeholder_fallback_enabled()) { Variant defval; if (script->get_property_default_value(p_name, defval)) { @@ -444,6 +457,13 @@ Variant::Type PlaceHolderScriptInstance::get_property_type(const StringName &p_n *r_is_valid = true; return values[p_name].get_type(); } + + if (constants.has(p_name)) { + if (r_is_valid) + *r_is_valid = true; + return constants[p_name].get_type(); + } + if (r_is_valid) *r_is_valid = false; @@ -513,6 +533,9 @@ void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, c owner->_change_notify(); } //change notify + + constants.clear(); + script->get_constants(&constants); } void PlaceHolderScriptInstance::property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid) { @@ -552,6 +575,13 @@ Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_nam *r_valid = true; return E->value(); } + + E = constants.find(p_name); + if (E) { + if (r_valid) + *r_valid = true; + return E->value(); + } } if (r_valid) diff --git a/core/script_language.h b/core/script_language.h index 2d35097692..005e21e2cc 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -87,6 +87,7 @@ public: static StringName get_global_class_language(const StringName &p_class); static String get_global_class_path(const String &p_class); static StringName get_global_class_base(const String &p_class); + static StringName get_global_class_native_base(const String &p_class); static void get_global_class_list(List<StringName> *r_global_classes); static void save_global_classes(); @@ -204,6 +205,8 @@ public: static ScriptCodeCompletionCache *get_singleton() { return singleton; } ScriptCodeCompletionCache(); + + virtual ~ScriptCodeCompletionCache() {} }; class ScriptLanguage { @@ -336,6 +339,7 @@ class PlaceHolderScriptInstance : public ScriptInstance { Object *owner; List<PropertyInfo> properties; Map<StringName, Variant> values; + Map<StringName, Variant> constants; ScriptLanguage *language; Ref<Script> script; diff --git a/core/typedefs.h b/core/typedefs.h index 966360d4f2..660139b90a 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -137,7 +137,7 @@ T *_nullptr() { /** Generic swap template */ #ifndef SWAP -#define SWAP(m_x, m_y) __swap_tmpl(m_x, m_y) +#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y)) template <class T> inline void __swap_tmpl(T &x, T &y) { @@ -250,21 +250,34 @@ static inline int get_shift_from_power_of_2(unsigned int p_pixel) { } /** Swap 16 bits value for endianness */ +#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap16) +#define BSWAP16(x) __builtin_bswap16(x) +#else static inline uint16_t BSWAP16(uint16_t x) { return (x >> 8) | (x << 8); } +#endif + /** Swap 32 bits value for endianness */ +#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap32) +#define BSWAP32(x) __builtin_bswap32(x) +#else static inline uint32_t BSWAP32(uint32_t x) { return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24)); } -/** Swap 64 bits value for endianness */ +#endif +/** Swap 64 bits value for endianness */ +#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap64) +#define BSWAP64(x) __builtin_bswap64(x) +#else static inline uint64_t BSWAP64(uint64_t x) { x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32; x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16; x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8; return x; } +#endif /** When compiling with RTTI, we can add an "extra" * layer of safeness in many operations, so dynamic_cast @@ -315,4 +328,31 @@ struct _GlobalLock { #define _PRINTF_FORMAT_ATTRIBUTE_2_3 #endif +/** This is needed due to a strange OpenGL API that expects a pointer + * type for an argument that is actually an offset. + */ +#define CAST_INT_TO_UCHAR_PTR(ptr) ((uint8_t *)(uintptr_t)(ptr)) + +/** Hint for compilers that this fallthrough in a switch is intentional. + * Can be replaced by [[fallthrough]] annotation if we move to C++17. + * Including conditional support for it for people who set -std=c++17 + * themselves. + * Requires a trailing semicolon when used. + */ +#if __cplusplus >= 201703L +#define FALLTHROUGH [[fallthrough]] +#elif defined(__GNUC__) && __GNUC__ >= 7 +#define FALLTHROUGH __attribute__((fallthrough)) +#elif defined(__llvm__) && __cplusplus >= 201103L && defined(__has_feature) +#if __has_feature(cxx_attributes) && defined(__has_warning) +#if __has_warning("-Wimplicit-fallthrough") +#define FALLTHROUGH [[clang::fallthrough]] +#endif +#endif +#endif + +#ifndef FALLTHROUGH +#define FALLTHROUGH +#endif + #endif // TYPEDEFS_H diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 00894b41d8..69581e4115 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -90,7 +90,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { actions.write[actions.size() - 1].last_tick = ticks; merge_mode = p_mode; - + merging = true; } else { Action new_action; @@ -239,6 +239,10 @@ void UndoRedo::_pop_history_tail() { } } +bool UndoRedo::is_commiting_action() const { + return commiting > 0; +} + void UndoRedo::commit_action() { ERR_FAIL_COND(action_level <= 0); @@ -246,8 +250,14 @@ void UndoRedo::commit_action() { if (action_level > 0) return; //still nested - redo(); // perform action + if (merging) { + version--; + merging = false; + } + commiting++; + redo(); // perform action + commiting--; if (callback && actions.size() > 0) { callback(callback_ud, actions[actions.size() - 1].name); } @@ -321,6 +331,7 @@ bool UndoRedo::redo() { if ((current_action + 1) >= actions.size()) return false; //nothing to redo + current_action++; _process_operation_list(actions.write[current_action].do_ops.front()); @@ -337,7 +348,6 @@ bool UndoRedo::undo() { _process_operation_list(actions.write[current_action].undo_ops.front()); current_action--; version--; - return true; } @@ -386,10 +396,12 @@ void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_ca UndoRedo::UndoRedo() { + commiting = 0; version = 1; action_level = 0; current_action = -1; merge_mode = MERGE_DISABLE; + merging = false; callback = NULL; callback_ud = NULL; @@ -484,6 +496,7 @@ void UndoRedo::_bind_methods() { ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE)); ClassDB::bind_method(D_METHOD("commit_action"), &UndoRedo::commit_action); + ClassDB::bind_method(D_METHOD("is_commiting_action"), &UndoRedo::is_commiting_action); //ClassDB::bind_method(D_METHOD("add_do_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_do_method); //ClassDB::bind_method(D_METHOD("add_undo_method","p_object", "p_method", "VARIANT_ARG_LIST"),&UndoRedo::add_undo_method); diff --git a/core/undo_redo.h b/core/undo_redo.h index 4ee64dbfcf..6293e77acc 100644 --- a/core/undo_redo.h +++ b/core/undo_redo.h @@ -80,6 +80,7 @@ private: int current_action; int action_level; MergeMode merge_mode; + bool merging; uint64_t version; void _pop_history_tail(); @@ -94,6 +95,8 @@ private: MethodNotifyCallback method_callback; PropertyNotifyCallback property_callback; + int commiting; + protected: static void _bind_methods(); @@ -107,6 +110,7 @@ public: void add_do_reference(Object *p_object); void add_undo_reference(Object *p_object); + bool is_commiting_action() const; void commit_action(); bool redo(); diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 25a0f3957c..3812592639 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -773,6 +773,8 @@ struct _VariantCall { VCALL_PTR0R(Basis, get_orthogonal_index); VCALL_PTR0R(Basis, orthonormalized); VCALL_PTR2R(Basis, slerp); + VCALL_PTR2R(Basis, is_equal_approx); + VCALL_PTR0R(Basis, get_rotation_quat); VCALL_PTR0R(Transform, inverse); VCALL_PTR0R(Transform, affine_inverse); @@ -1842,6 +1844,8 @@ void register_variant_methods() { ADDFUNC1R(BASIS, VECTOR3, Basis, xform_inv, VECTOR3, "v", varray()); ADDFUNC0R(BASIS, INT, Basis, get_orthogonal_index, varray()); ADDFUNC2R(BASIS, BASIS, Basis, slerp, BASIS, "b", REAL, "t", varray()); + ADDFUNC2R(BASIS, BOOL, Basis, is_equal_approx, BASIS, "b", REAL, "epsilon", varray(CMP_EPSILON)); + ADDFUNC0R(BASIS, QUAT, Basis, get_rotation_quat, varray()); ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, inverse, varray()); ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, affine_inverse, varray()); diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 26851e4c23..b40b6ce4a6 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -3656,11 +3656,55 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & } return; case POOL_INT_ARRAY: { - r_dst = a; + const PoolVector<int> *arr_a = reinterpret_cast<const PoolVector<int> *>(a._data._mem); + const PoolVector<int> *arr_b = reinterpret_cast<const PoolVector<int> *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + + r_dst = a; + } else { + + PoolVector<int> v; + v.resize(sz); + { + PoolVector<int>::Write vw = v.write(); + PoolVector<int>::Read ar = arr_a->read(); + PoolVector<int>::Read br = arr_b->read(); + + Variant va; + for (int i = 0; i < sz; i++) { + Variant::interpolate(ar[i], br[i], c, va); + vw[i] = va; + } + } + r_dst = v; + } } return; case POOL_REAL_ARRAY: { - r_dst = a; + const PoolVector<real_t> *arr_a = reinterpret_cast<const PoolVector<real_t> *>(a._data._mem); + const PoolVector<real_t> *arr_b = reinterpret_cast<const PoolVector<real_t> *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + + r_dst = a; + } else { + + PoolVector<real_t> v; + v.resize(sz); + { + PoolVector<real_t>::Write vw = v.write(); + PoolVector<real_t>::Read ar = arr_a->read(); + PoolVector<real_t>::Read br = arr_b->read(); + + Variant va; + for (int i = 0; i < sz; i++) { + Variant::interpolate(ar[i], br[i], c, va); + vw[i] = va; + } + } + r_dst = v; + } } return; case POOL_STRING_ARRAY: { @@ -3717,7 +3761,27 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & } return; case POOL_COLOR_ARRAY: { - r_dst = a; + const PoolVector<Color> *arr_a = reinterpret_cast<const PoolVector<Color> *>(a._data._mem); + const PoolVector<Color> *arr_b = reinterpret_cast<const PoolVector<Color> *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + + r_dst = a; + } else { + + PoolVector<Color> v; + v.resize(sz); + { + PoolVector<Color>::Write vw = v.write(); + PoolVector<Color>::Read ar = arr_a->read(); + PoolVector<Color>::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } } return; default: { |