diff options
Diffstat (limited to 'core')
29 files changed, 592 insertions, 56 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index aa954ed300..f939fca984 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -402,7 +402,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b #ifdef OSX_ENABLED if (!found) { // Attempt to load PCK from macOS .app bundle resources. - found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck")); + found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_filename + ".pck")); } #endif @@ -524,10 +524,6 @@ bool ProjectSettings::has_setting(String p_var) const { return props.has(p_var); } -void ProjectSettings::set_registering_order(bool p_enable) { - registering_order = p_enable; -} - Error ProjectSettings::_load_settings_binary(const String &p_path) { Error err; FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); diff --git a/core/config/project_settings.h b/core/config/project_settings.h index a8c9adc587..5a16248c76 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -76,7 +76,6 @@ protected: } }; - bool registering_order = true; int last_order = NO_BUILTIN_ORDER_BASE; int last_builtin_order = 0; Map<StringName, VariantContainer> props; @@ -160,8 +159,6 @@ public: bool is_using_datapack() const; - void set_registering_order(bool p_enable); - bool has_custom_feature(const String &p_feature) const; Map<StringName, AutoloadInfo> get_autoload_list() const; diff --git a/core/core_constants.cpp b/core/core_constants.cpp index 57ea10c074..db22a9ecf6 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -128,6 +128,7 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(HALIGN_LEFT); BIND_CORE_ENUM_CONSTANT(HALIGN_CENTER); BIND_CORE_ENUM_CONSTANT(HALIGN_RIGHT); + BIND_CORE_ENUM_CONSTANT(HALIGN_FILL); BIND_CORE_ENUM_CONSTANT(VALIGN_TOP); BIND_CORE_ENUM_CONSTANT(VALIGN_CENTER); diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp index d12108bca0..33ba0ba704 100644 --- a/core/crypto/crypto.cpp +++ b/core/crypto/crypto.cpp @@ -65,6 +65,22 @@ void X509Certificate::_bind_methods() { ClassDB::bind_method(D_METHOD("load", "path"), &X509Certificate::load); } +/// HMACContext + +void HMACContext::_bind_methods() { + ClassDB::bind_method(D_METHOD("start", "hash_type", "key"), &HMACContext::start); + ClassDB::bind_method(D_METHOD("update", "data"), &HMACContext::update); + ClassDB::bind_method(D_METHOD("finish"), &HMACContext::finish); +} + +HMACContext *(*HMACContext::_create)() = nullptr; +HMACContext *HMACContext::create() { + if (_create) { + return _create(); + } + ERR_FAIL_V_MSG(nullptr, "HMACContext is not available when the mbedtls module is disabled."); +} + /// Crypto void (*Crypto::_load_default_certificates)(String p_path) = nullptr; @@ -82,6 +98,35 @@ void Crypto::load_default_certificates(String p_path) { } } +PackedByteArray Crypto::hmac_digest(HashingContext::HashType p_hash_type, PackedByteArray p_key, PackedByteArray p_msg) { + Ref<HMACContext> ctx = Ref<HMACContext>(HMACContext::create()); + ERR_FAIL_COND_V_MSG(ctx.is_null(), PackedByteArray(), "HMAC is not available witout mbedtls module."); + Error err = ctx->start(p_hash_type, p_key); + ERR_FAIL_COND_V(err != OK, PackedByteArray()); + err = ctx->update(p_msg); + ERR_FAIL_COND_V(err != OK, PackedByteArray()); + return ctx->finish(); +} + +// Compares two HMACS for equality without leaking timing information in order to prevent timing attakcs. +// @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy +bool Crypto::constant_time_compare(PackedByteArray p_trusted, PackedByteArray p_received) { + const uint8_t *t = p_trusted.ptr(); + const uint8_t *r = p_received.ptr(); + int tlen = p_trusted.size(); + int rlen = p_received.size(); + // If the lengths are different then nothing else matters. + if (tlen != rlen) { + return false; + } + + uint8_t v = 0; + for (int i = 0; i < tlen; i++) { + v |= t[i] ^ r[i]; + } + return v == 0; +} + void Crypto::_bind_methods() { ClassDB::bind_method(D_METHOD("generate_random_bytes", "size"), &Crypto::generate_random_bytes); ClassDB::bind_method(D_METHOD("generate_rsa", "size"), &Crypto::generate_rsa); @@ -90,6 +135,8 @@ void Crypto::_bind_methods() { ClassDB::bind_method(D_METHOD("verify", "hash_type", "hash", "signature", "key"), &Crypto::verify); ClassDB::bind_method(D_METHOD("encrypt", "key", "plaintext"), &Crypto::encrypt); ClassDB::bind_method(D_METHOD("decrypt", "key", "ciphertext"), &Crypto::decrypt); + ClassDB::bind_method(D_METHOD("hmac_digest", "hash_type", "key", "msg"), &Crypto::hmac_digest); + ClassDB::bind_method(D_METHOD("constant_time_compare", "trusted", "received"), &Crypto::constant_time_compare); } /// Resource loader/saver diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h index 8325f043bf..5cacddaea0 100644 --- a/core/crypto/crypto.h +++ b/core/crypto/crypto.h @@ -67,6 +67,23 @@ public: virtual Error save(String p_path) = 0; }; +class HMACContext : public Reference { + GDCLASS(HMACContext, Reference); + +protected: + static void _bind_methods(); + static HMACContext *(*_create)(); + +public: + static HMACContext *create(); + + virtual Error start(HashingContext::HashType p_hash_type, PackedByteArray p_key) = 0; + virtual Error update(PackedByteArray p_data) = 0; + virtual PackedByteArray finish() = 0; + + HMACContext() {} +}; + class Crypto : public Reference { GDCLASS(Crypto, Reference); @@ -88,6 +105,12 @@ public: virtual Vector<uint8_t> encrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_plaintext) = 0; virtual Vector<uint8_t> decrypt(Ref<CryptoKey> p_key, Vector<uint8_t> p_ciphertext) = 0; + PackedByteArray hmac_digest(HashingContext::HashType p_hash_type, PackedByteArray p_key, PackedByteArray p_msg); + + // Compares two PackedByteArrays for equality without leaking timing information in order to prevent timing attacks. + // @see: https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy + bool constant_time_compare(PackedByteArray p_trusted, PackedByteArray p_received); + Crypto() {} }; diff --git a/core/doc_data.cpp b/core/doc_data.cpp new file mode 100644 index 0000000000..d84ac6d05b --- /dev/null +++ b/core/doc_data.cpp @@ -0,0 +1,126 @@ +/*************************************************************************/ +/* doc_data.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "doc_data.h" + +void DocData::return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo) { + if (p_retinfo.type == Variant::INT && p_retinfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + p_method.return_enum = p_retinfo.class_name; + if (p_method.return_enum.begins_with("_")) { //proxy class + p_method.return_enum = p_method.return_enum.substr(1, p_method.return_enum.length()); + } + p_method.return_type = "int"; + } else if (p_retinfo.class_name != StringName()) { + p_method.return_type = p_retinfo.class_name; + } else if (p_retinfo.type == Variant::ARRAY && p_retinfo.hint == PROPERTY_HINT_ARRAY_TYPE) { + p_method.return_type = p_retinfo.hint_string + "[]"; + } else if (p_retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { + p_method.return_type = p_retinfo.hint_string; + } else if (p_retinfo.type == Variant::NIL && p_retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { + p_method.return_type = "Variant"; + } else if (p_retinfo.type == Variant::NIL) { + p_method.return_type = "void"; + } else { + p_method.return_type = Variant::get_type_name(p_retinfo.type); + } +} + +void DocData::argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo) { + p_argument.name = p_arginfo.name; + + if (p_arginfo.type == Variant::INT && p_arginfo.usage & PROPERTY_USAGE_CLASS_IS_ENUM) { + p_argument.enumeration = p_arginfo.class_name; + if (p_argument.enumeration.begins_with("_")) { //proxy class + p_argument.enumeration = p_argument.enumeration.substr(1, p_argument.enumeration.length()); + } + p_argument.type = "int"; + } else if (p_arginfo.class_name != StringName()) { + p_argument.type = p_arginfo.class_name; + } else if (p_arginfo.type == Variant::ARRAY && p_arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) { + p_argument.type = p_arginfo.hint_string + "[]"; + } else if (p_arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) { + p_argument.type = p_arginfo.hint_string; + } else if (p_arginfo.type == Variant::NIL) { + // Parameters cannot be void, so PROPERTY_USAGE_NIL_IS_VARIANT is not necessary + p_argument.type = "Variant"; + } else { + p_argument.type = Variant::get_type_name(p_arginfo.type); + } +} + +void DocData::property_doc_from_scriptmemberinfo(DocData::PropertyDoc &p_property, const ScriptMemberInfo &p_memberinfo) { + p_property.name = p_memberinfo.propinfo.name; + p_property.description = p_memberinfo.doc_string; + + if (p_memberinfo.propinfo.type == Variant::OBJECT) { + p_property.type = p_memberinfo.propinfo.class_name; + } else if (p_memberinfo.propinfo.type == Variant::NIL && p_memberinfo.propinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { + p_property.type = "Variant"; + } else { + p_property.type = Variant::get_type_name(p_memberinfo.propinfo.type); + } + + p_property.setter = p_memberinfo.setter; + p_property.getter = p_memberinfo.getter; + + if (p_memberinfo.has_default_value && p_memberinfo.default_value.get_type() != Variant::OBJECT) { + p_property.default_value = p_memberinfo.default_value.get_construct_string().replace("\n", ""); + } + + p_property.overridden = false; +} + +void DocData::method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc) { + p_method.name = p_methodinfo.name; + p_method.description = p_desc; + + return_doc_from_retinfo(p_method, p_methodinfo.return_val); + + for (int i = 0; i < p_methodinfo.arguments.size(); i++) { + DocData::ArgumentDoc argument; + argument_doc_from_arginfo(argument, p_methodinfo.arguments[i]); + int default_arg_index = i - (p_methodinfo.arguments.size() - p_methodinfo.default_arguments.size()); + if (default_arg_index >= 0) { + Variant default_arg = p_methodinfo.default_arguments[default_arg_index]; + argument.default_value = default_arg.get_construct_string(); + } + p_method.arguments.push_back(argument); + } +} + +void DocData::constant_doc_from_variant(DocData::ConstantDoc &p_const, const StringName &p_name, const Variant &p_value, const String &p_desc) { + p_const.name = p_name; + p_const.value = p_value; + p_const.description = p_desc; +} + +void DocData::signal_doc_from_methodinfo(DocData::MethodDoc &p_signal, const MethodInfo &p_methodinfo, const String &p_desc) { + return method_doc_from_methodinfo(p_signal, p_methodinfo, p_desc); +} diff --git a/core/doc_data.h b/core/doc_data.h new file mode 100644 index 0000000000..bf016792ea --- /dev/null +++ b/core/doc_data.h @@ -0,0 +1,152 @@ +/*************************************************************************/ +/* doc_data.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef DOC_DATA_H +#define DOC_DATA_H + +#include "core/io/xml_parser.h" +#include "core/templates/map.h" +#include "core/variant/variant.h" + +struct ScriptMemberInfo { + PropertyInfo propinfo; + String doc_string; + StringName setter; + StringName getter; + + bool has_default_value = false; + Variant default_value; +}; + +class DocData { +public: + struct ArgumentDoc { + String name; + String type; + String enumeration; + String default_value; + bool operator<(const ArgumentDoc &p_arg) const { + if (name == p_arg.name) { + return type < p_arg.type; + } + return name < p_arg.name; + } + }; + + struct MethodDoc { + String name; + String return_type; + String return_enum; + String qualifiers; + String description; + Vector<ArgumentDoc> arguments; + bool operator<(const MethodDoc &p_method) const { + if (name == p_method.name) { + // Must be a constructor since there is no overloading. + // We want this arbitrary order for a class "Foo": + // - 1. Default constructor: Foo() + // - 2. Copy constructor: Foo(Foo) + // - 3+. Other constructors Foo(Bar, ...) based on first argument's name + if (arguments.size() == 0 || p_method.arguments.size() == 0) { // 1. + return arguments.size() < p_method.arguments.size(); + } + if (arguments[0].type == return_type || p_method.arguments[0].type == p_method.return_type) { // 2. + return (arguments[0].type == return_type) || (p_method.arguments[0].type != p_method.return_type); + } + return arguments[0] < p_method.arguments[0]; + } + return name < p_method.name; + } + }; + + struct ConstantDoc { + String name; + String value; + bool is_value_valid; + String enumeration; + String description; + bool operator<(const ConstantDoc &p_const) const { + return name < p_const.name; + } + }; + + struct EnumDoc { + String name = "@unnamed_enum"; + String description; + Vector<DocData::ConstantDoc> values; + }; + + struct PropertyDoc { + String name; + String type; + String enumeration; + String description; + String setter, getter; + String default_value; + bool overridden = false; + bool operator<(const PropertyDoc &p_prop) const { + return name < p_prop.name; + } + }; + + struct TutorialDoc { + String link; + String title; + }; + + struct ClassDoc { + String name; + String inherits; + String category; + String brief_description; + String description; + Vector<TutorialDoc> tutorials; + Vector<MethodDoc> methods; + Vector<MethodDoc> signals; + Vector<ConstantDoc> constants; + Map<String, String> enums; + Vector<PropertyDoc> properties; + Vector<PropertyDoc> theme_properties; + bool is_script_doc = false; + String script_path; + bool operator<(const ClassDoc &p_class) const { + return name < p_class.name; + } + }; + + static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo); + static void argument_doc_from_arginfo(DocData::ArgumentDoc &p_argument, const PropertyInfo &p_arginfo); + static void property_doc_from_scriptmemberinfo(DocData::PropertyDoc &p_property, const ScriptMemberInfo &p_memberinfo); + static void method_doc_from_methodinfo(DocData::MethodDoc &p_method, const MethodInfo &p_methodinfo, const String &p_desc); + static void constant_doc_from_variant(DocData::ConstantDoc &p_const, const StringName &p_name, const Variant &p_value, const String &p_desc); + static void signal_doc_from_methodinfo(DocData::MethodDoc &p_signal, const MethodInfo &p_methodinfo, const String &p_desc); +}; + +#endif // DOC_DATA_H diff --git a/core/input/input.cpp b/core/input/input.cpp index 00a7e63a73..153656e44a 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -1211,7 +1211,7 @@ void Input::parse_mapping(String p_mapping) { ERR_CONTINUE_MSG(output.length() < 1 || input.length() < 2, String(entry[idx] + "\nInvalid device mapping entry: " + entry[idx])); - if (output == "platform") { + if (output == "platform" || output == "hint") { continue; } diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 2f17d9e746..afab00ebd6 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -142,6 +142,10 @@ void MultiplayerAPI::set_root_node(Node *p_node) { root_node = p_node; } +Node *MultiplayerAPI::get_root_node() { + return root_node; +} + void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer) { if (p_peer == network_peer) { return; // Nothing to do @@ -1202,6 +1206,7 @@ bool MultiplayerAPI::is_object_decoding_allowed() const { void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); + ClassDB::bind_method(D_METHOD("get_root_node"), &MultiplayerAPI::get_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)); ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer); ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer); @@ -1221,6 +1226,7 @@ void MultiplayerAPI::_bind_methods() { 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"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_node", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_root_node", "get_root_node"); ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false); ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index 5b30c2e680..ca52a1c689 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -114,6 +114,7 @@ public: void poll(); void clear(); void set_root_node(Node *p_node); + Node *get_root_node(); void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer); Ref<NetworkedMultiplayerPeer> get_network_peer() const; Error send_bytes(Vector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST, NetworkedMultiplayerPeer::TransferMode p_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp index e633a56d54..488cfbeaa8 100644 --- a/core/io/packet_peer_udp.cpp +++ b/core/io/packet_peer_udp.cpp @@ -178,7 +178,6 @@ Error PacketPeerUDP::listen(int p_port, const IP_Address &p_bind_address, int p_ } _sock->set_blocking_enabled(false); - _sock->set_reuse_address_enabled(true); _sock->set_broadcasting_enabled(broadcast); err = _sock->bind(p_bind_address, p_port); diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index d31a9a0194..30bbd43c18 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -102,6 +102,7 @@ public: virtual String get_resource_type() const = 0; virtual float get_priority() const { return 1.0; } virtual int get_import_order() const { return 0; } + virtual int get_format_version() const { return 0; } struct ImportOption { PropertyInfo option; diff --git a/core/math/math_defs.h b/core/math/math_defs.h index 5192722839..4d97f72ebf 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -73,7 +73,8 @@ enum Orientation { enum HAlign { HALIGN_LEFT, HALIGN_CENTER, - HALIGN_RIGHT + HALIGN_RIGHT, + HALIGN_FILL, }; enum VAlign { diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index 64ebeb427e..dc28fa10de 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -978,6 +978,7 @@ void ClassDB::add_property_subgroup(StringName p_class, const String &p_name, co type->property_list.push_back(PropertyInfo(Variant::NIL, p_name, PROPERTY_HINT_NONE, p_prefix, PROPERTY_USAGE_SUBGROUP)); } +// NOTE: For implementation simplicity reasons, this method doesn't allow setters to have optional arguments at the end. void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) { lock->read_lock(); ClassInfo *type = classes.getptr(p_class); diff --git a/core/object/object.cpp b/core/object/object.cpp index 96a41d6852..a642647853 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1841,9 +1841,13 @@ void postinitialize_handler(Object *p_object) { void ObjectDB::debug_objects(DebugFunc p_func) { spin_lock.lock(); - for (uint32_t i = 0; i < slot_count; i++) { - uint32_t slot = object_slots[i].next_free; - p_func(object_slots[slot].object); + + for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) { + if (object_slots[i].validator) { + p_func(object_slots[i].object); + + count--; + } } spin_lock.unlock(); } @@ -1955,20 +1959,23 @@ void ObjectDB::cleanup() { MethodBind *resource_get_path = ClassDB::get_method("Resource", "get_path"); Callable::CallError call_error; - for (uint32_t i = 0; i < slot_count; i++) { - uint32_t slot = object_slots[i].next_free; - Object *obj = object_slots[slot].object; + for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) { + if (object_slots[i].validator) { + Object *obj = object_slots[i].object; - String extra_info; - if (obj->is_class("Node")) { - extra_info = " - Node name: " + String(node_get_name->call(obj, nullptr, 0, call_error)); - } - if (obj->is_class("Resource")) { - extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error)); - } + String extra_info; + if (obj->is_class("Node")) { + extra_info = " - Node name: " + String(node_get_name->call(obj, nullptr, 0, call_error)); + } + if (obj->is_class("Resource")) { + extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error)); + } + + uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[i].is_reference ? OBJECTDB_REFERENCE_BIT : 0); + print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + extra_info); - uint64_t id = uint64_t(slot) | (uint64_t(object_slots[slot].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[slot].is_reference ? OBJECTDB_REFERENCE_BIT : 0); - print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + extra_info); + count--; + } } print_line("Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`)."); } diff --git a/core/object/script_language.h b/core/object/script_language.h index 3fd56c2f15..72586780ae 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -31,6 +31,7 @@ #ifndef SCRIPT_LANGUAGE_H #define SCRIPT_LANGUAGE_H +#include "core/doc_data.h" #include "core/io/multiplayer_api.h" #include "core/io/resource.h" #include "core/templates/map.h" @@ -145,6 +146,10 @@ public: virtual void set_source_code(const String &p_code) = 0; virtual Error reload(bool p_keep_state = false) = 0; +#ifdef TOOLS_ENABLED + virtual const Vector<DocData::ClassDoc> &get_documentation() const = 0; +#endif // TOOLS_ENABLED + virtual bool has_method(const StringName &p_method) const = 0; virtual MethodInfo get_method_info(const StringName &p_method) const = 0; @@ -310,6 +315,7 @@ public: virtual Script *create_script() const = 0; virtual bool has_named_classes() const = 0; virtual bool supports_builtin_mode() const = 0; + virtual bool supports_documentation() const { return false; } virtual bool can_inherit_from_file() { return false; } virtual int find_function(const String &p_function, const String &p_code) const = 0; virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const = 0; diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index d29bcd011f..9252ba0840 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -47,6 +47,7 @@ void MainLoop::_bind_methods() { BIND_CONSTANT(NOTIFICATION_APPLICATION_PAUSED); BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_IN); BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_OUT); + BIND_CONSTANT(NOTIFICATION_TEXT_SERVER_CHANGED); ADD_SIGNAL(MethodInfo("on_request_permissions_result", PropertyInfo(Variant::STRING, "permission"), PropertyInfo(Variant::BOOL, "granted"))); }; diff --git a/core/os/main_loop.h b/core/os/main_loop.h index 8c46ad9b6a..7bc91fbb83 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -56,6 +56,7 @@ public: NOTIFICATION_APPLICATION_PAUSED = 2015, NOTIFICATION_APPLICATION_FOCUS_IN = 2016, NOTIFICATION_APPLICATION_FOCUS_OUT = 2017, + NOTIFICATION_TEXT_SERVER_CHANGED = 2018, }; virtual void init(); diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 7e32f215e7..9883ce12a0 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -168,6 +168,7 @@ void register_core_types() { ClassDB::register_class<AESContext>(); ClassDB::register_custom_instance_class<X509Certificate>(); ClassDB::register_custom_instance_class<CryptoKey>(); + ClassDB::register_custom_instance_class<HMACContext>(); ClassDB::register_custom_instance_class<Crypto>(); ClassDB::register_custom_instance_class<StreamPeerSSL>(); diff --git a/core/string/translation.cpp b/core/string/translation.cpp index df8a26e5ce..7b8c28e2e2 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -34,6 +34,11 @@ #include "core/io/resource_loader.h" #include "core/os/os.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#include "main/main.h" +#endif + // ISO 639-1 language codes, with the addition of glibc locales with their // regional identifiers. This list must match the language names (in English) // of locale_names. @@ -1214,6 +1219,22 @@ void TranslationServer::set_tool_translation(const Ref<Translation> &p_translati tool_translation = p_translation; } +Ref<Translation> TranslationServer::get_tool_translation() const { + return tool_translation; +} + +String TranslationServer::get_tool_locale() { +#ifdef TOOLS_ENABLED + if (TranslationServer::get_singleton()->get_tool_translation().is_valid() && (Engine::get_singleton()->is_editor_hint() || Main::is_project_manager())) { + return tool_translation->get_locale(); + } else { +#else + { +#endif + return get_locale(); + } +} + StringName TranslationServer::tool_translate(const StringName &p_message, const StringName &p_context) const { if (tool_translation.is_valid()) { StringName r = tool_translation->get_message(p_message, p_context); diff --git a/core/string/translation.h b/core/string/translation.h index 8d34f7997e..c7ffe4d065 100644 --- a/core/string/translation.h +++ b/core/string/translation.h @@ -110,7 +110,9 @@ public: static String standardize_locale(const String &p_locale); static String get_language_code(const String &p_locale); + String get_tool_locale(); void set_tool_translation(const Ref<Translation> &p_translation); + Ref<Translation> get_tool_translation() const; StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const; StringName tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; void set_doc_translation(const Ref<Translation> &p_translation); diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 213578485e..d630e987ea 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -209,7 +209,6 @@ void CharString::copy_from(const char *p_cstr) { /* String */ /*************************************************************************/ -//TODO: move to TextServer //kind of poor should be rewritten properly String String::word_wrap(int p_chars_per_line) const { int from = 0; @@ -4796,7 +4795,7 @@ Vector<uint8_t> String::to_utf16_buffer() const { Char16String charstr = s->utf16(); Vector<uint8_t> retval; - size_t len = charstr.length() * 2; + size_t len = charstr.length() * sizeof(char16_t); retval.resize(len); uint8_t *w = retval.ptrw(); copymem(w, (const void *)charstr.ptr(), len); @@ -4811,7 +4810,7 @@ Vector<uint8_t> String::to_utf32_buffer() const { } Vector<uint8_t> retval; - size_t len = s->length() * 4; + size_t len = s->length() * sizeof(char32_t); retval.resize(len); uint8_t *w = retval.ptrw(); copymem(w, (const void *)s->ptr(), len); diff --git a/core/string/ustring.h b/core/string/ustring.h index bfae16fe64..7ff78b2d86 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -28,8 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef USTRING_H -#define USTRING_H +#ifndef USTRING_GODOT_H +#define USTRING_GODOT_H +// Note: Renamed to avoid conflict with ICU header with the same name. #include "core/templates/cowdata.h" #include "core/templates/vector.h" @@ -555,4 +556,4 @@ _FORCE_INLINE_ Vector<String> sarray(P... p_args) { return arr; } -#endif // USTRING_H +#endif // USTRING_GODOT_H diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h index 86bb1b5228..1ed9ab1987 100644 --- a/core/templates/hashfuncs.h +++ b/core/templates/hashfuncs.h @@ -114,6 +114,24 @@ static inline uint32_t make_uint32_t(T p_in) { return _u._u32; } +static inline uint64_t hash_djb2_one_float_64(double p_in, uint64_t p_prev = 5381) { + union { + double d; + uint64_t i; + } u; + + // Normalize +/- 0.0 and NaN values so they hash the same. + if (p_in == 0.0f) { + u.d = 0.0; + } else if (Math::is_nan(p_in)) { + u.d = Math_NAN; + } else { + u.d = p_in; + } + + return ((p_prev << 5) + p_prev) + u.i; +} + static inline uint64_t hash_djb2_one_64(uint64_t p_in, uint64_t p_prev = 5381) { return ((p_prev << 5) + p_prev) + p_in; } diff --git a/core/templates/lru.h b/core/templates/lru.h new file mode 100644 index 0000000000..d02c4337d1 --- /dev/null +++ b/core/templates/lru.h @@ -0,0 +1,126 @@ +/*************************************************************************/ +/* lru.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef LRU_H +#define LRU_H + +#include "core/math/math_funcs.h" +#include "hash_map.h" +#include "list.h" + +template <class TKey, class TData> +class LRUCache { +private: + struct Pair { + TKey key; + TData data; + + Pair() {} + Pair(const TKey &p_key, const TData &p_data) : + key(p_key), + data(p_data) { + } + }; + + typedef typename List<Pair>::Element *Element; + + List<Pair> _list; + HashMap<TKey, Element> _map; + size_t capacity; + +public: + const TData *insert(const TKey &p_key, const TData &p_value) { + Element *e = _map.getptr(p_key); + Element n = _list.push_front(Pair(p_key, p_value)); + + if (e) { + _list.erase(*e); + _map.erase(p_key); + } + _map[p_key] = _list.front(); + + while (_map.size() > capacity) { + Element d = _list.back(); + _map.erase(d->get().key); + _list.pop_back(); + } + + return &n->get().data; + } + + void clear() { + _map.clear(); + _list.clear(); + } + + bool has(const TKey &p_key) const { + return _map.getptr(p_key); + } + + const TData &get(const TKey &p_key) { + Element *e = _map.getptr(p_key); + CRASH_COND(!e); + _list.move_to_front(*e); + return (*e)->get().data; + }; + + const TData *getptr(const TKey &p_key) { + Element *e = _map.getptr(p_key); + if (!e) { + return nullptr; + } else { + _list.move_to_front(*e); + return &(*e)->get().data; + } + } + + _FORCE_INLINE_ size_t get_capacity() const { return capacity; } + + void set_capacity(size_t p_capacity) { + if (capacity > 0) { + capacity = p_capacity; + while (_map.size() > capacity) { + Element d = _list.back(); + _map.erase(d->get().key); + _list.pop_back(); + } + } + } + + LRUCache() { + capacity = 64; + } + + LRUCache(int p_capacity) { + capacity = p_capacity; + } +}; + +#endif diff --git a/core/typedefs.h b/core/typedefs.h index d7ee5ee40e..7c98bc37f7 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -92,7 +92,7 @@ #endif #ifndef SGN -#define SGN(m_v) (((m_v) < 0) ? (-1.0) : (+1.0)) +#define SGN(m_v) (((m_v) == 0) ? (0.0) : (((m_v) < 0) ? (-1.0) : (+1.0))) #endif #ifndef MIN diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 13514b7b9f..214c424013 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -418,7 +418,7 @@ struct _VariantCall { String s; if (p_instance->size() > 0) { const uint8_t *r = p_instance->ptr(); - s.parse_utf16((const char16_t *)r, p_instance->size() / 2); + s.parse_utf16((const char16_t *)r, floor((double)p_instance->size() / (double)sizeof(char16_t))); } return s; } @@ -427,7 +427,7 @@ struct _VariantCall { String s; if (p_instance->size() > 0) { const uint8_t *r = p_instance->ptr(); - s = String((const char32_t *)r, p_instance->size() / 4); + s = String((const char32_t *)r, floor((double)p_instance->size() / (double)sizeof(char32_t))); } return s; } diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp index 01f5b7df59..3bb3fa3634 100644 --- a/core/variant/variant_construct.cpp +++ b/core/variant/variant_construct.cpp @@ -777,18 +777,23 @@ String Variant::get_constructor_argument_name(Variant::Type p_type, int p_constr return construct_data[p_type][p_constructor].arg_names[p_argument]; } -void VariantInternal::object_assign(Variant *v, const Variant *o) { - if (o->_get_obj().obj && o->_get_obj().id.is_reference()) { - Reference *reference = static_cast<Reference *>(o->_get_obj().obj); - if (!reference->reference()) { - v->_get_obj().obj = nullptr; - v->_get_obj().id = ObjectID(); - return; +void VariantInternal::object_assign(Variant *v, const Object *o) { + if (o) { + if (o->is_reference()) { + Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(o)); + if (!reference->init_ref()) { + v->_get_obj().obj = nullptr; + v->_get_obj().id = ObjectID(); + return; + } } - } - v->_get_obj().obj = const_cast<Object *>(o->_get_obj().obj); - v->_get_obj().id = o->_get_obj().id; + v->_get_obj().obj = const_cast<Object *>(o); + v->_get_obj().id = o->get_instance_id(); + } else { + v->_get_obj().obj = nullptr; + v->_get_obj().id = ObjectID(); + } } void Variant::get_constructor_list(Type p_type, List<MethodInfo> *r_list) { diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index bf7e46eed7..804abf8fbc 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -100,21 +100,14 @@ public: case Variant::PACKED_COLOR_ARRAY: init_color_array(v); break; + case Variant::OBJECT: + object_assign_null(v); + break; default: break; } } - _FORCE_INLINE_ static void set_object(Variant *v, Object *obj) { - if (obj) { - v->_get_obj().obj = obj; - v->_get_obj().id = obj->get_instance_id(); - } else { - v->_get_obj().obj = nullptr; - v->_get_obj().id = ObjectID(); - } - } - // Atomic types. _FORCE_INLINE_ static bool *get_bool(Variant *v) { return &v->_data._bool; } _FORCE_INLINE_ static const bool *get_bool(const Variant *v) { return &v->_data._bool; } @@ -285,7 +278,11 @@ public: v->clear(); } - static void object_assign(Variant *v, const Variant *o); //needs to use reference, do away + static void object_assign(Variant *v, const Object *o); // Needs Reference, so it's implemented elsewhere. + + _FORCE_INLINE_ static void object_assign(Variant *v, const Variant *o) { + object_assign(v, o->_get_obj().obj); + } _FORCE_INLINE_ static void object_assign_null(Variant *v) { v->_get_obj().obj = nullptr; |