summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/config/project_settings.cpp6
-rw-r--r--core/config/project_settings.h3
-rw-r--r--core/core_constants.cpp1
-rw-r--r--core/crypto/crypto.cpp47
-rw-r--r--core/crypto/crypto.h23
-rw-r--r--core/doc_data.cpp126
-rw-r--r--core/doc_data.h152
-rw-r--r--core/input/input.cpp2
-rw-r--r--core/io/multiplayer_api.cpp6
-rw-r--r--core/io/multiplayer_api.h1
-rw-r--r--core/io/packet_peer_udp.cpp1
-rw-r--r--core/io/resource_importer.h1
-rw-r--r--core/math/math_defs.h3
-rw-r--r--core/object/class_db.cpp1
-rw-r--r--core/object/object.cpp37
-rw-r--r--core/object/script_language.h6
-rw-r--r--core/os/main_loop.cpp1
-rw-r--r--core/os/main_loop.h1
-rw-r--r--core/register_core_types.cpp1
-rw-r--r--core/string/translation.cpp21
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/ustring.cpp5
-rw-r--r--core/string/ustring.h7
-rw-r--r--core/templates/hashfuncs.h18
-rw-r--r--core/templates/lru.h126
-rw-r--r--core/typedefs.h2
-rw-r--r--core/variant/variant_call.cpp4
-rw-r--r--core/variant/variant_construct.cpp25
-rw-r--r--core/variant/variant_internal.h19
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;