diff options
Diffstat (limited to 'core')
67 files changed, 594 insertions, 1822 deletions
diff --git a/core/SCsub b/core/SCsub index ed9a0a231d..755c5c65c6 100644 --- a/core/SCsub +++ b/core/SCsub @@ -80,6 +80,8 @@ if env['builtin_zlib']: env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir]) # Needs to be available in main env too env.Prepend(CPPPATH=[thirdparty_zlib_dir]) + if (env['target'] == 'debug'): + env_thirdparty.Append(CPPDEFINES=['ZLIB_DEBUG']) env_thirdparty.add_source_files(env.core_sources, thirdparty_zlib_sources) @@ -118,6 +120,8 @@ if env['builtin_zstd']: "compress/zstd_ldm.c", "compress/zstd_opt.c", "compress/zstdmt_compress.c", + "compress/zstd_compress_literals.c", + "compress/zstd_compress_sequences.c", "decompress/huf_decompress.c", "decompress/zstd_ddict.c", "decompress/zstd_decompress_block.c", diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index d07ba44788..1544503045 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -468,6 +468,16 @@ bool _OS::is_in_low_processor_usage_mode() const { return OS::get_singleton()->is_in_low_processor_usage_mode(); } +void _OS::set_low_processor_usage_mode_sleep_usec(int p_usec) { + + OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(p_usec); +} + +int _OS::get_low_processor_usage_mode_sleep_usec() const { + + return OS::get_singleton()->get_low_processor_usage_mode_sleep_usec(); +} + String _OS::get_executable_path() const { return OS::get_singleton()->get_executable_path(); @@ -1136,6 +1146,16 @@ bool _OS::request_permission(const String &p_name) { return OS::get_singleton()->request_permission(p_name); } +bool _OS::request_permissions() { + + return OS::get_singleton()->request_permissions(); +} + +Vector<String> _OS::get_granted_permissions() const { + + return OS::get_singleton()->get_granted_permissions(); +} + _OS *_OS::singleton = NULL; void _OS::_bind_methods() { @@ -1222,6 +1242,9 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("set_low_processor_usage_mode", "enable"), &_OS::set_low_processor_usage_mode); ClassDB::bind_method(D_METHOD("is_in_low_processor_usage_mode"), &_OS::is_in_low_processor_usage_mode); + ClassDB::bind_method(D_METHOD("set_low_processor_usage_mode_sleep_usec", "usec"), &_OS::set_low_processor_usage_mode_sleep_usec); + ClassDB::bind_method(D_METHOD("get_low_processor_usage_mode_sleep_usec"), &_OS::get_low_processor_usage_mode_sleep_usec); + ClassDB::bind_method(D_METHOD("get_processor_count"), &_OS::get_processor_count); ClassDB::bind_method(D_METHOD("get_executable_path"), &_OS::get_executable_path); @@ -1319,12 +1342,15 @@ void _OS::_bind_methods() { 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); + ClassDB::bind_method(D_METHOD("request_permissions"), &_OS::request_permissions); + ClassDB::bind_method(D_METHOD("get_granted_permissions"), &_OS::get_granted_permissions); 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"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vsync_enabled"), "set_use_vsync", "is_vsync_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "low_processor_usage_mode"), "set_low_processor_usage_mode", "is_in_low_processor_usage_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "low_processor_usage_mode_sleep_usec"), "set_low_processor_usage_mode_sleep_usec", "get_low_processor_usage_mode_sleep_usec"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_screen_on"), "set_keep_screen_on", "is_keep_screen_on"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "min_window_size"), "set_min_window_size", "get_min_window_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "max_window_size"), "set_max_window_size", "get_max_window_size"); @@ -1346,6 +1372,7 @@ void _OS::_bind_methods() { ADD_PROPERTY_DEFAULT("exit_code", 0); ADD_PROPERTY_DEFAULT("vsync_enabled", true); ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false); + ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900); ADD_PROPERTY_DEFAULT("keep_screen_on", true); ADD_PROPERTY_DEFAULT("min_window_size", Vector2()); ADD_PROPERTY_DEFAULT("max_window_size", Vector2()); @@ -3153,6 +3180,9 @@ Ref<JSONParseResult> _JSON::parse(const String &p_json) { result->error = JSON::parse(p_json, result->result, result->error_string, result->error_line); + if (result->error != OK) { + ERR_PRINTS(vformat("Error parsing JSON at line %s: %s", result->error_line, result->error_string)); + } return result; } diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 693b85710a..18182860c6 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -222,6 +222,9 @@ public: void set_low_processor_usage_mode(bool p_enabled); bool is_in_low_processor_usage_mode() const; + void set_low_processor_usage_mode_sleep_usec(int p_usec); + int get_low_processor_usage_mode_sleep_usec() const; + String get_executable_path() const; int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output = Array(), bool p_read_stderr = false); @@ -349,6 +352,8 @@ public: bool has_feature(const String &p_feature) const; bool request_permission(const String &p_name); + bool request_permissions(); + Vector<String> get_granted_permissions() const; static _OS *get_singleton() { return singleton; } diff --git a/core/color.cpp b/core/color.cpp index a54a3115cc..a6ad50b745 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -214,6 +214,11 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) { } } +bool Color::is_equal_approx(const Color &p_color) const { + + return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a); +} + void Color::invert() { r = 1.0 - r; diff --git a/core/color.h b/core/color.h index 8fb78d1ced..b34a82ef19 100644 --- a/core/color.h +++ b/core/color.h @@ -86,6 +86,8 @@ struct Color { void operator/=(const Color &p_color); void operator/=(const real_t &rvalue); + bool is_equal_approx(const Color &p_color) const; + void invert(); void contrast(); Color inverted() const; diff --git a/core/compressed_translation.cpp b/core/compressed_translation.cpp index f102721470..d927b74897 100644 --- a/core/compressed_translation.cpp +++ b/core/compressed_translation.cpp @@ -136,6 +136,8 @@ void PHashTranslation::generate(const Ref<Translation> &p_from) { bucket_table_size += 2 + b.size() * 4; } + ERR_FAIL_COND(bucket_table_size == 0); + hash_table.resize(size); bucket_table.resize(bucket_table_size); diff --git a/core/crypto/hashing_context.cpp b/core/crypto/hashing_context.cpp index bd863f546b..b5aa0ddc18 100644 --- a/core/crypto/hashing_context.cpp +++ b/core/crypto/hashing_context.cpp @@ -50,6 +50,7 @@ Error HashingContext::start(HashType p_type) { Error HashingContext::update(PoolByteArray p_chunk) { ERR_FAIL_COND_V(ctx == NULL, ERR_UNCONFIGURED); size_t len = p_chunk.size(); + ERR_FAIL_COND_V(len == 0, FAILED); PoolByteArray::Read r = p_chunk.read(); switch (type) { case HASH_MD5: diff --git a/core/dictionary.cpp b/core/dictionary.cpp index 5e4dfb9a5a..0d9945991e 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -192,13 +192,9 @@ uint32_t Dictionary::hash() const { uint32_t h = hash_djb2_one_32(Variant::DICTIONARY); - List<Variant> keys; - get_key_list(&keys); - - for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { - - h = hash_djb2_one_32(E->get().hash(), h); - h = hash_djb2_one_32(operator[](E->get()).hash(), h); + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { + h = hash_djb2_one_32(E.key().hash(), h); + h = hash_djb2_one_32(E.value().hash(), h); } return h; @@ -207,10 +203,11 @@ uint32_t Dictionary::hash() const { Array Dictionary::keys() const { Array varr; - varr.resize(size()); if (_p->variant_map.empty()) return varr; + varr.resize(size()); + int i = 0; for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { varr[i] = E.key(); @@ -223,10 +220,11 @@ Array Dictionary::keys() const { Array Dictionary::values() const { Array varr; - varr.resize(size()); if (_p->variant_map.empty()) return varr; + varr.resize(size()); + int i = 0; for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { varr[i] = E.get(); @@ -255,11 +253,8 @@ Dictionary Dictionary::duplicate(bool p_deep) const { Dictionary n; - List<Variant> keys; - get_key_list(&keys); - - for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { - n[E->get()] = p_deep ? operator[](E->get()).duplicate(p_deep) : operator[](E->get()); + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { + n[E.key()] = p_deep ? E.value().duplicate(true) : E.value(); } return n; diff --git a/core/error_macros.cpp b/core/error_macros.cpp index 0e8e4a9bb4..55a215cfb6 100644 --- a/core/error_macros.cpp +++ b/core/error_macros.cpp @@ -31,22 +31,11 @@ #include "error_macros.h" #include "core/io/logger.h" +#include "core/ustring.h" #include "os/os.h" -bool _err_error_exists = false; - static ErrorHandlerList *error_handler_list = NULL; -void _err_set_last_error(const char *p_err) { - - OS::get_singleton()->set_last_error(p_err); -} - -void _err_clear_last_error() { - - OS::get_singleton()->clear_last_error(); -} - void add_error_handler(ErrorHandlerList *p_handler) { _global_lock(); @@ -80,28 +69,47 @@ void remove_error_handler(ErrorHandlerList *p_handler) { } void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, ErrorHandlerType p_type) { + _err_print_error(p_function, p_file, p_line, p_error, "", p_type); +} + +void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, ErrorHandlerType p_type) { + _err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), "", p_type); +} - OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, _err_error_exists ? OS::get_singleton()->get_last_error() : "", (Logger::ErrorType)p_type); +void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, ErrorHandlerType p_type) { + + OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, p_message, (Logger::ErrorType)p_type); _global_lock(); ErrorHandlerList *l = error_handler_list; while (l) { - l->errfunc(l->userdata, p_function, p_file, p_line, p_error, _err_error_exists ? OS::get_singleton()->get_last_error() : "", p_type); + l->errfunc(l->userdata, p_function, p_file, p_line, p_error, p_message, p_type); l = l->next; } _global_unlock(); +} - if (_err_error_exists) { - OS::get_singleton()->clear_last_error(); - _err_error_exists = false; - } +void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, ErrorHandlerType p_type) { + _err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message, p_type); } -void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, bool fatal) { +void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, ErrorHandlerType p_type) { + _err_print_error(p_function, p_file, p_line, p_error, p_message.utf8().get_data(), p_type); +} + +void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, ErrorHandlerType p_type) { + _err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message.utf8().get_data(), p_type); +} + +void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message, bool fatal) { String fstr(fatal ? "FATAL: " : ""); String err(fstr + "Index " + p_index_str + "=" + itos(p_index) + " out of size (" + p_size_str + "=" + itos(p_size) + ")"); - _err_print_error(p_function, p_file, p_line, err.utf8().get_data()); + _err_print_error(p_function, p_file, p_line, err.utf8().get_data(), p_message); +} + +void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool fatal) { + _err_print_index_error(p_function, p_file, p_line, p_index, p_size, p_index_str, p_size_str, p_message.utf8().get_data(), fatal); } diff --git a/core/error_macros.h b/core/error_macros.h index 65802de9d2..00e830f73a 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -55,9 +55,8 @@ enum ErrorHandlerType { ERR_HANDLER_SHADER, }; +class String; typedef void (*ErrorHandlerFunc)(void *, const char *, const char *, int p_line, const char *, const char *, ErrorHandlerType p_type); -void _err_set_last_error(const char *p_err); -void _err_clear_last_error(); struct ErrorHandlerList { @@ -77,7 +76,13 @@ void add_error_handler(ErrorHandlerList *p_handler); void remove_error_handler(ErrorHandlerList *p_handler); void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, ErrorHandlerType p_type = ERR_HANDLER_ERROR); -void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, bool fatal = false); +void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const String &p_message, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, ErrorHandlerType p_type = ERR_HANDLER_ERROR); +void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const char *p_message = "", bool fatal = false); +void _err_print_index_error(const char *p_function, const char *p_file, int p_line, int64_t p_index, int64_t p_size, const char *p_index_str, const char *p_size_str, const String &p_message, bool fatal = false); #ifndef _STR #define _STR(m_x) #m_x @@ -88,29 +93,6 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li /** An index has failed if m_index<0 or m_index >=m_size, the function exits */ -extern bool _err_error_exists; - -#ifdef DEBUG_ENABLED -/** Print a warning string. - */ -#define ERR_EXPLAINC(m_reason) \ - { \ - _err_set_last_error(m_reason); \ - _err_error_exists = true; \ - } -#define ERR_EXPLAIN(m_string) \ - { \ - _err_set_last_error(String(m_string).utf8().get_data()); \ - _err_error_exists = true; \ - } - -#else - -#define ERR_EXPLAIN(m_text) -#define ERR_EXPLAINC(m_text) - -#endif - #ifdef __GNUC__ //#define FUNCTION_STR __PRETTY_FUNCTION__ - too annoying #define FUNCTION_STR __FUNCTION__ @@ -129,6 +111,13 @@ extern bool _err_error_exists; #define GENERATE_TRAP __builtin_trap(); #endif +// Used to strip debug messages in release mode +#ifdef DEBUG_ENABLED +#define DEBUG_STR(m_msg) m_msg +#else +#define DEBUG_STR(m_msg) "" +#endif + // (*): See https://stackoverflow.com/questions/257418/do-while-0-what-is-it-good-for #define ERR_FAIL_INDEX(m_index, m_size) \ @@ -137,17 +126,14 @@ extern bool _err_error_exists; _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ return; \ } \ - _err_error_exists = false; \ } while (0); // (*) -#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ - return; \ - } \ - _err_error_exists = false; \ +#define ERR_FAIL_INDEX_MSG(m_index, m_size, m_msg) \ + do { \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ + return; \ + } \ } while (0); // (*) /** An index has failed if m_index<0 or m_index >=m_size, the function exits. @@ -161,17 +147,14 @@ extern bool _err_error_exists; _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ return m_retval; \ } \ - _err_error_exists = false; \ } while (0); // (*) -#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ - return m_retval; \ - } \ - _err_error_exists = false; \ +#define ERR_FAIL_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ + do { \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ + return m_retval; \ + } \ } while (0); // (*) /** An index has failed if m_index >=m_size, the function exits. @@ -185,37 +168,33 @@ extern bool _err_error_exists; _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ return m_retval; \ } \ - _err_error_exists = false; \ } while (0); // (*) -#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ - do { \ - if (unlikely((m_index) >= (m_size))) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size)); \ - return m_retval; \ - } \ - _err_error_exists = false; \ +#define ERR_FAIL_UNSIGNED_INDEX_V_MSG(m_index, m_size, m_retval, m_msg) \ + do { \ + if (unlikely((m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), DEBUG_STR(m_msg)); \ + return m_retval; \ + } \ } while (0); // (*) /** Use this one if there is no sensible fallback, that is, the error is unrecoverable. * We'll return a null reference and try to keep running. */ -#define CRASH_BAD_INDEX(m_index, m_size) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), true); \ - GENERATE_TRAP \ - } \ +#define CRASH_BAD_INDEX(m_index, m_size) \ + do { \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), "", true); \ + GENERATE_TRAP \ + } \ } while (0); // (*) -#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \ - do { \ - if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), true); \ - GENERATE_TRAP \ - } \ +#define CRASH_BAD_INDEX_MSG(m_index, m_size, m_msg) \ + do { \ + if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \ + _err_print_index_error(FUNCTION_STR, __FILE__, __LINE__, m_index, m_size, _STR(m_index), _STR(m_size), m_msg, true); \ + GENERATE_TRAP \ + } \ } while (0); // (*) /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert(). @@ -228,17 +207,14 @@ extern bool _err_error_exists; _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null."); \ return; \ } \ - _err_error_exists = false; \ } -#define ERR_FAIL_NULL_MSG(m_param, m_msg) \ - { \ - if (unlikely(!m_param)) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null."); \ - return; \ - } \ - _err_error_exists = false; \ +#define ERR_FAIL_NULL_MSG(m_param, m_msg) \ + { \ + if (unlikely(!m_param)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null.", DEBUG_STR(m_msg)); \ + return; \ + } \ } #define ERR_FAIL_NULL_V(m_param, m_retval) \ @@ -247,17 +223,14 @@ extern bool _err_error_exists; _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null."); \ return m_retval; \ } \ - _err_error_exists = false; \ } -#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \ - { \ - if (unlikely(!m_param)) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null."); \ - return m_retval; \ - } \ - _err_error_exists = false; \ +#define ERR_FAIL_NULL_V_MSG(m_param, m_retval, m_msg) \ + { \ + if (unlikely(!m_param)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter ' " _STR(m_param) " ' is null.", DEBUG_STR(m_msg)); \ + return m_retval; \ + } \ } /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert(). @@ -270,17 +243,14 @@ extern bool _err_error_exists; _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true."); \ return; \ } \ - _err_error_exists = false; \ } -#define ERR_FAIL_COND_MSG(m_cond, m_msg) \ - { \ - if (unlikely(m_cond)) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true."); \ - return; \ - } \ - _err_error_exists = false; \ +#define ERR_FAIL_COND_MSG(m_cond, m_msg) \ + { \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true.", DEBUG_STR(m_msg)); \ + return; \ + } \ } /** Use this one if there is no sensible fallback, that is, the error is unrecoverable. @@ -294,13 +264,12 @@ extern bool _err_error_exists; } \ } -#define CRASH_COND_MSG(m_cond, m_msg) \ - { \ - if (unlikely(m_cond)) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition ' " _STR(m_cond) " ' is true."); \ - GENERATE_TRAP \ - } \ +#define CRASH_COND_MSG(m_cond, m_msg) \ + { \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Condition ' " _STR(m_cond) " ' is true.", DEBUG_STR(m_msg)); \ + GENERATE_TRAP \ + } \ } /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert(). @@ -315,17 +284,14 @@ extern bool _err_error_exists; _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. returned: " _STR(m_retval)); \ return m_retval; \ } \ - _err_error_exists = false; \ } -#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \ - { \ - if (unlikely(m_cond)) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. returned: " _STR(m_retval)); \ - return m_retval; \ - } \ - _err_error_exists = false; \ +#define ERR_FAIL_COND_V_MSG(m_cond, m_retval, m_msg) \ + { \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. returned: " _STR(m_retval), DEBUG_STR(m_msg)); \ + return m_retval; \ + } \ } /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert(). @@ -338,17 +304,14 @@ extern bool _err_error_exists; _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Continuing..:"); \ continue; \ } \ - _err_error_exists = false; \ } -#define ERR_CONTINUE_MSG(m_cond, m_msg) \ - { \ - if (unlikely(m_cond)) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Continuing..:"); \ - continue; \ - } \ - _err_error_exists = false; \ +#define ERR_CONTINUE_MSG(m_cond, m_msg) \ + { \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Continuing..:", DEBUG_STR(m_msg)); \ + continue; \ + } \ } /** An error condition happened (m_cond tested true) (WARNING this is the opposite as assert(). @@ -361,17 +324,14 @@ extern bool _err_error_exists; _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:"); \ break; \ } \ - _err_error_exists = false; \ } -#define ERR_BREAK_MSG(m_cond, m_msg) \ - { \ - if (unlikely(m_cond)) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:"); \ - break; \ - } \ - _err_error_exists = false; \ +#define ERR_BREAK_MSG(m_cond, m_msg) \ + { \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:", DEBUG_STR(m_msg)); \ + break; \ + } \ } /** Print an error string and return @@ -380,14 +340,13 @@ extern bool _err_error_exists; #define ERR_FAIL() \ { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed."); \ - _err_error_exists = false; \ return; \ } -#define ERR_FAIL_MSG(m_msg) \ - { \ - ERR_EXPLAIN(m_msg); \ - ERR_FAIL(); \ +#define ERR_FAIL_MSG(m_msg) \ + { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed.", DEBUG_STR(m_msg)); \ + return; \ } /** Print an error string and return with value @@ -396,14 +355,13 @@ extern bool _err_error_exists; #define ERR_FAIL_V(m_value) \ { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed, returning: " __STR(m_value)); \ - _err_error_exists = false; \ return m_value; \ } -#define ERR_FAIL_V_MSG(m_value, m_msg) \ - { \ - ERR_EXPLAIN(m_msg); \ - ERR_FAIL_V(m_value); \ +#define ERR_FAIL_V_MSG(m_value, m_msg) \ + { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/Function Failed, returning: " __STR(m_value), DEBUG_STR(m_msg)); \ + return m_value; \ } /** Use this one if there is no sensible fallback, that is, the error is unrecoverable. @@ -415,10 +373,10 @@ extern bool _err_error_exists; GENERATE_TRAP \ } -#define CRASH_NOW_MSG(m_msg) \ - { \ - ERR_EXPLAIN(m_msg); \ - CRASH_NOW(); \ +#define CRASH_NOW_MSG(m_msg) \ + { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "FATAL: Method/Function Failed.", DEBUG_STR(m_msg)); \ + GENERATE_TRAP \ } /** Print an error string. @@ -427,13 +385,11 @@ extern bool _err_error_exists; #define ERR_PRINT(m_string) \ { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_string); \ - _err_error_exists = false; \ } -#define ERR_PRINTS(m_string) \ - { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, String(m_string).utf8().get_data()); \ - _err_error_exists = false; \ +#define ERR_PRINTS(m_string) \ + { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_string); \ } #define ERR_PRINT_ONCE(m_string) \ @@ -441,7 +397,6 @@ extern bool _err_error_exists; static bool first_print = true; \ if (first_print) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_string); \ - _err_error_exists = false; \ first_print = false; \ } \ } @@ -452,13 +407,11 @@ extern bool _err_error_exists; #define WARN_PRINT(m_string) \ { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_string, ERR_HANDLER_WARNING); \ - _err_error_exists = false; \ } -#define WARN_PRINTS(m_string) \ - { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, String(m_string).utf8().get_data(), ERR_HANDLER_WARNING); \ - _err_error_exists = false; \ +#define WARN_PRINTS(m_string) \ + { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_string, ERR_HANDLER_WARNING); \ } #define WARN_PRINT_ONCE(m_string) \ @@ -466,7 +419,6 @@ extern bool _err_error_exists; 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; \ } \ } @@ -476,20 +428,17 @@ extern bool _err_error_exists; static volatile bool warning_shown = false; \ if (!warning_shown) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future", ERR_HANDLER_WARNING); \ - _err_error_exists = false; \ warning_shown = true; \ } \ } -#define WARN_DEPRECATED_MSG(m_msg) \ - { \ - static volatile bool warning_shown = false; \ - if (!warning_shown) { \ - ERR_EXPLAIN(m_msg); \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future", ERR_HANDLER_WARNING); \ - _err_error_exists = false; \ - warning_shown = true; \ - } \ +#define WARN_DEPRECATED_MSG(m_msg) \ + { \ + static volatile bool warning_shown = false; \ + if (!warning_shown) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future", m_msg, ERR_HANDLER_WARNING); \ + warning_shown = true; \ + } \ } #endif diff --git a/core/hash_map.h b/core/hash_map.h index 38da1d59ab..edc67e7806 100644 --- a/core/hash_map.h +++ b/core/hash_map.h @@ -210,6 +210,7 @@ private: e->next = hash_table[index]; e->hash = hash; e->pair.key = p_key; + e->pair.data = TData(); hash_table[index] = e; elements++; diff --git a/core/image.cpp b/core/image.cpp index e0b0a1f8be..74706535b3 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -885,8 +885,8 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */; - ERR_FAIL_COND_MSG(p_width <= 0, "Image width cannot be greater than 0."); - ERR_FAIL_COND_MSG(p_height <= 0, "Image height cannot be greater than 0."); + ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0."); + ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0."); ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + "."); ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + "."); @@ -1284,8 +1284,8 @@ static void _generate_po2_mipmap(const Component *p_src, Component *p_dst, uint3 Component *dst_ptr = &p_dst[i * dst_w * CC]; uint32_t count = dst_w; - while (count--) { - + while (count) { + count--; for (int j = 0; j < CC; j++) { average_func(dst_ptr[j], rup_ptr[j], rup_ptr[j + right_step], rdown_ptr[j], rdown_ptr[j + right_step]); } @@ -1322,6 +1322,8 @@ void Image::expand_x2_hq2x() { PoolVector<uint8_t>::Read r = data.read(); PoolVector<uint8_t>::Write w = dest.write(); + ERR_FAIL_COND(!r.ptr()); + hq2x_resize((const uint32_t *)r.ptr(), width, height, (uint32_t *)w.ptr()); } @@ -1373,6 +1375,7 @@ void Image::shrink_x2() { int ps = get_format_pixel_size(format); new_img.resize((width / 2) * (height / 2) * ps); ERR_FAIL_COND(new_img.size() == 0); + ERR_FAIL_COND(data.size() == 0); { PoolVector<uint8_t>::Write w = new_img.write(); @@ -2895,6 +2898,8 @@ void Image::bumpmap_to_normalmap(float bump_scale) { PoolVector<uint8_t>::Read rp = data.read(); PoolVector<uint8_t>::Write wp = result_image.write(); + ERR_FAIL_COND(!rp.ptr()); + unsigned char *write_ptr = wp.ptr(); float *read_ptr = (float *)rp.ptr(); @@ -2930,7 +2935,7 @@ void Image::srgb_to_linear() { if (data.size() == 0) return; - static const uint8_t srgb2lin[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 26, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54, 55, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87, 88, 89, 90, 92, 93, 94, 95, 97, 98, 99, 101, 102, 103, 105, 106, 107, 109, 110, 112, 113, 114, 116, 117, 119, 120, 122, 123, 125, 126, 128, 129, 131, 132, 134, 135, 137, 139, 140, 142, 144, 145, 147, 148, 150, 152, 153, 155, 157, 159, 160, 162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 188, 190, 192, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 235, 237, 239, 241, 243, 245, 248, 250, 252 }; + static const uint8_t srgb2lin[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 26, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 33, 34, 35, 36, 36, 37, 38, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 47, 48, 49, 50, 51, 52, 53, 54, 55, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 87, 88, 89, 90, 92, 93, 94, 95, 97, 98, 99, 101, 102, 103, 105, 106, 107, 109, 110, 112, 113, 114, 116, 117, 119, 120, 122, 123, 125, 126, 128, 129, 131, 132, 134, 135, 137, 139, 140, 142, 144, 145, 147, 148, 150, 152, 153, 155, 157, 159, 160, 162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 188, 190, 192, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 235, 237, 239, 241, 243, 245, 248, 250, 252, 255 }; ERR_FAIL_COND(format != FORMAT_RGB8 && format != FORMAT_RGBA8); diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 170bef4430..1904c70f42 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -98,6 +98,8 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) { + ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object."); + close(); connection = p_connection; status = STATUS_CONNECTED; @@ -713,6 +715,10 @@ void HTTPClient::set_read_chunk_size(int p_size) { read_chunk_size = p_size; } +int HTTPClient::get_read_chunk_size() const { + return read_chunk_size; +} + HTTPClient::HTTPClient() { tcp_connection.instance(); @@ -816,6 +822,7 @@ void HTTPClient::_bind_methods() { ClassDB::bind_method(D_METHOD("get_response_body_length"), &HTTPClient::get_response_body_length); ClassDB::bind_method(D_METHOD("read_response_body_chunk"), &HTTPClient::read_response_body_chunk); ClassDB::bind_method(D_METHOD("set_read_chunk_size", "bytes"), &HTTPClient::set_read_chunk_size); + ClassDB::bind_method(D_METHOD("get_read_chunk_size"), &HTTPClient::get_read_chunk_size); ClassDB::bind_method(D_METHOD("set_blocking_mode", "enabled"), &HTTPClient::set_blocking_mode); ClassDB::bind_method(D_METHOD("is_blocking_mode_enabled"), &HTTPClient::is_blocking_mode_enabled); @@ -827,6 +834,7 @@ void HTTPClient::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blocking_mode_enabled"), "set_blocking_mode", "is_blocking_mode_enabled"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "connection", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", 0), "set_connection", "get_connection"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "read_chunk_size", PROPERTY_HINT_RANGE, "256,16777216"), "set_read_chunk_size", "get_read_chunk_size"); BIND_ENUM_CONSTANT(METHOD_GET); BIND_ENUM_CONSTANT(METHOD_HEAD); diff --git a/core/io/http_client.h b/core/io/http_client.h index 85ee1959a2..ce7fe0491b 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -220,6 +220,7 @@ public: bool is_blocking_mode_enabled() const; void set_read_chunk_size(int p_size); + int get_read_chunk_size() const; Error poll(); diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 0ba84d0c8f..1426dbbd4d 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -602,7 +602,16 @@ void MultiplayerAPI::_add_peer(int p_id) { void MultiplayerAPI::_del_peer(int p_id) { connected_peers.erase(p_id); - path_get_cache.erase(p_id); // I no longer need your cache, sorry. + // Cleanup get cache. + path_get_cache.erase(p_id); + // Cleanup sent cache. + // Some refactoring is needed to make this faster and do paths GC. + List<NodePath> keys; + path_send_cache.get_key_list(&keys); + for (List<NodePath>::Element *E = keys.front(); E; E = E->next()) { + PathSentCache *psc = path_send_cache.getptr(E->get()); + psc->confirmed_peers.erase(p_id); + } emit_signal("network_peer_disconnected", p_id); } diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 821a04ebad..23dfc58385 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -279,6 +279,7 @@ Ref<StreamPeer> PacketPeerStream::get_stream_peer() const { void PacketPeerStream::set_input_buffer_max_size(int p_max_size) { + ERR_FAIL_COND_MSG(p_max_size < 0, "Max size of input buffer size cannot be smaller than 0."); //warning may lose packets ERR_FAIL_COND_MSG(ring_buffer.data_left(), "Buffer in use, resizing would cause loss of data."); ring_buffer.resize(nearest_shift(p_max_size + 4)); diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index ae2b56e7b7..bfa8b90344 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -164,36 +164,59 @@ void AStar::connect_points(int p_id, int p_with_id, bool bidirectional) { } Segment s(p_id, p_with_id); - if (s.from == p_id) { - s.from_point = a; - s.to_point = b; - } else { - s.from_point = b; - s.to_point = a; + if (bidirectional) s.direction = Segment::BIDIRECTIONAL; + + Set<Segment>::Element *element = segments.find(s); + if (element != NULL) { + s.direction |= element->get().direction; + if (s.direction == Segment::BIDIRECTIONAL) { + // Both are neighbours of each other now + a->unlinked_neighbours.remove(b->id); + b->unlinked_neighbours.remove(a->id); + } + segments.erase(element); } segments.insert(s); } -void AStar::disconnect_points(int p_id, int p_with_id) { - - Segment s(p_id, p_with_id); - ERR_FAIL_COND(!segments.has(s)); - - segments.erase(s); +void AStar::disconnect_points(int p_id, int p_with_id, bool bidirectional) { Point *a; bool a_exists = points.lookup(p_id, a); - CRASH_COND(!a_exists); + ERR_FAIL_COND(!a_exists); Point *b; bool b_exists = points.lookup(p_with_id, b); - CRASH_COND(!b_exists); + ERR_FAIL_COND(!b_exists); + + Segment s(p_id, p_with_id); + int remove_direction = bidirectional ? (int)Segment::BIDIRECTIONAL : s.direction; + + Set<Segment>::Element *element = segments.find(s); + if (element != NULL) { + // s is the new segment + // Erase the directions to be removed + s.direction = (element->get().direction & ~remove_direction); + + a->neighbours.remove(b->id); + if (bidirectional) { + b->neighbours.remove(a->id); + if (element->get().direction != Segment::BIDIRECTIONAL) { + a->unlinked_neighbours.remove(b->id); + b->unlinked_neighbours.remove(a->id); + } + } else { + if (s.direction == Segment::NONE) + b->unlinked_neighbours.remove(a->id); + else + a->unlinked_neighbours.set(b->id, b); + } - a->neighbours.remove(b->id); - a->unlinked_neighbours.remove(b->id); - b->neighbours.remove(a->id); - b->unlinked_neighbours.remove(a->id); + segments.erase(element); + if (s.direction != Segment::NONE) + segments.insert(s); + } } bool AStar::has_point(int p_id) const { @@ -227,10 +250,13 @@ PoolVector<int> AStar::get_point_connections(int p_id) { return point_list; } -bool AStar::are_points_connected(int p_id, int p_with_id) const { +bool AStar::are_points_connected(int p_id, int p_with_id, bool bidirectional) const { Segment s(p_id, p_with_id); - return segments.has(s); + const Set<Segment>::Element *element = segments.find(s); + + return element != NULL && + (bidirectional || (element->get().direction & s.direction) == s.direction); } void AStar::clear() { @@ -284,13 +310,17 @@ Vector3 AStar::get_closest_position_in_segment(const Vector3 &p_point) const { for (const Set<Segment>::Element *E = segments.front(); E; E = E->next()) { - if (!(E->get().from_point->enabled && E->get().to_point->enabled)) { + Point *from_point = nullptr, *to_point = nullptr; + points.lookup(E->get().u, from_point); + points.lookup(E->get().v, to_point); + + if (!(from_point->enabled && to_point->enabled)) { continue; } Vector3 segment[2] = { - E->get().from_point->pos, - E->get().to_point->pos, + from_point->pos, + to_point->pos, }; Vector3 p = Geometry::get_closest_point_to_segment(p_point, segment); @@ -376,11 +406,11 @@ float AStar::_estimate_cost(int p_from_id, int p_to_id) { Point *from_point; bool from_exists = points.lookup(p_from_id, from_point); - CRASH_COND(!from_exists); + ERR_FAIL_COND_V(!from_exists, 0); Point *to_point; bool to_exists = points.lookup(p_to_id, to_point); - CRASH_COND(!to_exists); + ERR_FAIL_COND_V(!to_exists, 0); return from_point->pos.distance_to(to_point->pos); } @@ -392,11 +422,11 @@ float AStar::_compute_cost(int p_from_id, int p_to_id) { Point *from_point; bool from_exists = points.lookup(p_from_id, from_point); - CRASH_COND(!from_exists); + ERR_FAIL_COND_V(!from_exists, 0); Point *to_point; bool to_exists = points.lookup(p_to_id, to_point); - CRASH_COND(!to_exists); + ERR_FAIL_COND_V(!to_exists, 0); return from_point->pos.distance_to(to_point->pos); } @@ -532,8 +562,8 @@ void AStar::_bind_methods() { ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar::is_point_disabled); ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar::connect_points, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar::disconnect_points); - ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id"), &AStar::are_points_connected); + ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id", "bidirectional"), &AStar::disconnect_points, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id", "bidirectional"), &AStar::are_points_connected, DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_point_count"), &AStar::get_point_count); ClassDB::bind_method(D_METHOD("get_point_capacity"), &AStar::get_point_capacity); diff --git a/core/math/a_star.h b/core/math/a_star.h index 0a5d3e992c..8ff62e646b 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -81,24 +81,35 @@ class AStar : public Reference { struct Segment { union { struct { - int32_t from; - int32_t to; + int32_t u; + int32_t v; }; uint64_t key; }; - Point *from_point; - Point *to_point; + enum { + NONE = 0, + FORWARD = 1, + BACKWARD = 2, + BIDIRECTIONAL = FORWARD | BACKWARD + }; + unsigned char direction; bool operator<(const Segment &p_s) const { return key < p_s.key; } - Segment() { key = 0; } + Segment() { + key = 0; + direction = NONE; + } Segment(int p_from, int p_to) { - if (p_from > p_to) { - SWAP(p_from, p_to); + if (p_from < p_to) { + u = p_from; + v = p_to; + direction = FORWARD; + } else { + u = p_to; + v = p_from; + direction = BACKWARD; } - - from = p_from; - to = p_to; } }; @@ -133,8 +144,8 @@ public: bool is_point_disabled(int p_id) const; void connect_points(int p_id, int p_with_id, bool bidirectional = true); - void disconnect_points(int p_id, int p_with_id); - bool are_points_connected(int p_id, int p_with_id) const; + void disconnect_points(int p_id, int p_with_id, bool bidirectional = true); + bool are_points_connected(int p_id, int p_with_id, bool bidirectional = true) const; int get_point_count() const; int get_point_capacity() const; diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp index a4eb1fe2a5..27da061274 100644 --- a/core/math/aabb.cpp +++ b/core/math/aabb.cpp @@ -69,6 +69,11 @@ void AABB::merge_with(const AABB &p_aabb) { size = max - min; } +bool AABB::is_equal_approx(const AABB &p_aabb) const { + + return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size); +} + AABB AABB::intersection(const AABB &p_aabb) const { Vector3 src_min = position; diff --git a/core/math/aabb.h b/core/math/aabb.h index 52e5ed3626..c3ce33c6f4 100644 --- a/core/math/aabb.h +++ b/core/math/aabb.h @@ -64,6 +64,7 @@ public: bool operator==(const AABB &p_rval) const; bool operator!=(const AABB &p_rval) const; + bool is_equal_approx(const AABB &p_aabb) const; _FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap _FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap _FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 0a491010e2..d77501c0f6 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -106,17 +106,17 @@ Basis Basis::orthonormalized() const { } bool Basis::is_orthogonal() const { - Basis id; + Basis identity; Basis m = (*this) * transposed(); - return is_equal_approx(id, m); + return m.is_equal_approx(identity); } bool Basis::is_diagonal() const { return ( - Math::is_equal_approx(elements[0][1], 0) && Math::is_equal_approx(elements[0][2], 0) && - Math::is_equal_approx(elements[1][0], 0) && Math::is_equal_approx(elements[1][2], 0) && - Math::is_equal_approx(elements[2][0], 0) && Math::is_equal_approx(elements[2][1], 0)); + Math::is_zero_approx(elements[0][1]) && Math::is_zero_approx(elements[0][2]) && + Math::is_zero_approx(elements[1][0]) && Math::is_zero_approx(elements[1][2]) && + Math::is_zero_approx(elements[2][0]) && Math::is_zero_approx(elements[2][1])); } bool Basis::is_rotation() const { @@ -557,16 +557,9 @@ void Basis::set_euler_yxz(const Vector3 &p_euler) { *this = ymat * xmat * zmat; } -bool Basis::is_equal_approx(const Basis &a, const Basis &b, real_t p_epsilon) const { +bool Basis::is_equal_approx(const Basis &p_basis) const { - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (!Math::is_equal_approx(a.elements[i][j], b.elements[i][j], p_epsilon)) - return false; - } - } - - return true; + return elements[0].is_equal_approx(p_basis.elements[0]) && elements[1].is_equal_approx(p_basis.elements[1]) && elements[2].is_equal_approx(p_basis.elements[2]); } bool Basis::is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon) const { diff --git a/core/math/basis.h b/core/math/basis.h index 4be4ea4cd3..9b2e38b3d3 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -127,7 +127,9 @@ 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, real_t p_epsilon = CMP_EPSILON) const; + bool is_equal_approx(const Basis &p_basis) const; + // TODO: Break compatibility in 4.0 by getting rid of this so that it's only an instance method. See also TODO in variant_call.cpp + bool is_equal_approx(const Basis &a, const Basis &b) const { return a.is_equal_approx(b); } 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; diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp index cfa698282e..ece293d036 100644 --- a/core/math/bsp_tree.cpp +++ b/core/math/bsp_tree.cpp @@ -364,7 +364,7 @@ static int _bsp_create_node(const Face3 *p_faces, const Vector<int> &p_indices, const Face3 &f = p_faces[indices[i]]; /* - if (f.get_plane().is_almost_like(divisor_plane)) + if (f.get_plane().is_equal_approx(divisor_plane)) continue; */ @@ -412,7 +412,7 @@ static int _bsp_create_node(const Face3 *p_faces, const Vector<int> &p_indices, for (int i = 0; i < p_planes.size(); i++) { - if (p_planes[i].is_almost_like(divisor_plane)) { + if (p_planes[i].is_equal_approx(divisor_plane)) { divisor_plane_idx = i; break; } diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 30c0cab909..b9b0f4ac54 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -183,6 +183,10 @@ void CameraMatrix::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear void CameraMatrix::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) { + ERR_FAIL_COND(p_right <= p_left); + ERR_FAIL_COND(p_top <= p_bottom); + ERR_FAIL_COND(p_far <= p_near); + real_t *te = &matrix[0][0]; real_t x = 2 * p_near / (p_right - p_left); real_t y = 2 * p_near / (p_top - p_bottom); diff --git a/core/math/delaunay.h b/core/math/delaunay.h index 3f8013a3e6..89a34de082 100644 --- a/core/math/delaunay.h +++ b/core/math/delaunay.h @@ -80,11 +80,11 @@ public: } static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) { - if (p_vertices[p_a.edge[0]] == p_vertices[p_b.edge[0]] && p_vertices[p_a.edge[1]] == p_vertices[p_b.edge[1]]) { + if (p_vertices[p_a.edge[0]].is_equal_approx(p_vertices[p_b.edge[0]]) && p_vertices[p_a.edge[1]].is_equal_approx(p_vertices[p_b.edge[1]])) { return true; } - if (p_vertices[p_a.edge[0]] == p_vertices[p_b.edge[1]] && p_vertices[p_a.edge[1]] == p_vertices[p_b.edge[0]]) { + if (p_vertices[p_a.edge[0]].is_equal_approx(p_vertices[p_b.edge[1]]) && p_vertices[p_a.edge[1]].is_equal_approx(p_vertices[p_b.edge[0]])) { return true; } diff --git a/core/math/face3.cpp b/core/math/face3.cpp index ab09142b2d..666d214f98 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -393,7 +393,7 @@ Vector3 Face3::get_closest_point_to(const Vector3 &p_point) const { s = CLAMP(numer / denom, 0.f, 1.f); t = 1 - s; } else { - s = CLAMP(-e / c, 0.f, 1.f); + s = CLAMP(-d / a, 0.f, 1.f); t = 0.f; } } else { diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 9078abea68..a94b27fcc5 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -472,7 +472,7 @@ public: return p_step != 0 ? Math::stepify(p_target - p_offset, p_step) + p_offset : p_target; } - static _ALWAYS_INLINE_ float snap_scalar_seperation(float p_offset, float p_step, float p_target, float p_separation) { + static _ALWAYS_INLINE_ float snap_scalar_separation(float p_offset, float p_step, float p_target, float p_separation) { if (p_step != 0) { float a = Math::stepify(p_target - p_offset, p_step + p_separation) + p_offset; float b = a; diff --git a/core/math/plane.cpp b/core/math/plane.cpp index b01853c4ac..d55957cd0a 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -32,9 +32,6 @@ #include "core/math/math_funcs.h" -#define _PLANE_EQ_DOT_EPSILON 0.999 -#define _PLANE_EQ_D_EPSILON 0.0001 - void Plane::set_normal(const Vector3 &p_normal) { normal = p_normal; @@ -91,7 +88,7 @@ bool Plane::intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r real_t denom = vec3_cross(normal0, normal1).dot(normal2); - if (ABS(denom) <= CMP_EPSILON) + if (Math::is_zero_approx(denom)) return false; if (r_result) { @@ -156,9 +153,9 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec /* misc */ -bool Plane::is_almost_like(const Plane &p_plane) const { +bool Plane::is_equal_approx(const Plane &p_plane) const { - return (normal.dot(p_plane.normal) > _PLANE_EQ_DOT_EPSILON && Math::absd(d - p_plane.d) < _PLANE_EQ_D_EPSILON); + return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d); } Plane::operator String() const { diff --git a/core/math/plane.h b/core/math/plane.h index ec817edd2c..9abf24fbba 100644 --- a/core/math/plane.h +++ b/core/math/plane.h @@ -68,7 +68,7 @@ public: /* misc */ Plane operator-() const { return Plane(-normal, -d); } - bool is_almost_like(const Plane &p_plane) const; + bool is_equal_approx(const Plane &p_plane) const; _FORCE_INLINE_ bool operator==(const Plane &p_plane) const; _FORCE_INLINE_ bool operator!=(const Plane &p_plane) const; @@ -125,12 +125,12 @@ Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_ bool Plane::operator==(const Plane &p_plane) const { - return normal == p_plane.normal && Math::is_equal_approx(d, p_plane.d); + return normal == p_plane.normal && d == p_plane.d; } bool Plane::operator!=(const Plane &p_plane) const { - return normal != p_plane.normal || !Math::is_equal_approx(d, p_plane.d); + return normal != p_plane.normal || d != p_plane.d; } #endif // PLANE_H diff --git a/core/math/quat.cpp b/core/math/quat.cpp index 1a67be7384..a4f91844b9 100644 --- a/core/math/quat.cpp +++ b/core/math/quat.cpp @@ -121,6 +121,11 @@ Quat Quat::operator*(const Quat &q) const { return r; } +bool Quat::is_equal_approx(const Quat &p_quat) const { + + return Math::is_equal_approx(x, p_quat.x) && Math::is_equal_approx(y, p_quat.y) && Math::is_equal_approx(z, p_quat.z) && Math::is_equal_approx(w, p_quat.w); +} + real_t Quat::length() const { return Math::sqrt(length_squared()); diff --git a/core/math/quat.h b/core/math/quat.h index 3d6602e466..27885f4152 100644 --- a/core/math/quat.h +++ b/core/math/quat.h @@ -43,6 +43,7 @@ public: real_t x, y, z, w; _FORCE_INLINE_ real_t length_squared() const; + bool is_equal_approx(const Quat &p_quat) const; real_t length() const; void normalize(); Quat normalized() const; diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index fc2eb1454d..f71f00afd6 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -401,7 +401,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me ERR_CONTINUE(O == E); ERR_CONTINUE(O == NULL); - if (O->get().plane.is_almost_like(f.plane)) { + if (O->get().plane.is_equal_approx(f.plane)) { //merge and delete edge and contiguous face, while repointing edges (uuugh!) int ois = O->get().indices.size(); int merged = 0; diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp index fea128afbd..e31776672e 100644 --- a/core/math/rect2.cpp +++ b/core/math/rect2.cpp @@ -30,6 +30,11 @@ #include "core/math/transform_2d.h" // Includes rect2.h but Rect2 needs Transform2D +bool Rect2::is_equal_approx(const Rect2 &p_rect) const { + + return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size); +} + bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const { real_t min = 0, max = 1; diff --git a/core/math/rect2.h b/core/math/rect2.h index f58756ee40..71221ffb1b 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -153,6 +153,7 @@ struct Rect2 { return true; } + bool is_equal_approx(const Rect2 &p_rect) const; bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; } bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } diff --git a/core/math/transform.cpp b/core/math/transform.cpp index 4056975da8..5dcc6ab9f0 100644 --- a/core/math/transform.cpp +++ b/core/math/transform.cpp @@ -182,6 +182,11 @@ Transform Transform::orthonormalized() const { return _copy; } +bool Transform::is_equal_approx(const Transform &p_transform) const { + + return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin); +} + bool Transform::operator==(const Transform &p_transform) const { return (basis == p_transform.basis && origin == p_transform.origin); diff --git a/core/math/transform.h b/core/math/transform.h index 90e2b07583..da65a183cf 100644 --- a/core/math/transform.h +++ b/core/math/transform.h @@ -70,6 +70,7 @@ public: void orthonormalize(); Transform orthonormalized() const; + bool is_equal_approx(const Transform &p_transform) const; bool operator==(const Transform &p_transform) const; bool operator!=(const Transform &p_transform) const; diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 1d0387bd45..a1c0814637 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -147,6 +147,7 @@ void Transform2D::orthonormalize() { elements[0] = x; elements[1] = y; } + Transform2D Transform2D::orthonormalized() const { Transform2D on = *this; @@ -154,6 +155,11 @@ Transform2D Transform2D::orthonormalized() const { return on; } +bool Transform2D::is_equal_approx(const Transform2D &p_transform) const { + + return elements[0].is_equal_approx(p_transform.elements[0]) && elements[1].is_equal_approx(p_transform.elements[1]) && elements[2].is_equal_approx(p_transform.elements[2]); +} + bool Transform2D::operator==(const Transform2D &p_transform) const { for (int i = 0; i < 3; i++) { diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index e8b44ab197..0ec39a1765 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -96,6 +96,7 @@ struct Transform2D { void orthonormalize(); Transform2D orthonormalized() const; + bool is_equal_approx(const Transform2D &p_transform) const; bool operator==(const Transform2D &p_transform) const; bool operator!=(const Transform2D &p_transform) const; diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index 972bccc0ac..fbedeb8eb2 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -203,6 +203,10 @@ Vector2 Vector2::reflect(const Vector2 &p_normal) const { return 2.0 * p_normal * this->dot(p_normal) - *this; } +bool Vector2::is_equal_approx(const Vector2 &p_v) const { + return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y); +} + /* Vector2i */ Vector2i Vector2i::operator+(const Vector2i &p_v) const { diff --git a/core/math/vector2.h b/core/math/vector2.h index 1a73831891..7fcaadab00 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -92,6 +92,8 @@ struct Vector2 { Vector2 bounce(const Vector2 &p_normal) const; Vector2 reflect(const Vector2 &p_normal) const; + bool is_equal_approx(const Vector2 &p_v) const; + Vector2 operator+(const Vector2 &p_v) const; void operator+=(const Vector2 &p_v); Vector2 operator-(const Vector2 &p_v) const; @@ -221,11 +223,11 @@ _FORCE_INLINE_ Vector2 Vector2::operator-() const { _FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const { - return Math::is_equal_approx(x, p_vec2.x) && Math::is_equal_approx(y, p_vec2.y); + return x == p_vec2.x && y == p_vec2.y; } _FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { - return !Math::is_equal_approx(x, p_vec2.x) || !Math::is_equal_approx(y, p_vec2.y); + return x != p_vec2.x || y != p_vec2.y; } Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const { diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index ebc1599820..e3211c8fb1 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -149,6 +149,11 @@ Basis Vector3::to_diagonal_matrix() const { 0, 0, z); } +bool Vector3::is_equal_approx(const Vector3 &p_v) const { + + return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z); +} + Vector3::operator String() const { return (rtos(x) + ", " + rtos(y) + ", " + rtos(z)); diff --git a/core/math/vector3.h b/core/math/vector3.h index de1743d88f..43fa09ffac 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -119,6 +119,8 @@ struct Vector3 { _FORCE_INLINE_ Vector3 bounce(const Vector3 &p_normal) const; _FORCE_INLINE_ Vector3 reflect(const Vector3 &p_normal) const; + bool is_equal_approx(const Vector3 &p_v) const; + /* Operators */ _FORCE_INLINE_ Vector3 &operator+=(const Vector3 &p_v); @@ -330,11 +332,12 @@ Vector3 Vector3::operator-() const { bool Vector3::operator==(const Vector3 &p_v) const { - return (Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z)); + return x == p_v.x && y == p_v.y && z == p_v.z; } bool Vector3::operator!=(const Vector3 &p_v) const { - return (!Math::is_equal_approx(x, p_v.x) || !Math::is_equal_approx(y, p_v.y) || !Math::is_equal_approx(z, p_v.z)); + + return x != p_v.x || y != p_v.y || z != p_v.z; } bool Vector3::operator<(const Vector3 &p_v) const { diff --git a/core/object.cpp b/core/object.cpp index 6facf38733..ed3ae4f25d 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -436,7 +436,7 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid } else if (p_name == CoreStringNames::get_singleton()->_meta) { //set_meta(p_name,p_value); - metadata = p_value; + metadata = p_value.duplicate(); if (r_valid) *r_valid = true; return; diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index 30fca0c155..f09a904953 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -49,11 +49,11 @@ bool InputEvent::is_action(const StringName &p_action) const { return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action); } -bool InputEvent::is_action_pressed(const StringName &p_action) const { +bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo) const { bool pressed; bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed); - return valid && pressed && !is_echo(); + return valid && pressed && (p_allow_echo || !is_echo()); } bool InputEvent::is_action_released(const StringName &p_action) const { @@ -112,7 +112,7 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device); ClassDB::bind_method(D_METHOD("is_action", "action"), &InputEvent::is_action); - ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &InputEvent::is_action_pressed); + ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "allow_echo"), &InputEvent::is_action_pressed, DEFVAL(false)); ClassDB::bind_method(D_METHOD("is_action_released", "action"), &InputEvent::is_action_released); ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &InputEvent::get_action_strength); @@ -557,10 +557,31 @@ InputEventMouseButton::InputEventMouseButton() { //////////////////////////////////////////// +void InputEventMouseMotion::set_tilt(const Vector2 &p_tilt) { + + tilt = p_tilt; +} + +Vector2 InputEventMouseMotion::get_tilt() const { + + return tilt; +} + +void InputEventMouseMotion::set_pressure(float p_pressure) { + + pressure = p_pressure; +} + +float InputEventMouseMotion::get_pressure() const { + + return pressure; +} + void InputEventMouseMotion::set_relative(const Vector2 &p_relative) { relative = p_relative; } + Vector2 InputEventMouseMotion::get_relative() const { return relative; @@ -570,6 +591,7 @@ void InputEventMouseMotion::set_speed(const Vector2 &p_speed) { speed = p_speed; } + Vector2 InputEventMouseMotion::get_speed() const { return speed; @@ -590,6 +612,8 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co mm->set_modifiers_from_event(this); mm->set_position(l); + mm->set_pressure(get_pressure()); + mm->set_tilt(get_tilt()); mm->set_global_position(g); mm->set_button_mask(get_button_mask()); @@ -665,17 +689,27 @@ bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) { void InputEventMouseMotion::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_tilt", "tilt"), &InputEventMouseMotion::set_tilt); + ClassDB::bind_method(D_METHOD("get_tilt"), &InputEventMouseMotion::get_tilt); + + ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventMouseMotion::set_pressure); + ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventMouseMotion::get_pressure); + ClassDB::bind_method(D_METHOD("set_relative", "relative"), &InputEventMouseMotion::set_relative); ClassDB::bind_method(D_METHOD("get_relative"), &InputEventMouseMotion::get_relative); ClassDB::bind_method(D_METHOD("set_speed", "speed"), &InputEventMouseMotion::set_speed); ClassDB::bind_method(D_METHOD("get_speed"), &InputEventMouseMotion::get_speed); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "tilt"), "set_tilt", "get_tilt"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "pressure"), "set_pressure", "get_pressure"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "relative"), "set_relative", "get_relative"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "speed"), "set_speed", "get_speed"); } InputEventMouseMotion::InputEventMouseMotion() { + + pressure = 0; } //////////////////////////////////////// diff --git a/core/os/input_event.h b/core/os/input_event.h index 28658e3865..a4db618bfe 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -184,7 +184,7 @@ public: int get_device() const; bool is_action(const StringName &p_action) const; - bool is_action_pressed(const StringName &p_action) const; + bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false) const; bool is_action_released(const StringName &p_action) const; float get_action_strength(const StringName &p_action) const; @@ -351,6 +351,9 @@ public: class InputEventMouseMotion : public InputEventMouse { GDCLASS(InputEventMouseMotion, InputEventMouse); + + Vector2 tilt; + float pressure; Vector2 relative; Vector2 speed; @@ -358,6 +361,12 @@ protected: static void _bind_methods(); public: + void set_tilt(const Vector2 &p_tilt); + Vector2 get_tilt() const; + + void set_pressure(float p_pressure); + float get_pressure() const; + void set_relative(const Vector2 &p_relative); Vector2 get_relative() const; diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index 5587e827ba..146a301995 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -65,6 +65,8 @@ void MainLoop::_bind_methods() { BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE); BIND_CONSTANT(NOTIFICATION_APP_RESUMED); BIND_CONSTANT(NOTIFICATION_APP_PAUSED); + + ADD_SIGNAL(MethodInfo("on_request_permissions_result", PropertyInfo(Variant::STRING, "permission"), PropertyInfo(Variant::BOOL, "granted"))); }; void MainLoop::set_init_script(const Ref<Script> &p_init_script) { diff --git a/core/os/memory.cpp b/core/os/memory.cpp index d1de51f3db..f4ed1d6e27 100644 --- a/core/os/memory.cpp +++ b/core/os/memory.cpp @@ -50,20 +50,17 @@ void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)) { #ifdef _MSC_VER void operator delete(void *p_mem, const char *p_description) { - ERR_EXPLAINC("Call to placement delete should not happen."); - CRASH_NOW(); + CRASH_NOW_MSG("Call to placement delete should not happen."); } void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size)) { - ERR_EXPLAINC("Call to placement delete should not happen."); - CRASH_NOW(); + CRASH_NOW_MSG("Call to placement delete should not happen."); } void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description) { - ERR_EXPLAINC("Call to placement delete should not happen."); - CRASH_NOW(); + CRASH_NOW_MSG("Call to placement delete should not happen."); } #endif diff --git a/core/os/os.cpp b/core/os/os.cpp index b44487b908..25889de1b3 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -196,29 +196,6 @@ bool OS::is_stdout_verbose() const { return _verbose_stdout; } -void OS::set_last_error(const char *p_error) { - - GLOBAL_LOCK_FUNCTION - if (p_error == NULL) - p_error = "Unknown Error"; - - if (last_error) - memfree(last_error); - last_error = NULL; - int len = 0; - while (p_error[len++]) - ; - - last_error = (char *)memalloc(len); - for (int i = 0; i < len; i++) - last_error[i] = p_error[i]; -} - -const char *OS::get_last_error() const { - GLOBAL_LOCK_FUNCTION - return last_error ? last_error : ""; -} - void OS::dump_memory_to_file(const char *p_file) { //Memory::dump_static_mem_to_file(p_file); @@ -297,14 +274,6 @@ void OS::dump_resources_to_file(const char *p_file) { ResourceCache::dump(p_file); } -void OS::clear_last_error() { - - GLOBAL_LOCK_FUNCTION - if (last_error) - memfree(last_error); - last_error = NULL; -} - void OS::set_no_window_mode(bool p_enable) { _no_window = p_enable; @@ -764,7 +733,6 @@ OS::OS() { void *volatile stack_bottom; restart_on_exit = false; - last_error = NULL; singleton = this; _keep_screen_on = true; // set default value to true, because this had been true before godot 2.0. low_processor_usage_mode = false; @@ -790,8 +758,6 @@ OS::OS() { } OS::~OS() { - if (last_error) - memfree(last_error); memdelete(_logger); singleton = NULL; } diff --git a/core/os/os.h b/core/os/os.h index 9b46b43081..687ccaaba5 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -61,8 +61,6 @@ class OS { bool _allow_layered; bool _use_vsync; - char *last_error; - void *_stack_bottom; CompositeLogger *_logger; @@ -155,10 +153,6 @@ public: virtual void alert(const String &p_alert, const String &p_title = "ALERT!") = 0; virtual String get_stdin_string(bool p_block = true) = 0; - virtual void set_last_error(const char *p_error); - virtual const char *get_last_error() const; - virtual void clear_last_error(); - enum MouseMode { MOUSE_MODE_VISIBLE, MOUSE_MODE_HIDDEN, @@ -530,6 +524,8 @@ public: List<String> get_restart_on_exit_arguments() const; virtual bool request_permission(const String &p_name) { return true; } + virtual bool request_permissions() { return true; } + virtual Vector<String> get_granted_permissions() const { return Vector<String>(); } virtual void process_and_drop_events() {} OS(); diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp index 003e7e7428..7afaf7f0f1 100644 --- a/core/packed_data_container.cpp +++ b/core/packed_data_container.cpp @@ -137,6 +137,7 @@ uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const { int PackedDataContainer::_size(uint32_t p_ofs) const { PoolVector<uint8_t>::Read rd = data.read(); + ERR_FAIL_COND_V(!rd.ptr(), 0); const uint8_t *r = &rd[p_ofs]; uint32_t type = decode_uint32(r); diff --git a/core/pool_vector.h b/core/pool_vector.h index fbd4d630be..a698e72e18 100644 --- a/core/pool_vector.h +++ b/core/pool_vector.h @@ -385,6 +385,7 @@ public: } inline int size() const; + inline bool empty() const; T get(int p_index) const; void set(int p_index, const T &p_val); void push_back(const T &p_val); @@ -475,6 +476,12 @@ int PoolVector<T>::size() const { } template <class T> +bool PoolVector<T>::empty() const { + + return alloc ? alloc->size == 0 : true; +} + +template <class T> T PoolVector<T>::get(int p_index) const { return operator[](p_index); diff --git a/core/project_settings.cpp b/core/project_settings.cpp index c2241ed926..067578e354 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -525,6 +525,8 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) { set(key, value); } + f->close(); + memdelete(f); return OK; } diff --git a/core/ref_ptr.cpp b/core/ref_ptr.cpp index 961f143e5c..6da73ca41a 100644 --- a/core/ref_ptr.cpp +++ b/core/ref_ptr.cpp @@ -49,6 +49,14 @@ bool RefPtr::operator==(const RefPtr &p_other) const { return *ref == *ref_other; } +bool RefPtr::operator!=(const RefPtr &p_other) const { + + Ref<Reference> *ref = reinterpret_cast<Ref<Reference> *>(&data[0]); + Ref<Reference> *ref_other = reinterpret_cast<Ref<Reference> *>(const_cast<char *>(&p_other.data[0])); + + return *ref != *ref_other; +} + RefPtr::RefPtr(const RefPtr &p_other) { memnew_placement(&data[0], Ref<Reference>); diff --git a/core/ref_ptr.h b/core/ref_ptr.h index f745ababa1..320cf35609 100644 --- a/core/ref_ptr.h +++ b/core/ref_ptr.h @@ -50,6 +50,7 @@ public: bool is_null() const; void operator=(const RefPtr &p_other); bool operator==(const RefPtr &p_other) const; + bool operator!=(const RefPtr &p_other) const; RID get_rid() const; void unref(); _FORCE_INLINE_ void *get_data() const { return data; } diff --git a/core/resource.cpp b/core/resource.cpp index 87c92ca5b1..e0a40b6f3c 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -365,17 +365,38 @@ bool Resource::is_translation_remapped() const { //helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored void Resource::set_id_for_path(const String &p_path, int p_id) { if (p_id == -1) { - id_for_path.erase(p_path); + if (ResourceCache::path_cache_lock) { + ResourceCache::path_cache_lock->write_lock(); + } + ResourceCache::resource_path_cache[p_path].erase(get_path()); + if (ResourceCache::path_cache_lock) { + ResourceCache::path_cache_lock->write_unlock(); + } } else { - id_for_path[p_path] = p_id; + if (ResourceCache::path_cache_lock) { + ResourceCache::path_cache_lock->write_lock(); + } + ResourceCache::resource_path_cache[p_path][get_path()] = p_id; + if (ResourceCache::path_cache_lock) { + ResourceCache::path_cache_lock->write_unlock(); + } } } int Resource::get_id_for_path(const String &p_path) const { - - if (id_for_path.has(p_path)) { - return id_for_path[p_path]; + if (ResourceCache::path_cache_lock) { + ResourceCache::path_cache_lock->read_lock(); + } + if (ResourceCache::resource_path_cache[p_path].has(get_path())) { + int result = ResourceCache::resource_path_cache[p_path][get_path()]; + if (ResourceCache::path_cache_lock) { + ResourceCache::path_cache_lock->read_unlock(); + } + return result; } else { + if (ResourceCache::path_cache_lock) { + ResourceCache::path_cache_lock->read_unlock(); + } return -1; } } @@ -430,12 +451,21 @@ Resource::~Resource() { } HashMap<String, Resource *> ResourceCache::resources; +#ifdef TOOLS_ENABLED +HashMap<String, HashMap<String, int> > ResourceCache::resource_path_cache; +#endif RWLock *ResourceCache::lock = NULL; +#ifdef TOOLS_ENABLED +RWLock *ResourceCache::path_cache_lock = NULL; +#endif void ResourceCache::setup() { lock = RWLock::create(); +#ifdef TOOLS_ENABLED + path_cache_lock = RWLock::create(); +#endif } void ResourceCache::clear() { diff --git a/core/resource.h b/core/resource.h index 038b4f6278..3e1fe07137 100644 --- a/core/resource.h +++ b/core/resource.h @@ -84,9 +84,7 @@ protected: void _set_path(const String &p_path); void _take_over_path(const String &p_path); -#ifdef TOOLS_ENABLED - Map<String, int> id_for_path; -#endif + public: static Node *(*_get_local_scene_func)(); //used by editor @@ -152,6 +150,10 @@ class ResourceCache { friend class ResourceLoader; //need the lock static RWLock *lock; static HashMap<String, Resource *> resources; +#ifdef TOOLS_ENABLED + static HashMap<String, HashMap<String, int> > resource_path_cache; // each tscn has a set of resource paths and IDs + static RWLock *path_cache_lock; +#endif // TOOLS_ENABLED friend void unregister_core_types(); static void clear(); friend void register_core_types(); diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp deleted file mode 100644 index 65ef2a0978..0000000000 --- a/core/script_debugger_remote.cpp +++ /dev/null @@ -1,1222 +0,0 @@ -/*************************************************************************/ -/* script_debugger_remote.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 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 "script_debugger_remote.h" - -#include "core/engine.h" -#include "core/io/ip.h" -#include "core/io/marshalls.h" -#include "core/os/input.h" -#include "core/os/os.h" -#include "core/project_settings.h" -#include "scene/main/node.h" -#include "scene/resources/packed_scene.h" - -void ScriptDebuggerRemote::_send_video_memory() { - - List<ResourceUsage> usage; - if (resource_usage_func) - resource_usage_func(&usage); - - usage.sort(); - - packet_peer_stream->put_var("message:video_mem"); - packet_peer_stream->put_var(usage.size() * 4); - - for (List<ResourceUsage>::Element *E = usage.front(); E; E = E->next()) { - - packet_peer_stream->put_var(E->get().path); - packet_peer_stream->put_var(E->get().type); - packet_peer_stream->put_var(E->get().format); - packet_peer_stream->put_var(E->get().vram); - } -} - -Error ScriptDebuggerRemote::connect_to_host(const String &p_host, uint16_t p_port) { - - IP_Address ip; - if (p_host.is_valid_ip_address()) - ip = p_host; - else - ip = IP::get_singleton()->resolve_hostname(p_host); - - int port = p_port; - - const int tries = 6; - int waits[tries] = { 1, 10, 100, 1000, 1000, 1000 }; - - tcp_client->connect_to_host(ip, port); - - for (int i = 0; i < tries; i++) { - - if (tcp_client->get_status() == StreamPeerTCP::STATUS_CONNECTED) { - print_verbose("Remote Debugger: Connected!"); - break; - } else { - - const int ms = waits[i]; - OS::get_singleton()->delay_usec(ms * 1000); - print_verbose("Remote Debugger: Connection failed with status: '" + String::num(tcp_client->get_status()) + "', retrying in " + String::num(ms) + " msec."); - }; - }; - - if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) { - - ERR_PRINTS("Remote Debugger: Unable to connect. Status: " + String::num(tcp_client->get_status()) + "."); - return FAILED; - }; - - packet_peer_stream->set_stream_peer(tcp_client); - - return OK; -} - -void ScriptDebuggerRemote::_put_variable(const String &p_name, const Variant &p_variable) { - - packet_peer_stream->put_var(p_name); - - Variant var = p_variable; - if (p_variable.get_type() == Variant::OBJECT && !ObjectDB::instance_validate(p_variable)) { - var = Variant(); - } - - int len = 0; - Error err = encode_variant(var, NULL, len, true); - if (err != OK) - ERR_PRINT("Failed to encode variant."); - - if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size - packet_peer_stream->put_var(Variant()); - } else { - packet_peer_stream->put_var(var); - } -} - -void ScriptDebuggerRemote::_save_node(ObjectID id, const String &p_path) { - - Node *node = Object::cast_to<Node>(ObjectDB::get_instance(id)); - ERR_FAIL_COND(!node); - - Ref<PackedScene> ps = memnew(PackedScene); - ps->pack(node); - ResourceSaver::save(p_path, ps); -} - -void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue, bool p_is_error_breakpoint) { - - //this function is called when there is a debugger break (bug on script) - //or when execution is paused from editor - - if (skip_breakpoints && !p_is_error_breakpoint) - return; - - ERR_FAIL_COND_MSG(!tcp_client->is_connected_to_host(), "Script Debugger failed to connect, but being used anyway."); - - packet_peer_stream->put_var("debug_enter"); - packet_peer_stream->put_var(2); - packet_peer_stream->put_var(p_can_continue); - packet_peer_stream->put_var(p_script->debug_get_error()); - - skip_profile_frame = true; // to avoid super long frame time for the frame - - Input::MouseMode mouse_mode = Input::get_singleton()->get_mouse_mode(); - if (mouse_mode != Input::MOUSE_MODE_VISIBLE) - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); - - while (true) { - - _get_output(); - - if (packet_peer_stream->get_available_packet_count() > 0) { - - Variant var; - Error err = packet_peer_stream->get_var(var); - - ERR_CONTINUE(err != OK); - ERR_CONTINUE(var.get_type() != Variant::ARRAY); - - Array cmd = var; - - ERR_CONTINUE(cmd.size() == 0); - ERR_CONTINUE(cmd[0].get_type() != Variant::STRING); - - String command = cmd[0]; - - if (command == "get_stack_dump") { - - packet_peer_stream->put_var("stack_dump"); - int slc = p_script->debug_get_stack_level_count(); - packet_peer_stream->put_var(slc); - - for (int i = 0; i < slc; i++) { - - Dictionary d; - d["file"] = p_script->debug_get_stack_level_source(i); - d["line"] = p_script->debug_get_stack_level_line(i); - d["function"] = p_script->debug_get_stack_level_function(i); - //d["id"]=p_script->debug_get_stack_level_ - d["id"] = 0; - - packet_peer_stream->put_var(d); - } - - } else if (command == "get_stack_frame_vars") { - - cmd.remove(0); - ERR_CONTINUE(cmd.size() != 1); - int lv = cmd[0]; - - List<String> members; - List<Variant> member_vals; - if (ScriptInstance *inst = p_script->debug_get_stack_level_instance(lv)) { - members.push_back("self"); - member_vals.push_back(inst->get_owner()); - } - p_script->debug_get_stack_level_members(lv, &members, &member_vals); - ERR_CONTINUE(members.size() != member_vals.size()); - - List<String> locals; - List<Variant> local_vals; - p_script->debug_get_stack_level_locals(lv, &locals, &local_vals); - ERR_CONTINUE(locals.size() != local_vals.size()); - - List<String> globals; - List<Variant> globals_vals; - p_script->debug_get_globals(&globals, &globals_vals); - ERR_CONTINUE(globals.size() != globals_vals.size()); - - packet_peer_stream->put_var("stack_frame_vars"); - packet_peer_stream->put_var(3 + (locals.size() + members.size() + globals.size()) * 2); - - { //locals - packet_peer_stream->put_var(locals.size()); - - List<String>::Element *E = locals.front(); - List<Variant>::Element *F = local_vals.front(); - - while (E) { - _put_variable(E->get(), F->get()); - - E = E->next(); - F = F->next(); - } - } - - { //members - packet_peer_stream->put_var(members.size()); - - List<String>::Element *E = members.front(); - List<Variant>::Element *F = member_vals.front(); - - while (E) { - - _put_variable(E->get(), F->get()); - - E = E->next(); - F = F->next(); - } - } - - { //globals - packet_peer_stream->put_var(globals.size()); - - List<String>::Element *E = globals.front(); - List<Variant>::Element *F = globals_vals.front(); - - while (E) { - _put_variable(E->get(), F->get()); - - E = E->next(); - F = F->next(); - } - } - - } else if (command == "step") { - - set_depth(-1); - set_lines_left(1); - break; - } else if (command == "next") { - - set_depth(0); - set_lines_left(1); - break; - - } else if (command == "continue") { - set_depth(-1); - set_lines_left(-1); - OS::get_singleton()->move_window_to_foreground(); - break; - } else if (command == "break") { - ERR_PRINT("Got break when already broke!"); - break; - } else if (command == "request_scene_tree") { - - if (request_scene_tree) - request_scene_tree(request_scene_tree_ud); - - } else if (command == "request_video_mem") { - - _send_video_memory(); - } else if (command == "inspect_object") { - - ObjectID id = cmd[1]; - _send_object_id(id); - } else if (command == "set_object_property") { - - _set_object_property(cmd[1], cmd[2], cmd[3]); - - } else if (command == "reload_scripts") { - reload_all_scripts = true; - } else if (command == "breakpoint") { - - bool set = cmd[3]; - if (set) - insert_breakpoint(cmd[2], cmd[1]); - else - remove_breakpoint(cmd[2], cmd[1]); - - } else if (command == "save_node") { - _save_node(cmd[1], cmd[2]); - } else if (command == "set_skip_breakpoints") { - skip_breakpoints = cmd[1]; - } else { - _parse_live_edit(cmd); - } - - } else { - OS::get_singleton()->delay_usec(10000); - OS::get_singleton()->process_and_drop_events(); - } - } - - packet_peer_stream->put_var("debug_exit"); - packet_peer_stream->put_var(0); - - if (mouse_mode != Input::MOUSE_MODE_VISIBLE) - Input::get_singleton()->set_mouse_mode(mouse_mode); -} - -void ScriptDebuggerRemote::_get_output() { - - mutex->lock(); - if (output_strings.size()) { - - locking = true; - packet_peer_stream->put_var("output"); - packet_peer_stream->put_var(output_strings.size()); - - while (output_strings.size()) { - - packet_peer_stream->put_var(output_strings.front()->get()); - output_strings.pop_front(); - } - locking = false; - } - - if (n_messages_dropped > 0) { - Message msg; - msg.message = "Too many messages! " + String::num_int64(n_messages_dropped) + " messages were dropped."; - messages.push_back(msg); - n_messages_dropped = 0; - } - - while (messages.size()) { - locking = true; - packet_peer_stream->put_var("message:" + messages.front()->get().message); - packet_peer_stream->put_var(messages.front()->get().data.size()); - for (int i = 0; i < messages.front()->get().data.size(); i++) { - packet_peer_stream->put_var(messages.front()->get().data[i]); - } - messages.pop_front(); - locking = false; - } - - if (n_errors_dropped == 1) { - // Only print one message about dropping per second - OutputError oe; - oe.error = "TOO_MANY_ERRORS"; - oe.error_descr = "Too many errors! Ignoring errors for up to 1 second."; - oe.warning = false; - uint64_t time = OS::get_singleton()->get_ticks_msec(); - oe.hr = time / 3600000; - oe.min = (time / 60000) % 60; - oe.sec = (time / 1000) % 60; - oe.msec = time % 1000; - errors.push_back(oe); - } - - if (n_warnings_dropped == 1) { - // Only print one message about dropping per second - OutputError oe; - oe.error = "TOO_MANY_WARNINGS"; - oe.error_descr = "Too many warnings! Ignoring warnings for up to 1 second."; - oe.warning = true; - uint64_t time = OS::get_singleton()->get_ticks_msec(); - oe.hr = time / 3600000; - oe.min = (time / 60000) % 60; - oe.sec = (time / 1000) % 60; - oe.msec = time % 1000; - errors.push_back(oe); - } - - while (errors.size()) { - locking = true; - packet_peer_stream->put_var("error"); - OutputError oe = errors.front()->get(); - - packet_peer_stream->put_var(oe.callstack.size() + 2); - - Array error_data; - - error_data.push_back(oe.hr); - error_data.push_back(oe.min); - error_data.push_back(oe.sec); - error_data.push_back(oe.msec); - error_data.push_back(oe.source_func); - error_data.push_back(oe.source_file); - error_data.push_back(oe.source_line); - error_data.push_back(oe.error); - error_data.push_back(oe.error_descr); - error_data.push_back(oe.warning); - packet_peer_stream->put_var(error_data); - packet_peer_stream->put_var(oe.callstack.size()); - for (int i = 0; i < oe.callstack.size(); i++) { - packet_peer_stream->put_var(oe.callstack[i]); - } - - errors.pop_front(); - locking = false; - } - mutex->unlock(); -} - -void ScriptDebuggerRemote::line_poll() { - - //the purpose of this is just processing events every now and then when the script might get too busy - //otherwise bugs like infinite loops can't be caught - if (poll_every % 2048 == 0) - _poll_events(); - poll_every++; -} - -void ScriptDebuggerRemote::_err_handler(void *ud, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, ErrorHandlerType p_type) { - - if (p_type == ERR_HANDLER_SCRIPT) - return; //ignore script errors, those go through debugger - - Vector<ScriptLanguage::StackInfo> si; - - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - si = ScriptServer::get_language(i)->debug_get_current_stack_info(); - if (si.size()) - break; - } - - ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote *)ud; - sdr->send_error(p_func, p_file, p_line, p_err, p_descr, p_type, si); -} - -bool ScriptDebuggerRemote::_parse_live_edit(const Array &p_command) { - - String cmdstr = p_command[0]; - if (!live_edit_funcs || !cmdstr.begins_with("live_")) - return false; - - //print_line(Variant(cmd).get_construct_string()); - if (cmdstr == "live_set_root") { - - if (!live_edit_funcs->root_func) - return true; - //print_line("root: "+Variant(cmd).get_construct_string()); - live_edit_funcs->root_func(live_edit_funcs->udata, p_command[1], p_command[2]); - - } else if (cmdstr == "live_node_path") { - - if (!live_edit_funcs->node_path_func) - return true; - //print_line("path: "+Variant(cmd).get_construct_string()); - - live_edit_funcs->node_path_func(live_edit_funcs->udata, p_command[1], p_command[2]); - - } else if (cmdstr == "live_res_path") { - - if (!live_edit_funcs->res_path_func) - return true; - live_edit_funcs->res_path_func(live_edit_funcs->udata, p_command[1], p_command[2]); - - } else if (cmdstr == "live_node_prop_res") { - if (!live_edit_funcs->node_set_res_func) - return true; - - live_edit_funcs->node_set_res_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); - - } else if (cmdstr == "live_node_prop") { - - if (!live_edit_funcs->node_set_func) - return true; - live_edit_funcs->node_set_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); - - } else if (cmdstr == "live_res_prop_res") { - - if (!live_edit_funcs->res_set_res_func) - return true; - live_edit_funcs->res_set_res_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); - - } else if (cmdstr == "live_res_prop") { - - if (!live_edit_funcs->res_set_func) - return true; - live_edit_funcs->res_set_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); - - } else if (cmdstr == "live_node_call") { - - if (!live_edit_funcs->node_call_func) - return true; - live_edit_funcs->node_call_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3], p_command[4], p_command[5], p_command[6], p_command[7]); - - } else if (cmdstr == "live_res_call") { - - if (!live_edit_funcs->res_call_func) - return true; - live_edit_funcs->res_call_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3], p_command[4], p_command[5], p_command[6], p_command[7]); - - } else if (cmdstr == "live_create_node") { - - live_edit_funcs->tree_create_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); - - } else if (cmdstr == "live_instance_node") { - - live_edit_funcs->tree_instance_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); - - } else if (cmdstr == "live_remove_node") { - - live_edit_funcs->tree_remove_node_func(live_edit_funcs->udata, p_command[1]); - - } else if (cmdstr == "live_remove_and_keep_node") { - - live_edit_funcs->tree_remove_and_keep_node_func(live_edit_funcs->udata, p_command[1], p_command[2]); - } else if (cmdstr == "live_restore_node") { - - live_edit_funcs->tree_restore_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]); - - } else if (cmdstr == "live_duplicate_node") { - - live_edit_funcs->tree_duplicate_node_func(live_edit_funcs->udata, p_command[1], p_command[2]); - } else if (cmdstr == "live_reparent_node") { - - live_edit_funcs->tree_reparent_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3], p_command[4]); - - } else { - - return false; - } - - return true; -} - -void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { - - Object *obj = ObjectDB::get_instance(p_id); - if (!obj) - return; - - typedef Pair<PropertyInfo, Variant> PropertyDesc; - List<PropertyDesc> properties; - - if (ScriptInstance *si = obj->get_script_instance()) { - if (!si->get_script().is_null()) { - - typedef Map<const Script *, Set<StringName> > ScriptMemberMap; - typedef Map<const Script *, Map<StringName, Variant> > ScriptConstantsMap; - - ScriptMemberMap members; - members[si->get_script().ptr()] = Set<StringName>(); - si->get_script()->get_members(&(members[si->get_script().ptr()])); - - ScriptConstantsMap constants; - constants[si->get_script().ptr()] = Map<StringName, Variant>(); - si->get_script()->get_constants(&(constants[si->get_script().ptr()])); - - Ref<Script> base = si->get_script()->get_base_script(); - while (base.is_valid()) { - - members[base.ptr()] = Set<StringName>(); - base->get_members(&(members[base.ptr()])); - - constants[base.ptr()] = Map<StringName, Variant>(); - base->get_constants(&(constants[base.ptr()])); - - base = base->get_base_script(); - } - - for (ScriptMemberMap::Element *sm = members.front(); sm; sm = sm->next()) { - for (Set<StringName>::Element *E = sm->get().front(); E; E = E->next()) { - Variant m; - if (si->get(E->get(), m)) { - String script_path = sm->key() == si->get_script().ptr() ? "" : sm->key()->get_path().get_file() + "/"; - PropertyInfo pi(m.get_type(), "Members/" + script_path + E->get()); - properties.push_back(PropertyDesc(pi, m)); - } - } - } - - for (ScriptConstantsMap::Element *sc = constants.front(); sc; sc = sc->next()) { - for (Map<StringName, Variant>::Element *E = sc->get().front(); E; E = E->next()) { - String script_path = sc->key() == si->get_script().ptr() ? "" : sc->key()->get_path().get_file() + "/"; - if (E->value().get_type() == Variant::OBJECT) { - Variant id = ((Object *)E->value())->get_instance_id(); - PropertyInfo pi(id.get_type(), "Constants/" + E->key(), PROPERTY_HINT_OBJECT_ID, "Object"); - properties.push_back(PropertyDesc(pi, id)); - } else { - PropertyInfo pi(E->value().get_type(), "Constants/" + script_path + E->key()); - properties.push_back(PropertyDesc(pi, E->value())); - } - } - } - } - } - - if (Node *node = Object::cast_to<Node>(obj)) { - // in some cases node will not be in tree here - // for instance where it created as variable and not yet added to tree - // in such cases we can't ask for it's path - if (node->is_inside_tree()) { - PropertyInfo pi(Variant::NODE_PATH, String("Node/path")); - properties.push_front(PropertyDesc(pi, node->get_path())); - } else { - PropertyInfo pi(Variant::STRING, String("Node/path")); - properties.push_front(PropertyDesc(pi, "[Orphan]")); - } - - } else if (Resource *res = Object::cast_to<Resource>(obj)) { - if (Script *s = Object::cast_to<Script>(res)) { - Map<StringName, Variant> constants; - s->get_constants(&constants); - for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { - if (E->value().get_type() == Variant::OBJECT) { - Variant id = ((Object *)E->value())->get_instance_id(); - PropertyInfo pi(id.get_type(), "Constants/" + E->key(), PROPERTY_HINT_OBJECT_ID, "Object"); - properties.push_front(PropertyDesc(pi, E->value())); - } else { - PropertyInfo pi(E->value().get_type(), String("Constants/") + E->key()); - properties.push_front(PropertyDesc(pi, E->value())); - } - } - } - } - - List<PropertyInfo> pinfo; - obj->get_property_list(&pinfo, true); - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) { - properties.push_back(PropertyDesc(E->get(), obj->get(E->get().name))); - } - } - - Array send_props; - for (int i = 0; i < properties.size(); i++) { - const PropertyInfo &pi = properties[i].first; - Variant &var = properties[i].second; - - WeakRef *ref = Object::cast_to<WeakRef>(var); - if (ref) { - var = ref->get_ref(); - } - - RES res = var; - - Array prop; - prop.push_back(pi.name); - prop.push_back(pi.type); - - //only send information that can be sent.. - int len = 0; //test how big is this to encode - encode_variant(var, NULL, len); - if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size - prop.push_back(PROPERTY_HINT_OBJECT_TOO_BIG); - prop.push_back(""); - prop.push_back(pi.usage); - prop.push_back(Variant()); - } else { - prop.push_back(pi.hint); - prop.push_back(pi.hint_string); - prop.push_back(pi.usage); - - if (!res.is_null()) { - var = res->get_path(); - } - - prop.push_back(var); - } - send_props.push_back(prop); - } - - packet_peer_stream->put_var("message:inspect_object"); - packet_peer_stream->put_var(3); - packet_peer_stream->put_var(p_id); - packet_peer_stream->put_var(obj->get_class()); - packet_peer_stream->put_var(send_props); -} - -void ScriptDebuggerRemote::_set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value) { - - Object *obj = ObjectDB::get_instance(p_id); - if (!obj) - return; - - String prop_name = p_property; - if (p_property.begins_with("Members/")) { - Vector<String> ss = p_property.split("/"); - prop_name = ss[ss.size() - 1]; - } - - obj->set(prop_name, p_value); -} - -void ScriptDebuggerRemote::_poll_events() { - - //this si called from ::idle_poll, happens only when running the game, - //does not get called while on debug break - - while (packet_peer_stream->get_available_packet_count() > 0) { - - _get_output(); - - //send over output_strings - - Variant var; - Error err = packet_peer_stream->get_var(var); - - ERR_CONTINUE(err != OK); - ERR_CONTINUE(var.get_type() != Variant::ARRAY); - - Array cmd = var; - - ERR_CONTINUE(cmd.size() == 0); - ERR_CONTINUE(cmd[0].get_type() != Variant::STRING); - - String command = cmd[0]; - //cmd.remove(0); - - if (command == "break") { - - if (get_break_language()) - debug(get_break_language()); - } else if (command == "request_scene_tree") { - - if (request_scene_tree) - request_scene_tree(request_scene_tree_ud); - } else if (command == "request_video_mem") { - - _send_video_memory(); - } else if (command == "inspect_object") { - - ObjectID id = cmd[1]; - _send_object_id(id); - } else if (command == "set_object_property") { - - _set_object_property(cmd[1], cmd[2], cmd[3]); - - } else if (command == "start_profiling") { - - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->profiling_start(); - } - - max_frame_functions = cmd[1]; - profiler_function_signature_map.clear(); - profiling = true; - frame_time = 0; - idle_time = 0; - physics_time = 0; - physics_frame_time = 0; - - print_line("PROFILING ALRIGHT!"); - - } else if (command == "stop_profiling") { - - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->profiling_stop(); - } - profiling = false; - _send_profiling_data(false); - print_line("PROFILING END!"); - } else if (command == "start_network_profiling") { - - multiplayer->profiling_start(); - profiling_network = true; - } else if (command == "stop_network_profiling") { - - multiplayer->profiling_end(); - profiling_network = false; - } else if (command == "reload_scripts") { - reload_all_scripts = true; - } else if (command == "breakpoint") { - - bool set = cmd[3]; - if (set) - insert_breakpoint(cmd[2], cmd[1]); - else - remove_breakpoint(cmd[2], cmd[1]); - } else if (command == "set_skip_breakpoints") { - skip_breakpoints = cmd[1]; - } else { - _parse_live_edit(cmd); - } - } -} - -void ScriptDebuggerRemote::_send_profiling_data(bool p_for_frame) { - - int ofs = 0; - - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - if (p_for_frame) - ofs += ScriptServer::get_language(i)->profiling_get_frame_data(&profile_info.write[ofs], profile_info.size() - ofs); - else - ofs += ScriptServer::get_language(i)->profiling_get_accumulated_data(&profile_info.write[ofs], profile_info.size() - ofs); - } - - for (int i = 0; i < ofs; i++) { - profile_info_ptrs.write[i] = &profile_info.write[i]; - } - - SortArray<ScriptLanguage::ProfilingInfo *, ProfileInfoSort> sa; - sa.sort(profile_info_ptrs.ptrw(), ofs); - - int to_send = MIN(ofs, max_frame_functions); - - //check signatures first - uint64_t total_script_time = 0; - - for (int i = 0; i < to_send; i++) { - - if (!profiler_function_signature_map.has(profile_info_ptrs[i]->signature)) { - - int idx = profiler_function_signature_map.size(); - packet_peer_stream->put_var("profile_sig"); - packet_peer_stream->put_var(2); - packet_peer_stream->put_var(profile_info_ptrs[i]->signature); - packet_peer_stream->put_var(idx); - - profiler_function_signature_map[profile_info_ptrs[i]->signature] = idx; - } - - total_script_time += profile_info_ptrs[i]->self_time; - } - - //send frames then - - if (p_for_frame) { - packet_peer_stream->put_var("profile_frame"); - packet_peer_stream->put_var(8 + profile_frame_data.size() * 2 + to_send * 4); - } else { - packet_peer_stream->put_var("profile_total"); - packet_peer_stream->put_var(8 + to_send * 4); - } - - packet_peer_stream->put_var(Engine::get_singleton()->get_frames_drawn()); //total frame time - packet_peer_stream->put_var(frame_time); //total frame time - packet_peer_stream->put_var(idle_time); //idle frame time - packet_peer_stream->put_var(physics_time); //fixed frame time - packet_peer_stream->put_var(physics_frame_time); //fixed frame time - - packet_peer_stream->put_var(USEC_TO_SEC(total_script_time)); //total script execution time - - if (p_for_frame) { - - packet_peer_stream->put_var(profile_frame_data.size()); //how many profile framedatas to send - packet_peer_stream->put_var(to_send); //how many script functions to send - for (int i = 0; i < profile_frame_data.size(); i++) { - - packet_peer_stream->put_var(profile_frame_data[i].name); - packet_peer_stream->put_var(profile_frame_data[i].data); - } - } else { - packet_peer_stream->put_var(0); //how many script functions to send - packet_peer_stream->put_var(to_send); //how many script functions to send - } - - for (int i = 0; i < to_send; i++) { - - int sig_id = -1; - - if (profiler_function_signature_map.has(profile_info_ptrs[i]->signature)) { - sig_id = profiler_function_signature_map[profile_info_ptrs[i]->signature]; - } - - packet_peer_stream->put_var(sig_id); - packet_peer_stream->put_var(profile_info_ptrs[i]->call_count); - packet_peer_stream->put_var(profile_info_ptrs[i]->total_time / 1000000.0); - packet_peer_stream->put_var(profile_info_ptrs[i]->self_time / 1000000.0); - } - - if (p_for_frame) { - profile_frame_data.clear(); - } -} - -void ScriptDebuggerRemote::idle_poll() { - - // this function is called every frame, except when there is a debugger break (::debug() in this class) - // execution stops and remains in the ::debug function - - _get_output(); - - if (requested_quit) { - - packet_peer_stream->put_var("kill_me"); - packet_peer_stream->put_var(0); - requested_quit = false; - } - - if (performance) { - - uint64_t pt = OS::get_singleton()->get_ticks_msec(); - if (pt - last_perf_time > 1000) { - - last_perf_time = pt; - int max = performance->get("MONITOR_MAX"); - Array arr; - arr.resize(max); - for (int i = 0; i < max; i++) { - arr[i] = performance->call("get_monitor", i); - } - packet_peer_stream->put_var("performance"); - packet_peer_stream->put_var(1); - packet_peer_stream->put_var(arr); - } - } - - if (profiling) { - - if (skip_profile_frame) { - skip_profile_frame = false; - } else { - //send profiling info normally - _send_profiling_data(true); - } - } - - if (profiling_network) { - uint64_t pt = OS::get_singleton()->get_ticks_msec(); - if (pt - last_net_bandwidth_time > 200) { - last_net_bandwidth_time = pt; - _send_network_bandwidth_usage(); - } - if (pt - last_net_prof_time > 100) { - last_net_prof_time = pt; - _send_network_profiling_data(); - } - } - - if (reload_all_scripts) { - - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->reload_all_scripts(); - } - reload_all_scripts = false; - } - - _poll_events(); -} - -void ScriptDebuggerRemote::_send_network_profiling_data() { - ERR_FAIL_COND(multiplayer.is_null()); - - int n_nodes = multiplayer->get_profiling_frame(&network_profile_info.write[0]); - - packet_peer_stream->put_var("network_profile"); - packet_peer_stream->put_var(n_nodes * 6); - for (int i = 0; i < n_nodes; ++i) { - packet_peer_stream->put_var(network_profile_info[i].node); - packet_peer_stream->put_var(network_profile_info[i].node_path); - packet_peer_stream->put_var(network_profile_info[i].incoming_rpc); - packet_peer_stream->put_var(network_profile_info[i].incoming_rset); - packet_peer_stream->put_var(network_profile_info[i].outgoing_rpc); - packet_peer_stream->put_var(network_profile_info[i].outgoing_rset); - } -} - -void ScriptDebuggerRemote::_send_network_bandwidth_usage() { - ERR_FAIL_COND(multiplayer.is_null()); - - int incoming_bandwidth = multiplayer->get_incoming_bandwidth_usage(); - int outgoing_bandwidth = multiplayer->get_outgoing_bandwidth_usage(); - - packet_peer_stream->put_var("network_bandwidth"); - packet_peer_stream->put_var(2); - packet_peer_stream->put_var(incoming_bandwidth); - packet_peer_stream->put_var(outgoing_bandwidth); -} - -void ScriptDebuggerRemote::send_message(const String &p_message, const Array &p_args) { - - mutex->lock(); - if (!locking && tcp_client->is_connected_to_host()) { - - if (messages.size() >= max_messages_per_frame) { - n_messages_dropped++; - } else { - Message msg; - msg.message = p_message; - msg.data = p_args; - messages.push_back(msg); - } - } - mutex->unlock(); -} - -void ScriptDebuggerRemote::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info) { - - OutputError oe; - oe.error = p_err; - oe.error_descr = p_descr; - oe.source_file = p_file; - oe.source_line = p_line; - oe.source_func = p_func; - oe.warning = p_type == ERR_HANDLER_WARNING; - uint64_t time = OS::get_singleton()->get_ticks_msec(); - oe.hr = time / 3600000; - oe.min = (time / 60000) % 60; - oe.sec = (time / 1000) % 60; - oe.msec = time % 1000; - Array cstack; - - uint64_t ticks = OS::get_singleton()->get_ticks_usec() / 1000; - msec_count += ticks - last_msec; - last_msec = ticks; - - if (msec_count > 1000) { - msec_count = 0; - - err_count = 0; - n_errors_dropped = 0; - warn_count = 0; - n_warnings_dropped = 0; - } - - cstack.resize(p_stack_info.size() * 3); - for (int i = 0; i < p_stack_info.size(); i++) { - cstack[i * 3 + 0] = p_stack_info[i].file; - cstack[i * 3 + 1] = p_stack_info[i].func; - cstack[i * 3 + 2] = p_stack_info[i].line; - } - - oe.callstack = cstack; - if (oe.warning) { - warn_count++; - } else { - err_count++; - } - - mutex->lock(); - - if (!locking && tcp_client->is_connected_to_host()) { - - if (oe.warning) { - if (warn_count > max_warnings_per_second) { - n_warnings_dropped++; - } else { - errors.push_back(oe); - } - } else { - if (err_count > max_errors_per_second) { - n_errors_dropped++; - } else { - errors.push_back(oe); - } - } - } - - mutex->unlock(); -} - -void ScriptDebuggerRemote::_print_handler(void *p_this, const String &p_string, bool p_error) { - - ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote *)p_this; - - uint64_t ticks = OS::get_singleton()->get_ticks_usec() / 1000; - sdr->msec_count += ticks - sdr->last_msec; - sdr->last_msec = ticks; - - if (sdr->msec_count > 1000) { - sdr->char_count = 0; - sdr->msec_count = 0; - } - - String s = p_string; - int allowed_chars = MIN(MAX(sdr->max_cps - sdr->char_count, 0), s.length()); - - if (allowed_chars == 0) - return; - - if (allowed_chars < s.length()) { - s = s.substr(0, allowed_chars); - } - - sdr->char_count += allowed_chars; - bool overflowed = sdr->char_count >= sdr->max_cps; - - sdr->mutex->lock(); - if (!sdr->locking && sdr->tcp_client->is_connected_to_host()) { - - if (overflowed) - s += "[...]"; - - sdr->output_strings.push_back(s); - - if (overflowed) { - sdr->output_strings.push_back("[output overflow, print less text!]"); - } - } - sdr->mutex->unlock(); -} - -void ScriptDebuggerRemote::request_quit() { - - requested_quit = true; -} - -void ScriptDebuggerRemote::set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) { - - request_scene_tree = p_func; - request_scene_tree_ud = p_udata; -} - -void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) { - - live_edit_funcs = p_funcs; -} - -void ScriptDebuggerRemote::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) { - multiplayer = p_multiplayer; -} - -bool ScriptDebuggerRemote::is_profiling() const { - - return profiling; -} -void ScriptDebuggerRemote::add_profiling_frame_data(const StringName &p_name, const Array &p_data) { - - int idx = -1; - for (int i = 0; i < profile_frame_data.size(); i++) { - if (profile_frame_data[i].name == p_name) { - idx = i; - break; - } - } - - FrameData fd; - fd.name = p_name; - fd.data = p_data; - - if (idx == -1) { - profile_frame_data.push_back(fd); - } else { - profile_frame_data.write[idx] = fd; - } -} - -void ScriptDebuggerRemote::profiling_start() { - //ignores this, uses it via connection -} - -void ScriptDebuggerRemote::profiling_end() { - //ignores this, uses it via connection -} - -void ScriptDebuggerRemote::profiling_set_frame_times(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { - - frame_time = p_frame_time; - idle_time = p_idle_time; - physics_time = p_physics_time; - physics_frame_time = p_physics_frame_time; -} - -void ScriptDebuggerRemote::set_skip_breakpoints(bool p_skip_breakpoints) { - skip_breakpoints = p_skip_breakpoints; -} - -ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_func = NULL; - -ScriptDebuggerRemote::ScriptDebuggerRemote() : - profiling(false), - profiling_network(false), - max_frame_functions(16), - skip_profile_frame(false), - reload_all_scripts(false), - tcp_client(Ref<StreamPeerTCP>(memnew(StreamPeerTCP))), - packet_peer_stream(Ref<PacketPeerStream>(memnew(PacketPeerStream))), - last_perf_time(0), - last_net_prof_time(0), - last_net_bandwidth_time(0), - performance(Engine::get_singleton()->get_singleton_object("Performance")), - requested_quit(false), - mutex(Mutex::create()), - max_messages_per_frame(GLOBAL_GET("network/limits/debugger_stdout/max_messages_per_frame")), - n_messages_dropped(0), - max_errors_per_second(GLOBAL_GET("network/limits/debugger_stdout/max_errors_per_second")), - max_warnings_per_second(GLOBAL_GET("network/limits/debugger_stdout/max_warnings_per_second")), - n_errors_dropped(0), - max_cps(GLOBAL_GET("network/limits/debugger_stdout/max_chars_per_second")), - char_count(0), - err_count(0), - warn_count(0), - last_msec(0), - msec_count(0), - locking(false), - poll_every(0), - request_scene_tree(NULL), - live_edit_funcs(NULL) { - - packet_peer_stream->set_stream_peer(tcp_client); - packet_peer_stream->set_output_buffer_max_size(1024 * 1024 * 8); //8mb should be way more than enough - - phl.printfunc = _print_handler; - phl.userdata = this; - add_print_handler(&phl); - - eh.errfunc = _err_handler; - eh.userdata = this; - add_error_handler(&eh); - - profile_info.resize(GLOBAL_GET("debug/settings/profiler/max_functions")); - network_profile_info.resize(GLOBAL_GET("debug/settings/profiler/max_functions")); - profile_info_ptrs.resize(profile_info.size()); -} - -ScriptDebuggerRemote::~ScriptDebuggerRemote() { - - remove_print_handler(&phl); - remove_error_handler(&eh); - memdelete(mutex); -} diff --git a/core/script_debugger_remote.h b/core/script_debugger_remote.h deleted file mode 100644 index b6dd925181..0000000000 --- a/core/script_debugger_remote.h +++ /dev/null @@ -1,196 +0,0 @@ -/*************************************************************************/ -/* script_debugger_remote.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 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 SCRIPT_DEBUGGER_REMOTE_H -#define SCRIPT_DEBUGGER_REMOTE_H - -#include "core/io/packet_peer.h" -#include "core/io/stream_peer_tcp.h" -#include "core/list.h" -#include "core/os/os.h" -#include "core/script_language.h" - -class ScriptDebuggerRemote : public ScriptDebugger { - - struct Message { - - String message; - Array data; - }; - - struct ProfileInfoSort { - - bool operator()(ScriptLanguage::ProfilingInfo *A, ScriptLanguage::ProfilingInfo *B) const { - return A->total_time < B->total_time; - } - }; - - Vector<ScriptLanguage::ProfilingInfo> profile_info; - Vector<ScriptLanguage::ProfilingInfo *> profile_info_ptrs; - Vector<MultiplayerAPI::ProfilingInfo> network_profile_info; - - Map<StringName, int> profiler_function_signature_map; - float frame_time, idle_time, physics_time, physics_frame_time; - - bool profiling; - bool profiling_network; - int max_frame_functions; - bool skip_profile_frame; - bool reload_all_scripts; - - Ref<StreamPeerTCP> tcp_client; - Ref<PacketPeerStream> packet_peer_stream; - - uint64_t last_perf_time; - uint64_t last_net_prof_time; - uint64_t last_net_bandwidth_time; - Object *performance; - bool requested_quit; - Mutex *mutex; - - struct OutputError { - - int hr; - int min; - int sec; - int msec; - String source_file; - String source_func; - int source_line; - String error; - String error_descr; - bool warning; - Array callstack; - }; - - List<String> output_strings; - List<Message> messages; - int max_messages_per_frame; - int n_messages_dropped; - List<OutputError> errors; - int max_errors_per_second; - int max_warnings_per_second; - int n_errors_dropped; - int n_warnings_dropped; - - int max_cps; - int char_count; - int err_count; - int warn_count; - uint64_t last_msec; - uint64_t msec_count; - - bool locking; //hack to avoid a deadloop - static void _print_handler(void *p_this, const String &p_string, bool p_error); - - PrintHandlerList phl; - - void _get_output(); - void _poll_events(); - uint32_t poll_every; - - bool _parse_live_edit(const Array &p_command); - - RequestSceneTreeMessageFunc request_scene_tree; - void *request_scene_tree_ud; - - void _set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value); - - void _send_object_id(ObjectID p_id); - void _send_video_memory(); - LiveEditFuncs *live_edit_funcs; - - Ref<MultiplayerAPI> multiplayer; - - ErrorHandlerList eh; - static void _err_handler(void *, const char *, const char *, int p_line, const char *, const char *, ErrorHandlerType p_type); - - void _send_profiling_data(bool p_for_frame); - void _send_network_profiling_data(); - void _send_network_bandwidth_usage(); - - struct FrameData { - - StringName name; - Array data; - }; - - Vector<FrameData> profile_frame_data; - - void _put_variable(const String &p_name, const Variant &p_variable); - - void _save_node(ObjectID id, const String &p_path); - - bool skip_breakpoints; - -public: - struct ResourceUsage { - - String path; - String format; - String type; - RID id; - int vram; - bool operator<(const ResourceUsage &p_img) const { return vram == p_img.vram ? id < p_img.id : vram > p_img.vram; } - }; - - typedef void (*ResourceUsageFunc)(List<ResourceUsage> *); - - static ResourceUsageFunc resource_usage_func; - - Error connect_to_host(const String &p_host, uint16_t p_port); - virtual void debug(ScriptLanguage *p_script, bool p_can_continue = true, bool p_is_error_breakpoint = false); - virtual void idle_poll(); - virtual void line_poll(); - - virtual bool is_remote() const { return true; } - virtual void request_quit(); - - virtual void send_message(const String &p_message, const Array &p_args); - virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info); - - virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata); - virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs); - virtual void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer); - - virtual bool is_profiling() const; - virtual void add_profiling_frame_data(const StringName &p_name, const Array &p_data); - - virtual void profiling_start(); - virtual void profiling_end(); - virtual void profiling_set_frame_times(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time); - - virtual void set_skip_breakpoints(bool p_skip_breakpoints); - - ScriptDebuggerRemote(); - ~ScriptDebuggerRemote(); -}; - -#endif // SCRIPT_DEBUGGER_REMOTE_H diff --git a/core/script_language.cpp b/core/script_language.cpp index 7201773ea5..cbe4681eca 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -218,6 +218,7 @@ void ScriptServer::global_classes_clear() { } void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) { + ERR_FAIL_COND_MSG(p_class == p_base || (global_classes.has(p_base) && get_global_class_native_base(p_base) == p_class), "Cyclic inheritance in script class."); GlobalScriptClass g; g.language = p_language; g.path = p_path; diff --git a/core/script_language.h b/core/script_language.h index 116918fdc0..f90bb4b6c3 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -427,31 +427,6 @@ class ScriptDebugger { ScriptLanguage *break_lang; public: - typedef void (*RequestSceneTreeMessageFunc)(void *); - - struct LiveEditFuncs { - - void *udata; - void (*node_path_func)(void *, const NodePath &p_path, int p_id); - void (*res_path_func)(void *, const String &p_path, int p_id); - - void (*node_set_func)(void *, int p_id, const StringName &p_prop, const Variant &p_value); - void (*node_set_res_func)(void *, int p_id, const StringName &p_prop, const String &p_value); - void (*node_call_func)(void *, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE); - void (*res_set_func)(void *, int p_id, const StringName &p_prop, const Variant &p_value); - void (*res_set_res_func)(void *, int p_id, const StringName &p_prop, const String &p_value); - void (*res_call_func)(void *, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE); - void (*root_func)(void *, const NodePath &p_scene_path, const String &p_scene_from); - - void (*tree_create_node_func)(void *, const NodePath &p_parent, const String &p_type, const String &p_name); - void (*tree_instance_node_func)(void *, const NodePath &p_parent, const String &p_path, const String &p_name); - void (*tree_remove_node_func)(void *, const NodePath &p_at); - void (*tree_remove_and_keep_node_func)(void *, const NodePath &p_at, ObjectID p_keep_id); - void (*tree_restore_node_func)(void *, ObjectID p_id, const NodePath &p_at, int p_at_pos); - void (*tree_duplicate_node_func)(void *, const NodePath &p_at, const String &p_new_name); - void (*tree_reparent_node_func)(void *, const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos); - }; - _FORCE_INLINE_ static ScriptDebugger *get_singleton() { return singleton; } void set_lines_left(int p_left); int get_lines_left() const; @@ -480,8 +455,6 @@ public: virtual bool is_remote() const { return false; } virtual void request_quit() {} - virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {} - virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs) {} virtual void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {} virtual bool is_profiling() const = 0; diff --git a/core/translation.cpp b/core/translation.cpp index a0902d71fc..4a1ac26433 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -986,6 +986,7 @@ Array TranslationServer::get_loaded_locales() const { for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) { const Ref<Translation> &t = E->get(); + ERR_FAIL_COND_V(t.is_null(), Array()); String l = t->get_locale(); locales.push_back(l); @@ -1057,6 +1058,7 @@ StringName TranslationServer::translate(const StringName &p_message) const { for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) { const Ref<Translation> &t = E->get(); + ERR_FAIL_COND_V(t.is_null(), StringName("")); String l = t->get_locale(); if (lptr[0] != l[0] || lptr[1] != l[1]) continue; // Language code does not match. @@ -1085,6 +1087,7 @@ StringName TranslationServer::translate(const StringName &p_message) const { for (const Set<Ref<Translation> >::Element *E = translations.front(); E; E = E->next()) { const Ref<Translation> &t = E->get(); + ERR_FAIL_COND_V(t.is_null(), StringName("")); String l = t->get_locale(); if (fptr[0] != l[0] || fptr[1] != l[1]) continue; // Language code does not match. diff --git a/core/typedefs.h b/core/typedefs.h index 767a97ac38..42f34c73cb 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -174,6 +174,9 @@ inline void __swap_tmpl(T &x, T &y) { static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) { + if (x == 0) + return 0; + --x; x |= x >> 1; x |= x >> 2; diff --git a/core/ustring.cpp b/core/ustring.cpp index f029ae4200..25930db201 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -1337,7 +1337,17 @@ String String::num_scientific(double p_num) { char buf[256]; #if defined(__GNUC__) || defined(_MSC_VER) + +#if (defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER < 1900)) && defined(_TWO_DIGIT_EXPONENT) && !defined(_UCRT) + // MinGW and old MSC require _set_output_format() to conform to C99 output for printf + unsigned int old_exponent_format = _set_output_format(_TWO_DIGIT_EXPONENT); +#endif snprintf(buf, 256, "%lg", p_num); + +#if (defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER < 1900)) && defined(_TWO_DIGIT_EXPONENT) && !defined(_UCRT) + _set_output_format(old_exponent_format); +#endif + #else sprintf(buf, "%.16lg", p_num); #endif @@ -1406,7 +1416,7 @@ bool String::parse_utf8(const char *p_utf8, int p_len) { if (skip == 0) { - uint8_t c = *ptrtmp; + uint8_t c = *ptrtmp >= 0 ? *ptrtmp : uint8_t(256 + *ptrtmp); /* Determine the number of characters in sequence */ if ((c & 0x80) == 0) @@ -4058,6 +4068,11 @@ String itos(int64_t p_val) { return String::num_int64(p_val); } +String uitos(uint64_t p_val) { + + return String::num_uint64(p_val); +} + String rtos(double p_val) { return String::num(p_val); diff --git a/core/ustring.h b/core/ustring.h index 15e2c07d9f..dfc5044942 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -369,6 +369,7 @@ String operator+(const char *p_chr, const String &p_str); String operator+(CharType p_chr, const String &p_str); String itos(int64_t p_val); +String uitos(uint64_t p_val); String rtos(double p_val); String rtoss(double p_val); //scientific version diff --git a/core/variant.cpp b/core/variant.cpp index 16bbf94c54..e0cc6685f4 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -3299,7 +3299,7 @@ String vformat(const String &p_text, const Variant &p1, const Variant &p2, const bool error = false; String fmt = p_text.sprintf(args, &error); - ERR_FAIL_COND_V(error, String()); + ERR_FAIL_COND_V_MSG(error, String(), fmt); return fmt; } diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 40b944744b..6e593a308d 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -351,12 +351,13 @@ struct _VariantCall { r_ret = retval; } - VCALL_LOCALMEM0R(Vector2, normalized); + VCALL_LOCALMEM1R(Vector2, distance_to); + VCALL_LOCALMEM1R(Vector2, distance_squared_to); VCALL_LOCALMEM0R(Vector2, length); VCALL_LOCALMEM0R(Vector2, length_squared); + VCALL_LOCALMEM0R(Vector2, normalized); VCALL_LOCALMEM0R(Vector2, is_normalized); - VCALL_LOCALMEM1R(Vector2, distance_to); - VCALL_LOCALMEM1R(Vector2, distance_squared_to); + VCALL_LOCALMEM1R(Vector2, is_equal_approx); VCALL_LOCALMEM1R(Vector2, posmod); VCALL_LOCALMEM1R(Vector2, posmodv); VCALL_LOCALMEM1R(Vector2, project); @@ -385,24 +386,28 @@ struct _VariantCall { VCALL_LOCALMEM0R(Vector2, sign); VCALL_LOCALMEM0R(Rect2, get_area); + VCALL_LOCALMEM0R(Rect2, has_no_area); + VCALL_LOCALMEM1R(Rect2, has_point); + VCALL_LOCALMEM1R(Rect2, is_equal_approx); VCALL_LOCALMEM1R(Rect2, intersects); VCALL_LOCALMEM1R(Rect2, encloses); - VCALL_LOCALMEM0R(Rect2, has_no_area); VCALL_LOCALMEM1R(Rect2, clip); VCALL_LOCALMEM1R(Rect2, merge); - VCALL_LOCALMEM1R(Rect2, has_point); + VCALL_LOCALMEM1R(Rect2, expand); VCALL_LOCALMEM1R(Rect2, grow); VCALL_LOCALMEM2R(Rect2, grow_margin); VCALL_LOCALMEM4R(Rect2, grow_individual); - VCALL_LOCALMEM1R(Rect2, expand); VCALL_LOCALMEM0R(Rect2, abs); VCALL_LOCALMEM0R(Vector3, min_axis); VCALL_LOCALMEM0R(Vector3, max_axis); + VCALL_LOCALMEM1R(Vector3, distance_to); + VCALL_LOCALMEM1R(Vector3, distance_squared_to); VCALL_LOCALMEM0R(Vector3, length); VCALL_LOCALMEM0R(Vector3, length_squared); - VCALL_LOCALMEM0R(Vector3, is_normalized); VCALL_LOCALMEM0R(Vector3, normalized); + VCALL_LOCALMEM0R(Vector3, is_normalized); + VCALL_LOCALMEM1R(Vector3, is_equal_approx); VCALL_LOCALMEM0R(Vector3, inverse); VCALL_LOCALMEM1R(Vector3, snapped); VCALL_LOCALMEM2R(Vector3, rotated); @@ -418,8 +423,6 @@ struct _VariantCall { VCALL_LOCALMEM0R(Vector3, floor); VCALL_LOCALMEM0R(Vector3, ceil); VCALL_LOCALMEM0R(Vector3, round); - VCALL_LOCALMEM1R(Vector3, distance_to); - VCALL_LOCALMEM1R(Vector3, distance_squared_to); VCALL_LOCALMEM1R(Vector3, posmod); VCALL_LOCALMEM1R(Vector3, posmodv); VCALL_LOCALMEM1R(Vector3, project); @@ -433,6 +436,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(Plane, normalized); VCALL_LOCALMEM0R(Plane, center); VCALL_LOCALMEM0R(Plane, get_any_point); + VCALL_LOCALMEM1R(Plane, is_equal_approx); VCALL_LOCALMEM1R(Plane, is_point_over); VCALL_LOCALMEM1R(Plane, distance_to); VCALL_LOCALMEM2R(Plane, has_point); @@ -467,6 +471,7 @@ struct _VariantCall { VCALL_LOCALMEM0R(Quat, length_squared); VCALL_LOCALMEM0R(Quat, normalized); VCALL_LOCALMEM0R(Quat, is_normalized); + VCALL_LOCALMEM1R(Quat, is_equal_approx); VCALL_LOCALMEM0R(Quat, inverse); VCALL_LOCALMEM1R(Quat, dot); VCALL_LOCALMEM1R(Quat, xform); @@ -492,6 +497,7 @@ struct _VariantCall { VCALL_LOCALMEM1R(Color, darkened); VCALL_LOCALMEM1R(Color, to_html); VCALL_LOCALMEM4R(Color, from_hsv); + VCALL_LOCALMEM1R(Color, is_equal_approx); VCALL_LOCALMEM0R(RID, get_id); @@ -626,6 +632,7 @@ struct _VariantCall { } VCALL_LOCALMEM0R(PoolByteArray, size); + VCALL_LOCALMEM0R(PoolByteArray, empty); VCALL_LOCALMEM2(PoolByteArray, set); VCALL_LOCALMEM1R(PoolByteArray, get); VCALL_LOCALMEM1(PoolByteArray, push_back); @@ -638,6 +645,7 @@ struct _VariantCall { VCALL_LOCALMEM2R(PoolByteArray, subarray); VCALL_LOCALMEM0R(PoolIntArray, size); + VCALL_LOCALMEM0R(PoolIntArray, empty); VCALL_LOCALMEM2(PoolIntArray, set); VCALL_LOCALMEM1R(PoolIntArray, get); VCALL_LOCALMEM1(PoolIntArray, push_back); @@ -649,6 +657,7 @@ struct _VariantCall { VCALL_LOCALMEM0(PoolIntArray, invert); VCALL_LOCALMEM0R(PoolRealArray, size); + VCALL_LOCALMEM0R(PoolRealArray, empty); VCALL_LOCALMEM2(PoolRealArray, set); VCALL_LOCALMEM1R(PoolRealArray, get); VCALL_LOCALMEM1(PoolRealArray, push_back); @@ -660,6 +669,7 @@ struct _VariantCall { VCALL_LOCALMEM0(PoolRealArray, invert); VCALL_LOCALMEM0R(PoolStringArray, size); + VCALL_LOCALMEM0R(PoolStringArray, empty); VCALL_LOCALMEM2(PoolStringArray, set); VCALL_LOCALMEM1R(PoolStringArray, get); VCALL_LOCALMEM1(PoolStringArray, push_back); @@ -672,6 +682,7 @@ struct _VariantCall { VCALL_LOCALMEM1R(PoolStringArray, join); VCALL_LOCALMEM0R(PoolVector2Array, size); + VCALL_LOCALMEM0R(PoolVector2Array, empty); VCALL_LOCALMEM2(PoolVector2Array, set); VCALL_LOCALMEM1R(PoolVector2Array, get); VCALL_LOCALMEM1(PoolVector2Array, push_back); @@ -683,6 +694,7 @@ struct _VariantCall { VCALL_LOCALMEM0(PoolVector2Array, invert); VCALL_LOCALMEM0R(PoolVector3Array, size); + VCALL_LOCALMEM0R(PoolVector3Array, empty); VCALL_LOCALMEM2(PoolVector3Array, set); VCALL_LOCALMEM1R(PoolVector3Array, get); VCALL_LOCALMEM1(PoolVector3Array, push_back); @@ -694,6 +706,7 @@ struct _VariantCall { VCALL_LOCALMEM0(PoolVector3Array, invert); VCALL_LOCALMEM0R(PoolColorArray, size); + VCALL_LOCALMEM0R(PoolColorArray, empty); VCALL_LOCALMEM2(PoolColorArray, set); VCALL_LOCALMEM1R(PoolColorArray, get); VCALL_LOCALMEM1(PoolColorArray, push_back); @@ -732,13 +745,16 @@ struct _VariantCall { VCALL_PTR0R(AABB, get_area); VCALL_PTR0R(AABB, has_no_area); VCALL_PTR0R(AABB, has_no_surface); + VCALL_PTR1R(AABB, has_point); + VCALL_PTR1R(AABB, is_equal_approx); VCALL_PTR1R(AABB, intersects); VCALL_PTR1R(AABB, encloses); - VCALL_PTR1R(AABB, merge); - VCALL_PTR1R(AABB, intersection); VCALL_PTR1R(AABB, intersects_plane); VCALL_PTR2R(AABB, intersects_segment); - VCALL_PTR1R(AABB, has_point); + VCALL_PTR1R(AABB, intersection); + VCALL_PTR1R(AABB, merge); + VCALL_PTR1R(AABB, expand); + VCALL_PTR1R(AABB, grow); VCALL_PTR1R(AABB, get_support); VCALL_PTR0R(AABB, get_longest_axis); VCALL_PTR0R(AABB, get_longest_axis_index); @@ -746,8 +762,6 @@ struct _VariantCall { VCALL_PTR0R(AABB, get_shortest_axis); VCALL_PTR0R(AABB, get_shortest_axis_index); VCALL_PTR0R(AABB, get_shortest_axis_size); - VCALL_PTR1R(AABB, expand); - VCALL_PTR1R(AABB, grow); VCALL_PTR1R(AABB, get_endpoint); VCALL_PTR0R(Transform2D, inverse); @@ -760,6 +774,7 @@ struct _VariantCall { VCALL_PTR1R(Transform2D, scaled); VCALL_PTR1R(Transform2D, translated); VCALL_PTR2R(Transform2D, interpolate_with); + VCALL_PTR1R(Transform2D, is_equal_approx); static void _call_Transform2D_xform(Variant &r_ret, Variant &p_self, const Variant **p_args) { @@ -816,7 +831,7 @@ struct _VariantCall { VCALL_PTR0R(Basis, get_orthogonal_index); VCALL_PTR0R(Basis, orthonormalized); VCALL_PTR2R(Basis, slerp); - VCALL_PTR2R(Basis, is_equal_approx); + VCALL_PTR2R(Basis, is_equal_approx); // TODO: Break compatibility in 4.0 to change this to an instance method (a.is_equal_approx(b) as VCALL_PTR1R) for consistency. VCALL_PTR0R(Basis, get_rotation_quat); VCALL_PTR0R(Transform, inverse); @@ -827,6 +842,7 @@ struct _VariantCall { VCALL_PTR0R(Transform, orthonormalized); VCALL_PTR2R(Transform, looking_at); VCALL_PTR2R(Transform, interpolate_with); + VCALL_PTR1R(Transform, is_equal_approx); static void _call_Transform_xform(Variant &r_ret, Variant &p_self, const Variant **p_args) { @@ -1607,19 +1623,20 @@ void register_variant_methods() { ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_ascii, varray()); ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_utf8, varray()); - ADDFUNC0R(VECTOR2, VECTOR2, Vector2, normalized, varray()); - ADDFUNC0R(VECTOR2, REAL, Vector2, length, varray()); ADDFUNC0R(VECTOR2, REAL, Vector2, angle, varray()); - ADDFUNC0R(VECTOR2, REAL, Vector2, length_squared, varray()); - ADDFUNC0R(VECTOR2, BOOL, Vector2, is_normalized, varray()); + ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to, VECTOR2, "to", varray()); + ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to_point, VECTOR2, "to", varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, direction_to, VECTOR2, "b", varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, distance_to, VECTOR2, "to", varray()); ADDFUNC1R(VECTOR2, REAL, Vector2, distance_squared_to, VECTOR2, "to", varray()); + ADDFUNC0R(VECTOR2, REAL, Vector2, length, varray()); + ADDFUNC0R(VECTOR2, REAL, Vector2, length_squared, varray()); + ADDFUNC0R(VECTOR2, VECTOR2, Vector2, normalized, varray()); + ADDFUNC0R(VECTOR2, BOOL, Vector2, is_normalized, varray()); + ADDFUNC1R(VECTOR2, BOOL, Vector2, is_equal_approx, VECTOR2, "v", varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, posmod, REAL, "mod", varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, posmodv, VECTOR2, "modv", varray()); ADDFUNC1R(VECTOR2, VECTOR2, Vector2, project, VECTOR2, "b", varray()); - ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to, VECTOR2, "to", varray()); - ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to_point, VECTOR2, "to", varray()); ADDFUNC2R(VECTOR2, VECTOR2, Vector2, linear_interpolate, VECTOR2, "b", REAL, "t", varray()); ADDFUNC2R(VECTOR2, VECTOR2, Vector2, slerp, VECTOR2, "b", REAL, "t", varray()); ADDFUNC4R(VECTOR2, VECTOR2, Vector2, cubic_interpolate, VECTOR2, "b", VECTOR2, "pre_a", VECTOR2, "post_b", REAL, "t", varray()); @@ -1641,31 +1658,36 @@ void register_variant_methods() { ADDFUNC0R(VECTOR2, VECTOR2, Vector2, sign, varray()); ADDFUNC0R(RECT2, REAL, Rect2, get_area, varray()); + ADDFUNC0R(RECT2, BOOL, Rect2, has_no_area, varray()); + ADDFUNC1R(RECT2, BOOL, Rect2, has_point, VECTOR2, "point", varray()); + ADDFUNC1R(RECT2, BOOL, Rect2, is_equal_approx, RECT2, "rect", varray()); ADDFUNC1R(RECT2, BOOL, Rect2, intersects, RECT2, "b", varray()); ADDFUNC1R(RECT2, BOOL, Rect2, encloses, RECT2, "b", varray()); - ADDFUNC0R(RECT2, BOOL, Rect2, has_no_area, varray()); ADDFUNC1R(RECT2, RECT2, Rect2, clip, RECT2, "b", varray()); ADDFUNC1R(RECT2, RECT2, Rect2, merge, RECT2, "b", varray()); - ADDFUNC1R(RECT2, BOOL, Rect2, has_point, VECTOR2, "point", varray()); + ADDFUNC1R(RECT2, RECT2, Rect2, expand, VECTOR2, "to", varray()); ADDFUNC1R(RECT2, RECT2, Rect2, grow, REAL, "by", varray()); ADDFUNC2R(RECT2, RECT2, Rect2, grow_margin, INT, "margin", REAL, "by", varray()); ADDFUNC4R(RECT2, RECT2, Rect2, grow_individual, REAL, "left", REAL, "top", REAL, "right", REAL, " bottom", varray()); - ADDFUNC1R(RECT2, RECT2, Rect2, expand, VECTOR2, "to", varray()); ADDFUNC0R(RECT2, RECT2, Rect2, abs, varray()); ADDFUNC0R(VECTOR3, INT, Vector3, min_axis, varray()); ADDFUNC0R(VECTOR3, INT, Vector3, max_axis, varray()); + ADDFUNC1R(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray()); + ADDFUNC1R(VECTOR3, VECTOR3, Vector3, direction_to, VECTOR3, "b", varray()); + ADDFUNC1R(VECTOR3, REAL, Vector3, distance_to, VECTOR3, "b", varray()); + ADDFUNC1R(VECTOR3, REAL, Vector3, distance_squared_to, VECTOR3, "b", varray()); ADDFUNC0R(VECTOR3, REAL, Vector3, length, varray()); ADDFUNC0R(VECTOR3, REAL, Vector3, length_squared, varray()); - ADDFUNC0R(VECTOR3, BOOL, Vector3, is_normalized, varray()); ADDFUNC0R(VECTOR3, VECTOR3, Vector3, normalized, varray()); + ADDFUNC0R(VECTOR3, BOOL, Vector3, is_normalized, varray()); + ADDFUNC1R(VECTOR3, BOOL, Vector3, is_equal_approx, VECTOR3, "v", varray()); ADDFUNC0R(VECTOR3, VECTOR3, Vector3, inverse, varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, snapped, VECTOR3, "by", varray()); ADDFUNC2R(VECTOR3, VECTOR3, Vector3, rotated, VECTOR3, "axis", REAL, "phi", varray()); ADDFUNC2R(VECTOR3, VECTOR3, Vector3, linear_interpolate, VECTOR3, "b", REAL, "t", varray()); ADDFUNC2R(VECTOR3, VECTOR3, Vector3, slerp, VECTOR3, "b", REAL, "t", varray()); ADDFUNC4R(VECTOR3, VECTOR3, Vector3, cubic_interpolate, VECTOR3, "b", VECTOR3, "pre_a", VECTOR3, "post_b", REAL, "t", varray()); - ADDFUNC1R(VECTOR3, VECTOR3, Vector3, direction_to, VECTOR3, "b", varray()); ADDFUNC2R(VECTOR3, VECTOR3, Vector3, move_toward, VECTOR3, "to", REAL, "delta", varray()); ADDFUNC1R(VECTOR3, REAL, Vector3, dot, VECTOR3, "b", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, cross, VECTOR3, "b", varray()); @@ -1675,12 +1697,9 @@ void register_variant_methods() { ADDFUNC0R(VECTOR3, VECTOR3, Vector3, floor, varray()); ADDFUNC0R(VECTOR3, VECTOR3, Vector3, ceil, varray()); ADDFUNC0R(VECTOR3, VECTOR3, Vector3, round, varray()); - ADDFUNC1R(VECTOR3, REAL, Vector3, distance_to, VECTOR3, "b", varray()); - ADDFUNC1R(VECTOR3, REAL, Vector3, distance_squared_to, VECTOR3, "b", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, posmod, REAL, "mod", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, posmodv, VECTOR3, "modv", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, project, VECTOR3, "b", varray()); - ADDFUNC1R(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, slide, VECTOR3, "n", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, bounce, VECTOR3, "n", varray()); ADDFUNC1R(VECTOR3, VECTOR3, Vector3, reflect, VECTOR3, "n", varray()); @@ -1689,6 +1708,7 @@ void register_variant_methods() { ADDFUNC0R(PLANE, PLANE, Plane, normalized, varray()); ADDFUNC0R(PLANE, VECTOR3, Plane, center, varray()); ADDFUNC0R(PLANE, VECTOR3, Plane, get_any_point, varray()); + ADDFUNC1R(PLANE, BOOL, Plane, is_equal_approx, PLANE, "plane", varray()); ADDFUNC1R(PLANE, BOOL, Plane, is_point_over, VECTOR3, "point", varray()); ADDFUNC1R(PLANE, REAL, Plane, distance_to, VECTOR3, "point", varray()); ADDFUNC2R(PLANE, BOOL, Plane, has_point, VECTOR3, "point", REAL, "epsilon", varray(CMP_EPSILON)); @@ -1701,6 +1721,7 @@ void register_variant_methods() { ADDFUNC0R(QUAT, REAL, Quat, length_squared, varray()); ADDFUNC0R(QUAT, QUAT, Quat, normalized, varray()); ADDFUNC0R(QUAT, BOOL, Quat, is_normalized, varray()); + ADDFUNC1R(QUAT, BOOL, Quat, is_equal_approx, QUAT, "quat", varray()); ADDFUNC0R(QUAT, QUAT, Quat, inverse, varray()); ADDFUNC1R(QUAT, REAL, Quat, dot, QUAT, "b", varray()); ADDFUNC1R(QUAT, VECTOR3, Quat, xform, VECTOR3, "v", varray()); @@ -1726,6 +1747,7 @@ void register_variant_methods() { ADDFUNC1R(COLOR, COLOR, Color, darkened, REAL, "amount", varray()); ADDFUNC1R(COLOR, STRING, Color, to_html, BOOL, "with_alpha", varray(true)); ADDFUNC4R(COLOR, COLOR, Color, from_hsv, REAL, "h", REAL, "s", REAL, "v", REAL, "a", varray(1.0)); + ADDFUNC1R(COLOR, BOOL, Color, is_equal_approx, COLOR, "color", varray()); ADDFUNC0R(_RID, INT, RID, get_id, varray()); @@ -1782,6 +1804,7 @@ void register_variant_methods() { ADDFUNC0R(ARRAY, NIL, Array, min, varray()); ADDFUNC0R(POOL_BYTE_ARRAY, INT, PoolByteArray, size, varray()); + ADDFUNC0R(POOL_BYTE_ARRAY, BOOL, PoolByteArray, empty, varray()); ADDFUNC2(POOL_BYTE_ARRAY, NIL, PoolByteArray, set, INT, "idx", INT, "byte", varray()); ADDFUNC1(POOL_BYTE_ARRAY, NIL, PoolByteArray, push_back, INT, "byte", varray()); ADDFUNC1(POOL_BYTE_ARRAY, NIL, PoolByteArray, append, INT, "byte", varray()); @@ -1799,6 +1822,7 @@ void register_variant_methods() { ADDFUNC2R(POOL_BYTE_ARRAY, POOL_BYTE_ARRAY, PoolByteArray, decompress, INT, "buffer_size", INT, "compression_mode", varray(0)); ADDFUNC0R(POOL_INT_ARRAY, INT, PoolIntArray, size, varray()); + ADDFUNC0R(POOL_INT_ARRAY, BOOL, PoolIntArray, empty, varray()); ADDFUNC2(POOL_INT_ARRAY, NIL, PoolIntArray, set, INT, "idx", INT, "integer", varray()); ADDFUNC1(POOL_INT_ARRAY, NIL, PoolIntArray, push_back, INT, "integer", varray()); ADDFUNC1(POOL_INT_ARRAY, NIL, PoolIntArray, append, INT, "integer", varray()); @@ -1809,6 +1833,7 @@ void register_variant_methods() { ADDFUNC0(POOL_INT_ARRAY, NIL, PoolIntArray, invert, varray()); ADDFUNC0R(POOL_REAL_ARRAY, INT, PoolRealArray, size, varray()); + ADDFUNC0R(POOL_REAL_ARRAY, BOOL, PoolRealArray, empty, varray()); ADDFUNC2(POOL_REAL_ARRAY, NIL, PoolRealArray, set, INT, "idx", REAL, "value", varray()); ADDFUNC1(POOL_REAL_ARRAY, NIL, PoolRealArray, push_back, REAL, "value", varray()); ADDFUNC1(POOL_REAL_ARRAY, NIL, PoolRealArray, append, REAL, "value", varray()); @@ -1819,6 +1844,7 @@ void register_variant_methods() { ADDFUNC0(POOL_REAL_ARRAY, NIL, PoolRealArray, invert, varray()); ADDFUNC0R(POOL_STRING_ARRAY, INT, PoolStringArray, size, varray()); + ADDFUNC0R(POOL_STRING_ARRAY, BOOL, PoolStringArray, empty, varray()); ADDFUNC2(POOL_STRING_ARRAY, NIL, PoolStringArray, set, INT, "idx", STRING, "string", varray()); ADDFUNC1(POOL_STRING_ARRAY, NIL, PoolStringArray, push_back, STRING, "string", varray()); ADDFUNC1(POOL_STRING_ARRAY, NIL, PoolStringArray, append, STRING, "string", varray()); @@ -1830,6 +1856,7 @@ void register_variant_methods() { ADDFUNC1(POOL_STRING_ARRAY, STRING, PoolStringArray, join, STRING, "delimiter", varray()); ADDFUNC0R(POOL_VECTOR2_ARRAY, INT, PoolVector2Array, size, varray()); + ADDFUNC0R(POOL_VECTOR2_ARRAY, BOOL, PoolVector2Array, empty, varray()); ADDFUNC2(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, set, INT, "idx", VECTOR2, "vector2", varray()); ADDFUNC1(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, push_back, VECTOR2, "vector2", varray()); ADDFUNC1(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, append, VECTOR2, "vector2", varray()); @@ -1840,6 +1867,7 @@ void register_variant_methods() { ADDFUNC0(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, invert, varray()); ADDFUNC0R(POOL_VECTOR3_ARRAY, INT, PoolVector3Array, size, varray()); + ADDFUNC0R(POOL_VECTOR3_ARRAY, BOOL, PoolVector3Array, empty, varray()); ADDFUNC2(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, set, INT, "idx", VECTOR3, "vector3", varray()); ADDFUNC1(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, push_back, VECTOR3, "vector3", varray()); ADDFUNC1(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, append, VECTOR3, "vector3", varray()); @@ -1850,6 +1878,7 @@ void register_variant_methods() { ADDFUNC0(POOL_VECTOR3_ARRAY, NIL, PoolVector3Array, invert, varray()); ADDFUNC0R(POOL_COLOR_ARRAY, INT, PoolColorArray, size, varray()); + ADDFUNC0R(POOL_COLOR_ARRAY, BOOL, PoolColorArray, empty, varray()); ADDFUNC2(POOL_COLOR_ARRAY, NIL, PoolColorArray, set, INT, "idx", COLOR, "color", varray()); ADDFUNC1(POOL_COLOR_ARRAY, NIL, PoolColorArray, push_back, COLOR, "color", varray()); ADDFUNC1(POOL_COLOR_ARRAY, NIL, PoolColorArray, append, COLOR, "color", varray()); @@ -1864,13 +1893,16 @@ void register_variant_methods() { ADDFUNC0R(AABB, REAL, AABB, get_area, varray()); ADDFUNC0R(AABB, BOOL, AABB, has_no_area, varray()); ADDFUNC0R(AABB, BOOL, AABB, has_no_surface, varray()); + ADDFUNC1R(AABB, BOOL, AABB, has_point, VECTOR3, "point", varray()); + ADDFUNC1R(AABB, BOOL, AABB, is_equal_approx, AABB, "aabb", varray()); ADDFUNC1R(AABB, BOOL, AABB, intersects, AABB, "with", varray()); ADDFUNC1R(AABB, BOOL, AABB, encloses, AABB, "with", varray()); - ADDFUNC1R(AABB, AABB, AABB, merge, AABB, "with", varray()); - ADDFUNC1R(AABB, AABB, AABB, intersection, AABB, "with", varray()); ADDFUNC1R(AABB, BOOL, AABB, intersects_plane, PLANE, "plane", varray()); ADDFUNC2R(AABB, BOOL, AABB, intersects_segment, VECTOR3, "from", VECTOR3, "to", varray()); - ADDFUNC1R(AABB, BOOL, AABB, has_point, VECTOR3, "point", varray()); + ADDFUNC1R(AABB, AABB, AABB, intersection, AABB, "with", varray()); + ADDFUNC1R(AABB, AABB, AABB, merge, AABB, "with", varray()); + ADDFUNC1R(AABB, AABB, AABB, expand, VECTOR3, "to_point", varray()); + ADDFUNC1R(AABB, AABB, AABB, grow, REAL, "by", varray()); ADDFUNC1R(AABB, VECTOR3, AABB, get_support, VECTOR3, "dir", varray()); ADDFUNC0R(AABB, VECTOR3, AABB, get_longest_axis, varray()); ADDFUNC0R(AABB, INT, AABB, get_longest_axis_index, varray()); @@ -1878,8 +1910,6 @@ void register_variant_methods() { ADDFUNC0R(AABB, VECTOR3, AABB, get_shortest_axis, varray()); ADDFUNC0R(AABB, INT, AABB, get_shortest_axis_index, varray()); ADDFUNC0R(AABB, REAL, AABB, get_shortest_axis_size, varray()); - ADDFUNC1R(AABB, AABB, AABB, expand, VECTOR3, "to_point", varray()); - ADDFUNC1R(AABB, AABB, AABB, grow, REAL, "by", varray()); ADDFUNC1R(AABB, VECTOR3, AABB, get_endpoint, INT, "idx", varray()); ADDFUNC0R(TRANSFORM2D, TRANSFORM2D, Transform2D, inverse, varray()); @@ -1896,6 +1926,7 @@ void register_variant_methods() { ADDFUNC1R(TRANSFORM2D, VECTOR2, Transform2D, basis_xform, VECTOR2, "v", varray()); ADDFUNC1R(TRANSFORM2D, VECTOR2, Transform2D, basis_xform_inv, VECTOR2, "v", varray()); ADDFUNC2R(TRANSFORM2D, TRANSFORM2D, Transform2D, interpolate_with, TRANSFORM2D, "transform", REAL, "weight", varray()); + ADDFUNC1R(TRANSFORM2D, BOOL, Transform2D, is_equal_approx, TRANSFORM2D, "transform", varray()); ADDFUNC0R(BASIS, BASIS, Basis, inverse, varray()); ADDFUNC0R(BASIS, BASIS, Basis, transposed, varray()); @@ -1912,7 +1943,7 @@ 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)); + ADDFUNC2R(BASIS, BOOL, Basis, is_equal_approx, BASIS, "b", REAL, "epsilon", varray(CMP_EPSILON)); // TODO: Replace in 4.0, see other TODO. ADDFUNC0R(BASIS, QUAT, Basis, get_rotation_quat, varray()); ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, inverse, varray()); @@ -1923,6 +1954,7 @@ void register_variant_methods() { ADDFUNC1R(TRANSFORM, TRANSFORM, Transform, translated, VECTOR3, "ofs", varray()); ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, looking_at, VECTOR3, "target", VECTOR3, "up", varray()); ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, interpolate_with, TRANSFORM, "transform", REAL, "weight", varray()); + ADDFUNC1R(TRANSFORM, BOOL, Transform, is_equal_approx, TRANSFORM, "transform", varray()); ADDFUNC1R(TRANSFORM, NIL, Transform, xform, NIL, "v", varray()); ADDFUNC1R(TRANSFORM, NIL, Transform, xform_inv, NIL, "v", varray()); diff --git a/core/vmap.h b/core/vmap.h index fde9723d71..ed66b46993 100644 --- a/core/vmap.h +++ b/core/vmap.h @@ -196,8 +196,7 @@ public: int pos = _find_exact(p_key); if (pos < 0) { - V val; - pos = insert(p_key, val); + pos = insert(p_key, V()); } return _cowdata.get_m(pos).value; |