diff options
Diffstat (limited to 'core')
61 files changed, 632 insertions, 387 deletions
diff --git a/core/SCsub b/core/SCsub index 14dfa3487f..c12dd4e60e 100644 --- a/core/SCsub +++ b/core/SCsub @@ -146,6 +146,7 @@ env.core_sources += thirdparty_obj # Godot source files env.add_source_files(env.core_sources, "*.cpp") +env.add_source_files(env.core_sources, "script_encryption_key.gen.cpp") # Certificates env.Depends( diff --git a/core/config/engine.cpp b/core/config/engine.cpp index d8fbb50a75..dc5b3e25c6 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -111,7 +111,7 @@ Dictionary Engine::get_version_info() const { static Array array_from_info(const char *const *info_list) { Array arr; for (int i = 0; info_list[i] != nullptr; i++) { - arr.push_back(info_list[i]); + arr.push_back(String::utf8(info_list[i])); } return arr; } @@ -119,7 +119,7 @@ static Array array_from_info(const char *const *info_list) { static Array array_from_info_count(const char *const *info_list, int info_count) { Array arr; for (int i = 0; i < info_count; i++) { - arr.push_back(info_list[i]); + arr.push_back(String::utf8(info_list[i])); } return arr; } @@ -140,14 +140,14 @@ Array Engine::get_copyright_info() const { for (int component_index = 0; component_index < COPYRIGHT_INFO_COUNT; component_index++) { const ComponentCopyright &cp_info = COPYRIGHT_INFO[component_index]; Dictionary component_dict; - component_dict["name"] = cp_info.name; + component_dict["name"] = String::utf8(cp_info.name); Array parts; for (int i = 0; i < cp_info.part_count; i++) { const ComponentCopyrightPart &cp_part = cp_info.parts[i]; Dictionary part_dict; part_dict["files"] = array_from_info_count(cp_part.files, cp_part.file_count); part_dict["copyright"] = array_from_info_count(cp_part.copyright_statements, cp_part.copyright_count); - part_dict["license"] = cp_part.license; + part_dict["license"] = String::utf8(cp_part.license); parts.push_back(part_dict); } component_dict["parts"] = parts; diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 85e83ff7f2..562cbbdd27 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -48,11 +48,21 @@ ProjectSettings *ProjectSettings::get_singleton() { return singleton; } +String ProjectSettings::get_project_data_dir_name() const { + return project_data_dir_name; +} + +String ProjectSettings::get_project_data_path() const { + return "res://" + get_project_data_dir_name(); +} + String ProjectSettings::get_resource_path() const { return resource_path; } -const String ProjectSettings::IMPORTED_FILES_PATH("res://.godot/imported"); +String ProjectSettings::get_imported_files_path() const { + return get_project_data_path().plus_file("imported"); +} String ProjectSettings::localize_path(const String &p_path) const { if (resource_path.is_empty() || p_path.begins_with("res://") || p_path.begins_with("user://") || @@ -509,6 +519,10 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo _load_settings_text(custom_settings); } } + + // Updating the default value after the project settings have loaded. + project_data_dir_name = GLOBAL_GET("application/config/project_data_dir_name"); + // Using GLOBAL_GET on every block for compressing can be slow, so assigning here. Compression::zstd_long_distance_matching = GLOBAL_GET("compression/formats/zstd/long_distance_matching"); Compression::zstd_level = GLOBAL_GET("compression/formats/zstd/compression_level"); @@ -1080,6 +1094,7 @@ ProjectSettings::ProjectSettings() { custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res"); GLOBAL_DEF("application/run/disable_stdout", false); GLOBAL_DEF("application/run/disable_stderr", false); + project_data_dir_name = GLOBAL_DEF_RST("application/config/project_data_dir_name", ".godot"); GLOBAL_DEF("application/config/use_custom_user_dir", false); GLOBAL_DEF("application/config/custom_user_dir_name", ""); GLOBAL_DEF("application/config/project_settings_override", ""); diff --git a/core/config/project_settings.h b/core/config/project_settings.h index 7e93f26f0d..82f04b94df 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -42,7 +42,6 @@ class ProjectSettings : public Object { public: typedef Map<String, Variant> CustomMap; - static const String IMPORTED_FILES_PATH; enum { //properties that are not for built in values begin from this value, so builtin ones are displayed first @@ -94,6 +93,8 @@ protected: OrderedHashMap<StringName, AutoloadInfo> autoloads; + String project_data_dir_name; + bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; @@ -141,7 +142,10 @@ public: bool property_can_revert(const String &p_name); Variant property_get_revert(const String &p_name); + String get_project_data_dir_name() const; + String get_project_data_path() const; String get_resource_path() const; + String get_imported_files_path() const; static ProjectSettings *get_singleton(); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index f630adc39e..3a4fddc670 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -1077,79 +1077,79 @@ bool File::is_open() const { } String File::get_path() const { - ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use, or is lacking read-write permission."); return f->get_path(); } String File::get_path_absolute() const { - ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use, or is lacking read-write permission."); return f->get_path_absolute(); } void File::seek(int64_t p_position) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); ERR_FAIL_COND_MSG(p_position < 0, "Seek position must be a positive integer."); f->seek(p_position); } void File::seek_end(int64_t p_position) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->seek_end(p_position); } uint64_t File::get_position() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); return f->get_position(); } uint64_t File::get_length() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); return f->get_length(); } bool File::eof_reached() const { - ERR_FAIL_COND_V_MSG(!f, false, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, false, "File must be opened before use, or is lacking read-write permission."); return f->eof_reached(); } uint8_t File::get_8() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); return f->get_8(); } uint16_t File::get_16() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); return f->get_16(); } uint32_t File::get_32() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); return f->get_32(); } uint64_t File::get_64() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); return f->get_64(); } float File::get_float() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); return f->get_float(); } double File::get_double() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); return f->get_double(); } real_t File::get_real() const { - ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use, or is lacking read-write permission."); return f->get_real(); } Vector<uint8_t> File::get_buffer(int64_t p_length) const { Vector<uint8_t> data; - ERR_FAIL_COND_V_MSG(!f, data, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, data, "File must be opened before use, or is lacking read-write permission."); ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0."); if (p_length == 0) { @@ -1170,7 +1170,7 @@ Vector<uint8_t> File::get_buffer(int64_t p_length) const { } String File::get_as_text() const { - ERR_FAIL_COND_V_MSG(!f, String(), "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, String(), "File must be opened before use, or is lacking read-write permission."); String text; uint64_t original_pos = f->get_position(); @@ -1197,12 +1197,12 @@ String File::get_sha256(const String &p_path) const { } String File::get_line() const { - ERR_FAIL_COND_V_MSG(!f, String(), "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, String(), "File must be opened before use, or is lacking read-write permission."); return f->get_line(); } Vector<String> File::get_csv_line(const String &p_delim) const { - ERR_FAIL_COND_V_MSG(!f, Vector<String>(), "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, Vector<String>(), "File must be opened before use, or is lacking read-write permission."); return f->get_csv_line(p_delim); } @@ -1230,77 +1230,77 @@ Error File::get_error() const { } void File::store_8(uint8_t p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_8(p_dest); } void File::store_16(uint16_t p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_16(p_dest); } void File::store_32(uint32_t p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_32(p_dest); } void File::store_64(uint64_t p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_64(p_dest); } void File::store_float(float p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_float(p_dest); } void File::store_double(double p_dest) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_double(p_dest); } void File::store_real(real_t p_real) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_real(p_real); } void File::store_string(const String &p_string) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_string(p_string); } void File::store_pascal_string(const String &p_string) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_pascal_string(p_string); } String File::get_pascal_string() { - ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, "", "File must be opened before use, or is lacking read-write permission."); return f->get_pascal_string(); } void File::store_line(const String &p_string) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_line(p_string); } void File::store_csv_line(const Vector<String> &p_values, const String &p_delim) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); f->store_csv_line(p_values, p_delim); } void File::store_buffer(const Vector<uint8_t> &p_buffer) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); uint64_t len = p_buffer.size(); if (len == 0) { @@ -1317,7 +1317,7 @@ bool File::file_exists(const String &p_name) const { } void File::store_var(const Variant &p_var, bool p_full_objects) { - ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(!f, "File must be opened before use, or is lacking read-write permission."); int len; Error err = encode_variant(p_var, nullptr, len, p_full_objects); ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant."); @@ -1334,7 +1334,7 @@ void File::store_var(const Variant &p_var, bool p_full_objects) { } Variant File::get_var(bool p_allow_objects) const { - ERR_FAIL_COND_V_MSG(!f, Variant(), "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!f, Variant(), "File must be opened before use, or is lacking read-write permission."); uint32_t len = get_32(); Vector<uint8_t> buff = get_buffer(len); ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant()); @@ -1771,6 +1771,7 @@ void Thread::_start_func(void *ud) { Object *target_instance = t->target_callable.get_object(); if (!target_instance) { + t->running.clear(); ERR_FAIL_MSG(vformat("Could not call function '%s' on previously freed instance to start thread %s.", t->target_callable.get_method(), t->get_id())); } @@ -1813,19 +1814,22 @@ void Thread::_start_func(void *ud) { t->target_callable.call(arg, argc, t->ret, ce); if (ce.error != Callable::CallError::CALL_OK) { + t->running.clear(); ERR_FAIL_MSG("Could not call function '" + t->target_callable.get_method().operator String() + "' to start thread " + t->get_id() + ": " + Variant::get_callable_error_text(t->target_callable, arg, argc, ce) + "."); } + + t->running.clear(); } Error Thread::start(const Callable &p_callable, const Variant &p_userdata, Priority p_priority) { - ERR_FAIL_COND_V_MSG(active.is_set(), ERR_ALREADY_IN_USE, "Thread already started."); + ERR_FAIL_COND_V_MSG(is_started(), ERR_ALREADY_IN_USE, "Thread already started."); ERR_FAIL_COND_V(p_callable.is_null(), ERR_INVALID_PARAMETER); ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER); ret = Variant(); target_callable = p_callable; userdata = p_userdata; - active.set(); + running.set(); Ref<Thread> *ud = memnew(Ref<Thread>(this)); @@ -1840,15 +1844,18 @@ String Thread::get_id() const { return itos(thread.get_id()); } -bool Thread::is_active() const { - return active.is_set(); +bool Thread::is_started() const { + return thread.is_started(); +} + +bool Thread::is_alive() const { + return running.is_set(); } Variant Thread::wait_to_finish() { - ERR_FAIL_COND_V_MSG(!active.is_set(), Variant(), "Thread must be active to wait for its completion."); + ERR_FAIL_COND_V_MSG(!is_started(), Variant(), "Thread must have been started to wait for its completion."); thread.wait_to_finish(); Variant r = ret; - active.clear(); target_callable = Callable(); userdata = Variant(); @@ -1858,7 +1865,8 @@ Variant Thread::wait_to_finish() { void Thread::_bind_methods() { ClassDB::bind_method(D_METHOD("start", "callable", "userdata", "priority"), &Thread::start, DEFVAL(Variant()), DEFVAL(PRIORITY_NORMAL)); ClassDB::bind_method(D_METHOD("get_id"), &Thread::get_id); - ClassDB::bind_method(D_METHOD("is_active"), &Thread::is_active); + ClassDB::bind_method(D_METHOD("is_started"), &Thread::is_started); + ClassDB::bind_method(D_METHOD("is_alive"), &Thread::is_alive); ClassDB::bind_method(D_METHOD("wait_to_finish"), &Thread::wait_to_finish); BIND_ENUM_CONSTANT(PRIORITY_LOW); diff --git a/core/core_bind.h b/core/core_bind.h index 84a284f948..4eab085dda 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -538,7 +538,7 @@ class Thread : public RefCounted { protected: Variant ret; Variant userdata; - SafeFlag active; + SafeFlag running; Callable target_callable; ::Thread thread; static void _bind_methods(); @@ -554,7 +554,8 @@ public: Error start(const Callable &p_callable, const Variant &p_userdata = Variant(), Priority p_priority = PRIORITY_NORMAL); String get_id() const; - bool is_active() const; + bool is_started() const; + bool is_alive() const; Variant wait_to_finish(); }; diff --git a/core/debugger/engine_debugger.h b/core/debugger/engine_debugger.h index 22c6ef943e..41142bf305 100644 --- a/core/debugger/engine_debugger.h +++ b/core/debugger/engine_debugger.h @@ -128,7 +128,7 @@ public: virtual void poll_events(bool p_is_idle) {} virtual void send_message(const String &p_msg, const Array &p_data) = 0; - 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) = 0; + virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) = 0; virtual void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false) = 0; virtual ~EngineDebugger(); diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp index f7e56351b0..60aa3e6be7 100644 --- a/core/debugger/local_debugger.cpp +++ b/core/debugger/local_debugger.cpp @@ -358,7 +358,7 @@ void LocalDebugger::send_message(const String &p_message, const Array &p_args) { // print_line("MESSAGE: '" + p_message + "' - " + String(Variant(p_args))); } -void LocalDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type) { +void LocalDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) { print_line("ERROR: '" + (p_descr.is_empty() ? p_err : p_descr) + "'"); } diff --git a/core/debugger/local_debugger.h b/core/debugger/local_debugger.h index e793b2a859..cb59eb82e9 100644 --- a/core/debugger/local_debugger.h +++ b/core/debugger/local_debugger.h @@ -50,7 +50,7 @@ private: public: void debug(bool p_can_continue, bool p_is_error_breakpoint); void send_message(const String &p_message, const Array &p_args); - 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); + void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type); LocalDebugger(); ~LocalDebugger(); diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 032c7d55c0..9967d1e361 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -455,7 +455,7 @@ Error RemoteDebugger::_put_msg(String p_message, Array p_data) { return err; } -void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, ErrorHandlerType p_type) { +void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, bool p_editor_notify, ErrorHandlerType p_type) { if (p_type == ERR_HANDLER_SCRIPT) { return; //ignore script errors, those go through debugger } @@ -475,7 +475,7 @@ void RemoteDebugger::_err_handler(void *p_this, const char *p_func, const char * } // send_error will lock internally. - rd->script_debugger->send_error(p_func, p_file, p_line, p_err, p_descr, p_type, si); + rd->script_debugger->send_error(p_func, p_file, p_line, p_err, p_descr, p_editor_notify, p_type, si); } void RemoteDebugger::_print_handler(void *p_this, const String &p_string, bool p_error) { @@ -605,7 +605,7 @@ void RemoteDebugger::send_message(const String &p_message, const Array &p_args) } } -void RemoteDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type) { +void RemoteDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type) { ErrorMessage oe; oe.error = p_err; oe.error_descr = p_descr; diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h index 28e670747e..73799e3f81 100644 --- a/core/debugger/remote_debugger.h +++ b/core/debugger/remote_debugger.h @@ -89,7 +89,7 @@ private: PrintHandlerList phl; static void _print_handler(void *p_this, const String &p_string, bool p_error); ErrorHandlerList eh; - static void _err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, ErrorHandlerType p_type); + static void _err_handler(void *p_this, const char *p_func, const char *p_file, int p_line, const char *p_err, const char *p_descr, bool p_editor_notify, ErrorHandlerType p_type); ErrorMessage _create_overflow_error(const String &p_what, const String &p_descr); Error _put_msg(String p_message, Array p_data); @@ -111,7 +111,7 @@ public: // Overrides void poll_events(bool p_is_idle); void send_message(const String &p_message, const Array &p_args); - 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); + void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type); void debug(bool p_can_continue = true, bool p_is_error_breakpoint = false); RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer); diff --git a/core/debugger/script_debugger.cpp b/core/debugger/script_debugger.cpp index 6d1e4ed101..70ec101a03 100644 --- a/core/debugger/script_debugger.cpp +++ b/core/debugger/script_debugger.cpp @@ -100,10 +100,10 @@ void ScriptDebugger::debug(ScriptLanguage *p_lang, bool p_can_continue, bool p_i break_lang = prev; } -void ScriptDebugger::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<StackInfo> &p_stack_info) { +void ScriptDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type, const Vector<StackInfo> &p_stack_info) { // Store stack info, this is ugly, but allows us to separate EngineDebugger and ScriptDebugger. There might be a better way. error_stack_info.append_array(p_stack_info); - EngineDebugger::get_singleton()->send_error(p_func, p_file, p_line, p_err, p_descr, p_type); + EngineDebugger::get_singleton()->send_error(p_func, p_file, p_line, p_err, p_descr, p_editor_notify, p_type); error_stack_info.resize(0); } diff --git a/core/debugger/script_debugger.h b/core/debugger/script_debugger.h index 9f034a5e5d..c1d0170334 100644 --- a/core/debugger/script_debugger.h +++ b/core/debugger/script_debugger.h @@ -71,7 +71,7 @@ public: void debug(ScriptLanguage *p_lang, bool p_can_continue = true, bool p_is_error_breakpoint = false); ScriptLanguage *get_break_language() const; - 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<StackInfo> &p_stack_info); + void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, bool p_editor_notify, ErrorHandlerType p_type, const Vector<StackInfo> &p_stack_info); Vector<StackInfo> get_error_stack_info() const; ScriptDebugger() {} }; diff --git a/core/error/error_macros.cpp b/core/error/error_macros.cpp index 272dda97d8..719ea8afb5 100644 --- a/core/error/error_macros.cpp +++ b/core/error/error_macros.cpp @@ -65,45 +65,49 @@ void remove_error_handler(ErrorHandlerList *p_handler) { _global_unlock(); } -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); +// Errors without messages. +void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify, ErrorHandlerType p_type) { + _err_print_error(p_function, p_file, p_line, p_error, "", p_editor_notify, 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); +void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, bool p_editor_notify, ErrorHandlerType p_type) { + _err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), "", p_editor_notify, 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) { +// Main error printing function. +void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify, 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, p_message, p_type); + l->errfunc(l->userdata, p_function, p_file, p_line, p_error, p_message, p_editor_notify, p_type); l = l->next; } _global_unlock(); } -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); +// Errors with message. (All combinations of p_error and p_message as String or char*.) +void _err_print_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const char *p_message, bool p_editor_notify, ErrorHandlerType p_type) { + _err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message, p_editor_notify, p_type); } -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 char *p_error, const String &p_message, bool p_editor_notify, ErrorHandlerType p_type) { + _err_print_error(p_function, p_file, p_line, p_error, p_message.utf8().get_data(), p_editor_notify, 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_error(const char *p_function, const char *p_file, int p_line, const String &p_error, const String &p_message, bool p_editor_notify, ErrorHandlerType p_type) { + _err_print_error(p_function, p_file, p_line, p_error.utf8().get_data(), p_message.utf8().get_data(), p_editor_notify, 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: " : ""); +// Index errors. (All combinations of p_message as String or char*.) +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 p_editor_notify, bool p_fatal) { + String fstr(p_fatal ? "FATAL: " : ""); String err(fstr + "Index " + p_index_str + " = " + itos(p_index) + " is out of bounds (" + p_size_str + " = " + itos(p_size) + ")."); _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); +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 p_editor_notify, bool p_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(), p_fatal); } diff --git a/core/error/error_macros.h b/core/error/error_macros.h index 1bed8d366b..4eb862dce2 100644 --- a/core/error/error_macros.h +++ b/core/error/error_macros.h @@ -46,7 +46,7 @@ enum ErrorHandlerType { // Pointer to the error handler printing function. Reassign to any function to have errors printed. // Parameters: userdata, function, file, line, error, explanation, type. -typedef void (*ErrorHandlerFunc)(void *, const char *, const char *, int p_line, const char *, const char *, ErrorHandlerType p_type); +typedef void (*ErrorHandlerFunc)(void *, const char *, const char *, int p_line, const char *, const char *, bool p_editor_notify, ErrorHandlerType p_type); struct ErrorHandlerList { ErrorHandlerFunc errfunc = nullptr; @@ -61,14 +61,14 @@ void add_error_handler(ErrorHandlerList *p_handler); void remove_error_handler(ErrorHandlerList *p_handler); // Functions used by the error macros. -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_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); +void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, bool p_editor_notify = false, 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, bool p_editor_notify = false, 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, bool p_editor_notify = false, 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, bool p_editor_notify = false, 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, bool p_editor_notify = false, 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, bool p_editor_notify = false, 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 p_editor_notify = false, 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 p_editor_notify = false, bool fatal = false); #ifdef __GNUC__ //#define FUNCTION_STR __PRETTY_FUNCTION__ - too annoying @@ -136,6 +136,17 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. + * If not, prints `m_msg`, notifies in the editor, and the current function returns. + */ +#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \ + 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); \ + return; \ + } else \ + ((void)0) + +/** * Try using `ERR_FAIL_INDEX_V_MSG`. * Only use this macro if there is no sensible error message. * @@ -161,6 +172,17 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0. + * If not, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`. + */ +#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \ + 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); \ + return m_retval; \ + } else \ + ((void)0) + +/** * Try using `ERR_FAIL_INDEX_MSG` or `ERR_FAIL_INDEX_V_MSG`. * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and * there is no sensible error message. @@ -215,6 +237,16 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li return; \ } else \ ((void)0) +/** + * Ensures an unsigned integer index `m_index` is less than `m_size`. + * If not, prints `m_msg`, notifies in the editor, and the current function returns. + */ +#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \ + if (unlikely((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); \ + return; \ + } else \ + ((void)0) /** * Try using `ERR_FAIL_UNSIGNED_INDEX_V_MSG`. @@ -242,6 +274,17 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Ensures an unsigned integer index `m_index` is less than `m_size`. + * If not, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`. + */ +#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \ + if (unlikely((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); \ + return m_retval; \ + } else \ + ((void)0) + +/** * Try using `ERR_FAIL_UNSIGNED_INDEX_MSG` or `ERR_FAIL_UNSIGNED_INDEX_V_MSG`. * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and * there is no sensible error message. @@ -298,6 +341,17 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Ensures a pointer `m_param` is not null. + * If it is null, prints `m_msg`, notifies in the editor, and the current function returns. + */ +#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \ + if (unlikely(m_param == nullptr)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \ + return; \ + } else \ + ((void)0) + +/** * Try using `ERR_FAIL_NULL_V_MSG`. * Only use this macro if there is no sensible error message. * @@ -323,6 +377,17 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Ensures a pointer `m_param` is not null. + * If it is null, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`. + */ +#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \ + if (unlikely(m_param == nullptr)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Parameter \"" _STR(m_param) "\" is null.", m_msg, true); \ + return m_retval; \ + } else \ + ((void)0) + +/** * Try using `ERR_FAIL_COND_MSG`. * Only use this macro if there is no sensible error message. * If checking for null use ERR_FAIL_NULL_MSG instead. @@ -353,6 +418,20 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Ensures `m_cond` is false. + * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current function returns. + * + * If checking for null use ERR_FAIL_NULL_MSG instead. + * If checking index bounds use ERR_FAIL_INDEX_MSG instead. + */ +#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true.", m_msg, true); \ + return; \ + } else \ + ((void)0) + +/** * Try using `ERR_FAIL_COND_V_MSG`. * Only use this macro if there is no sensible error message. * If checking for null use ERR_FAIL_NULL_V_MSG instead. @@ -383,6 +462,20 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Ensures `m_cond` is false. + * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`. + * + * If checking for null use ERR_FAIL_NULL_V_MSG instead. + * If checking index bounds use ERR_FAIL_INDEX_V_MSG instead. + */ +#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Returning: " _STR(m_retval), m_msg, true); \ + return m_retval; \ + } else \ + ((void)0) + +/** * Try using `ERR_CONTINUE_MSG`. * Only use this macro if there is no sensible error message. * @@ -408,6 +501,17 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Ensures `m_cond` is false. + * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current loop continues. + */ +#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Continuing.", m_msg, true); \ + continue; \ + } else \ + ((void)0) + +/** * Try using `ERR_BREAK_MSG`. * Only use this macro if there is no sensible error message. * @@ -433,6 +537,17 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Ensures `m_cond` is false. + * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current loop breaks. + */ +#define ERR_BREAK_EDMSG(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition \"" _STR(m_cond) "\" is true. Breaking.", m_msg, true); \ + break; \ + } else \ + ((void)0) + +/** * Try using `ERR_FAIL_COND_MSG` or `ERR_FAIL_COND_V_MSG`. * Only use this macro if there is no sensible fallback i.e. the error is unrecoverable, and * there is no sensible error message. @@ -491,6 +606,19 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Try using `ERR_FAIL_COND_MSG`. + * Only use this macro if more complex error detection or recovery is required. + * + * Prints `m_msg`, notifies in the editor, and the current function returns. + */ +#define ERR_FAIL_EDMSG(m_msg) \ + if (true) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed.", m_msg, true); \ + return; \ + } else \ + ((void)0) + +/** * Try using `ERR_FAIL_COND_V_MSG` or `ERR_FAIL_V_MSG`. * Only use this macro if more complex error detection or recovery is required, and * there is no sensible error message. @@ -518,6 +646,19 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li ((void)0) /** + * Try using `ERR_FAIL_COND_V_MSG`. + * Only use this macro if more complex error detection or recovery is required. + * + * Prints `m_msg`, notifies in the editor, and the current function returns `m_retval`. + */ +#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \ + if (true) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Method/function failed. Returning: " _STR(m_retval), m_msg, true); \ + return m_retval; \ + } else \ + ((void)0) + +/** * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or ERR_BREAK_MSG. * Only use this macro at the start of a function that has not been implemented yet, or * if more complex error detection or recovery is required. @@ -528,6 +669,16 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg) /** + * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or ERR_BREAK_MSG. + * Only use this macro at the start of a function that has not been implemented yet, or + * if more complex error detection or recovery is required. + * + * Prints `m_msg` and notifies the editor. + */ +#define ERR_PRINT_ED(m_msg) \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, ) + +/** * Prints `m_msg` once during the application lifetime. */ #define ERR_PRINT_ONCE(m_msg) \ @@ -540,6 +691,19 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li } else \ ((void)0) +/** + * Prints `m_msg` and notifies the editor once during the application lifetime. + */ +#define ERR_PRINT_ONCE_ED(m_msg) \ + if (true) { \ + static bool first_print = true; \ + if (first_print) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true); \ + first_print = false; \ + } \ + } else \ + ((void)0) + // Print warning message macros. /** @@ -548,52 +712,75 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead. */ #define WARN_PRINT(m_msg) \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, ERR_HANDLER_WARNING) + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING) + +/** + * Prints `m_msg` and notifies the editor. + * + * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead. + */ +#define WARN_PRINT_ED(m_msg) \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING) /** * Prints `m_msg` once during the application lifetime. * * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead. */ -#define WARN_PRINT_ONCE(m_msg) \ - if (true) { \ - static bool first_print = true; \ - if (first_print) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, ERR_HANDLER_WARNING); \ - first_print = false; \ - } \ - } else \ +#define WARN_PRINT_ONCE(m_msg) \ + if (true) { \ + static bool first_print = true; \ + if (first_print) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING); \ + first_print = false; \ + } \ + } else \ ((void)0) -// Print deprecated warning message macros. - /** - * Warns that the current function is deprecated. + * Prints `m_msg` and notifies the editor once during the application lifetime. + * + * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead. */ -#define WARN_DEPRECATED \ - if (true) { \ - static SafeFlag warning_shown; \ - if (!warning_shown.is_set()) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", ERR_HANDLER_WARNING); \ - warning_shown.set(); \ - } \ - } else \ +#define WARN_PRINT_ONCE_ED(m_msg) \ + if (true) { \ + static bool first_print = true; \ + if (first_print) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING); \ + first_print = false; \ + } \ + } else \ ((void)0) +// Print deprecated warning message macros. + /** - * Warns that the current function is deprecated and prints `m_msg`. + * Warns that the current function is deprecated. */ -#define WARN_DEPRECATED_MSG(m_msg) \ +#define WARN_DEPRECATED \ if (true) { \ static SafeFlag warning_shown; \ if (!warning_shown.is_set()) { \ - _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, ERR_HANDLER_WARNING); \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", false, ERR_HANDLER_WARNING); \ warning_shown.set(); \ } \ } else \ ((void)0) /** + * Warns that the current function is deprecated and prints `m_msg`. + */ +#define WARN_DEPRECATED_MSG(m_msg) \ + if (true) { \ + static SafeFlag warning_shown; \ + if (!warning_shown.is_set()) { \ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", m_msg, false, ERR_HANDLER_WARNING); \ + warning_shown.set(); \ + } \ + } else \ + ((void)0) + +/** * Do not use. * If the application should never reach this point use CRASH_NOW_MSG(m_msg) to explain why. * diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp index ff09b0b86c..4770c9c65f 100644 --- a/core/extension/gdnative_interface.cpp +++ b/core/extension/gdnative_interface.cpp @@ -51,13 +51,13 @@ static void gdnative_free(void *p_mem) { // Helper print functions. static void gdnative_print_error(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) { - _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_ERROR); + _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_ERROR); } static void gdnative_print_warning(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) { - _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_WARNING); + _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_WARNING); } static void gdnative_print_script_error(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) { - _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_SCRIPT); + _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_SCRIPT); } // Variant functions diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h index 73f78bde54..8f8cb5a3e0 100644 --- a/core/extension/gdnative_interface.h +++ b/core/extension/gdnative_interface.h @@ -182,11 +182,11 @@ typedef void *(*GDNativeInstanceBindingCreateCallback)(void *p_token, void *p_in typedef void (*GDNativeInstanceBindingFreeCallback)(void *p_token, void *p_instance, void *p_binding); typedef GDNativeBool (*GDNativeInstanceBindingReferenceCallback)(void *p_token, void *p_binding, GDNativeBool p_reference); -struct GDNativeInstanceBindingCallbacks { +typedef struct { GDNativeInstanceBindingCreateCallback create_callback; GDNativeInstanceBindingFreeCallback free_callback; GDNativeInstanceBindingReferenceCallback reference_callback; -}; +} GDNativeInstanceBindingCallbacks; /* EXTENSION CLASSES */ diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp index 635e53fa9c..a6b0a708c3 100644 --- a/core/extension/native_extension.cpp +++ b/core/extension/native_extension.cpp @@ -35,7 +35,9 @@ #include "core/object/method_bind.h" #include "core/os/os.h" -const char *NativeExtension::EXTENSION_LIST_CONFIG_FILE = "res://.godot/extension_list.cfg"; +String NativeExtension::get_extension_list_config_file() { + return ProjectSettings::get_singleton()->get_project_data_path().plus_file("extension_list.cfg"); +} class NativeExtensionMethodBind : public MethodBind { GDNativeExtensionClassMethodCall call_func; diff --git a/core/extension/native_extension.h b/core/extension/native_extension.h index 52e869ad4d..f7f235d8fc 100644 --- a/core/extension/native_extension.h +++ b/core/extension/native_extension.h @@ -62,7 +62,7 @@ protected: static void _bind_methods(); public: - static const char *EXTENSION_LIST_CONFIG_FILE; + static String get_extension_list_config_file(); Error open_library(const String &p_path, const String &p_entry_symbol); void close_library(); diff --git a/core/extension/native_extension_manager.cpp b/core/extension/native_extension_manager.cpp index 4eac5249c9..c8755250d5 100644 --- a/core/extension/native_extension_manager.cpp +++ b/core/extension/native_extension_manager.cpp @@ -112,7 +112,7 @@ void NativeExtensionManager::deinitialize_extensions(NativeExtension::Initializa } void NativeExtensionManager::load_extensions() { - FileAccessRef f = FileAccess::open(NativeExtension::EXTENSION_LIST_CONFIG_FILE, FileAccess::READ); + FileAccessRef f = FileAccess::open(NativeExtension::get_extension_list_config_file(), FileAccess::READ); while (f && !f->eof_reached()) { String s = f->get_line().strip_edges(); if (s != String()) { diff --git a/core/input/SCsub b/core/input/SCsub index 740398b266..b12bf561de 100644 --- a/core/input/SCsub +++ b/core/input/SCsub @@ -7,19 +7,15 @@ import input_builders # Order matters here. Higher index controller database files write on top of lower index database files. controller_databases = [ - "#core/input/gamecontrollerdb.txt", - "#core/input/godotcontrollerdb.txt", + "gamecontrollerdb.txt", + "godotcontrollerdb.txt", ] -env.Depends("#core/input/default_controller_mappings.gen.cpp", controller_databases) -env.CommandNoCache( - "#core/input/default_controller_mappings.gen.cpp", +gensource = env.CommandNoCache( + "default_controller_mappings.gen.cpp", controller_databases, env.Run(input_builders.make_default_controller_mappings, "Generating default controller mappings."), ) env.add_source_files(env.core_sources, "*.cpp") - -# Don't warn about duplicate entry here, we need it registered manually for first build, -# even if later builds will pick it up twice due to above *.cpp globbing. -env.add_source_files(env.core_sources, "#core/input/default_controller_mappings.gen.cpp", warn_duplicates=False) +env.add_source_files(env.core_sources, gensource) diff --git a/core/input/input.cpp b/core/input/input.cpp index f9a361c761..296aa1f071 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -117,6 +117,10 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("get_accelerometer"), &Input::get_accelerometer); ClassDB::bind_method(D_METHOD("get_magnetometer"), &Input::get_magnetometer); ClassDB::bind_method(D_METHOD("get_gyroscope"), &Input::get_gyroscope); + ClassDB::bind_method(D_METHOD("set_gravity", "value"), &Input::set_gravity); + ClassDB::bind_method(D_METHOD("set_accelerometer", "value"), &Input::set_accelerometer); + ClassDB::bind_method(D_METHOD("set_magnetometer", "value"), &Input::set_magnetometer); + ClassDB::bind_method(D_METHOD("set_gyroscope", "value"), &Input::set_gyroscope); ClassDB::bind_method(D_METHOD("get_last_mouse_speed"), &Input::get_last_mouse_speed); ClassDB::bind_method(D_METHOD("get_mouse_button_mask"), &Input::get_mouse_button_mask); ClassDB::bind_method(D_METHOD("set_mouse_mode", "mode"), &Input::set_mouse_mode); diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 1d2b5f19ee..c6448b1e44 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -452,8 +452,13 @@ bool InputEventKey::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) return false; } - return keycode == key->keycode && - (!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask()); + if (keycode == 0) { + return physical_keycode == key->physical_keycode && + (!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask()); + } else { + return keycode == key->keycode && + (!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask()); + } } void InputEventKey::_bind_methods() { diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index e54c947340..df631053b8 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -233,7 +233,7 @@ uint64_t FileAccessCompressed::get_position() const { if (writing) { return write_pos; } else { - return read_block * block_size + read_pos; + return (uint64_t)read_block * block_size + read_pos; } } diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index b5c882e9ce..53bf7456e6 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -99,7 +99,7 @@ static int godot_testerror(voidpf opaque, voidpf stream) { } static voidpf godot_alloc(voidpf opaque, uInt items, uInt size) { - return memalloc(items * size); + return memalloc((size_t)items * size); } static void godot_free(voidpf opaque, voidpf address) { diff --git a/core/io/logger.cpp b/core/io/logger.cpp index 09539f716c..b68a8b20a5 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -50,7 +50,7 @@ void Logger::set_flush_stdout_on_print(bool value) { _flush_stdout_on_print = value; } -void Logger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { +void Logger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) { if (!should_log(true)) { return; } @@ -81,7 +81,11 @@ void Logger::log_error(const char *p_function, const char *p_file, int p_line, c err_details = p_code; } - logf_error("%s: %s\n", err_type, err_details); + if (p_editor_notify) { + logf_error("%s: %s\n", err_type, err_details); + } else { + logf_error("USER %s: %s\n", err_type, err_details); + } logf_error(" at: %s (%s:%i) - %s\n", p_function, p_file, p_line, p_code); } @@ -256,7 +260,7 @@ void CompositeLogger::logv(const char *p_format, va_list p_list, bool p_err) { } } -void CompositeLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { +void CompositeLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) { if (!should_log(true)) { return; } diff --git a/core/io/logger.h b/core/io/logger.h index ccf68562d6..f244f70e7e 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -54,7 +54,7 @@ public: static void set_flush_stdout_on_print(bool value); virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0; - virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, ErrorType p_type = ERR_ERROR); void logf(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; void logf_error(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; @@ -103,7 +103,7 @@ public: CompositeLogger(Vector<Logger *> p_loggers); virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0; - virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type = ERR_ERROR); void add_logger(Logger *p_logger); diff --git a/core/io/resource.cpp b/core/io/resource.cpp index 1cefa52d69..972076e397 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -136,6 +136,7 @@ String Resource::get_scene_unique_id() const { void Resource::set_name(const String &p_name) { name = p_name; + emit_changed(); } String Resource::get_name() const { diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp index 1e166015b0..cd44c537a8 100644 --- a/core/io/resource_importer.cpp +++ b/core/io/resource_importer.cpp @@ -418,7 +418,7 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_extension(const St } String ResourceFormatImporter::get_import_base_path(const String &p_for_file) const { - return ProjectSettings::IMPORTED_FILES_PATH.plus_file(p_for_file.get_file() + "-" + p_for_file.md5_text()); + return ProjectSettings::get_singleton()->get_imported_files_path().plus_file(p_for_file.get_file() + "-" + p_for_file.md5_text()); } bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) const { diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp index 290a71043c..b7d01712ff 100644 --- a/core/io/resource_uid.cpp +++ b/core/io/resource_uid.cpp @@ -29,6 +29,8 @@ /*************************************************************************/ #include "resource_uid.h" + +#include "core/config/project_settings.h" #include "core/crypto/crypto.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" @@ -36,7 +38,9 @@ static constexpr uint32_t char_count = ('z' - 'a'); static constexpr uint32_t base = char_count + ('9' - '0'); -const char *ResourceUID::CACHE_FILE = "res://.godot/uid_cache.bin"; +String ResourceUID::get_cache_file() { + return ProjectSettings::get_singleton()->get_project_data_path().plus_file("uid_cache.bin"); +} String ResourceUID::id_to_text(ID p_id) const { if (p_id < 0) { @@ -135,12 +139,13 @@ void ResourceUID::remove_id(ID p_id) { } Error ResourceUID::save_to_cache() { - if (!FileAccess::exists(CACHE_FILE)) { + String cache_file = get_cache_file(); + if (!FileAccess::exists(cache_file)) { DirAccessRef d = DirAccess::create(DirAccess::ACCESS_RESOURCES); - d->make_dir_recursive(String(CACHE_FILE).get_base_dir()); //ensure base dir exists + d->make_dir_recursive(String(cache_file).get_base_dir()); //ensure base dir exists } - FileAccessRef f = FileAccess::open(CACHE_FILE, FileAccess::WRITE); + FileAccessRef f = FileAccess::open(cache_file, FileAccess::WRITE); if (!f) { return ERR_CANT_OPEN; } @@ -164,7 +169,7 @@ Error ResourceUID::save_to_cache() { } Error ResourceUID::load_from_cache() { - FileAccessRef f = FileAccess::open(CACHE_FILE, FileAccess::READ); + FileAccessRef f = FileAccess::open(get_cache_file(), FileAccess::READ); if (!f) { return ERR_CANT_OPEN; } @@ -206,7 +211,7 @@ Error ResourceUID::update_cache() { for (OrderedHashMap<ID, Cache>::Element E = unique_ids.front(); E; E = E.next()) { if (!E.get().saved_to_cache) { if (f == nullptr) { - f = FileAccess::open(CACHE_FILE, FileAccess::READ_WRITE); //append + f = FileAccess::open(get_cache_file(), FileAccess::READ_WRITE); //append if (!f) { return ERR_CANT_OPEN; } diff --git a/core/io/resource_uid.h b/core/io/resource_uid.h index b12138425a..2f1bfdf243 100644 --- a/core/io/resource_uid.h +++ b/core/io/resource_uid.h @@ -44,7 +44,7 @@ public: INVALID_ID = -1 }; - static const char *CACHE_FILE; + static String get_cache_file(); private: mutable Ref<Crypto> crypto; diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp index fb4c76aa7a..24808cc8d6 100644 --- a/core/io/zip_io.cpp +++ b/core/io/zip_io.cpp @@ -100,7 +100,7 @@ int zipio_testerror(voidpf opaque, voidpf stream) { } voidpf zipio_alloc(voidpf opaque, uInt items, uInt size) { - voidpf ptr = memalloc(items * size); + voidpf ptr = memalloc((size_t)items * size); memset(ptr, 0, items * size); return ptr; } diff --git a/core/math/bvh.h b/core/math/bvh.h index cefbc9b0db..65b8b102a3 100644 --- a/core/math/bvh.h +++ b/core/math/bvh.h @@ -200,7 +200,7 @@ public: // use in conjunction with activate if you have deferred the collision check, and // set pairable has never been called. - // (deferred collision checks are a workaround for visual server for historical reasons) + // (deferred collision checks are a workaround for rendering server for historical reasons) void force_collision_check(BVHHandle p_handle) { if (USE_PAIRS) { // the aabb should already be up to date in the BVH diff --git a/core/math/face3.cpp b/core/math/face3.cpp index 045ab67ce8..31a853e1a9 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -229,7 +229,7 @@ bool Face3::intersects_aabb(const AABB &p_aabb) const { axis.normalize(); real_t minA, maxA, minB, maxB; - p_aabb.project_range_in_plane(Plane(axis, 0), minA, maxA); + p_aabb.project_range_in_plane(Plane(axis), minA, maxA); project_range(axis, Transform3D(), minB, maxB); if (maxA < minB || maxB < minA) { diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp index 6628b760e0..88d2656025 100644 --- a/core/math/geometry_3d.cpp +++ b/core/math/geometry_3d.cpp @@ -819,11 +819,9 @@ Vector<Plane> Geometry3D::build_sphere_planes(real_t p_radius, int p_lats, int p planes.push_back(Plane(normal, p_radius)); for (int j = 1; j <= p_lats; j++) { - // FIXME: This is stupid. - Vector3 angle = normal.lerp(axis, j / (real_t)p_lats).normalized(); - Vector3 pos = angle * p_radius; - planes.push_back(Plane(pos, angle)); - planes.push_back(Plane(pos * axis_neg, angle * axis_neg)); + Vector3 plane_normal = normal.lerp(axis, j / (real_t)p_lats).normalized(); + planes.push_back(Plane(plane_normal, p_radius)); + planes.push_back(Plane(plane_normal * axis_neg, p_radius)); } } @@ -852,10 +850,10 @@ Vector<Plane> Geometry3D::build_capsule_planes(real_t p_radius, real_t p_height, planes.push_back(Plane(normal, p_radius)); for (int j = 1; j <= p_lats; j++) { - Vector3 angle = normal.lerp(axis, j / (real_t)p_lats).normalized(); - Vector3 pos = axis * p_height * 0.5 + angle * p_radius; - planes.push_back(Plane(pos, angle)); - planes.push_back(Plane(pos * axis_neg, angle * axis_neg)); + Vector3 plane_normal = normal.lerp(axis, j / (real_t)p_lats).normalized(); + Vector3 position = axis * p_height * 0.5 + plane_normal * p_radius; + planes.push_back(Plane(plane_normal, position)); + planes.push_back(Plane(plane_normal * axis_neg, position * axis_neg)); } } diff --git a/core/math/plane.h b/core/math/plane.h index 2267b28c53..18be5d5d12 100644 --- a/core/math/plane.h +++ b/core/math/plane.h @@ -85,8 +85,8 @@ public: normal(p_a, p_b, p_c), d(p_d) {} - _FORCE_INLINE_ Plane(const Vector3 &p_normal, real_t p_d); - _FORCE_INLINE_ Plane(const Vector3 &p_point, const Vector3 &p_normal); + _FORCE_INLINE_ Plane(const Vector3 &p_normal, real_t p_d = 0.0); + _FORCE_INLINE_ Plane(const Vector3 &p_normal, const Vector3 &p_point); _FORCE_INLINE_ Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir = CLOCKWISE); }; @@ -109,7 +109,7 @@ Plane::Plane(const Vector3 &p_normal, real_t p_d) : d(p_d) { } -Plane::Plane(const Vector3 &p_point, const Vector3 &p_normal) : +Plane::Plane(const Vector3 &p_normal, const Vector3 &p_point) : normal(p_normal), d(p_normal.dot(p_point)) { } diff --git a/core/multiplayer/multiplayer.h b/core/multiplayer/multiplayer.h index 31b7bf0043..be398f02c8 100644 --- a/core/multiplayer/multiplayer.h +++ b/core/multiplayer/multiplayer.h @@ -52,7 +52,7 @@ enum RPCMode { struct RPCConfig { StringName name; RPCMode rpc_mode = RPC_MODE_DISABLED; - bool sync = false; + bool call_local = false; TransferMode transfer_mode = TRANSFER_MODE_RELIABLE; int channel = 0; diff --git a/core/multiplayer/multiplayer_replicator.cpp b/core/multiplayer/multiplayer_replicator.cpp index a4ea74327c..6604510394 100644 --- a/core/multiplayer/multiplayer_replicator.cpp +++ b/core/multiplayer/multiplayer_replicator.cpp @@ -572,7 +572,7 @@ Error MultiplayerReplicator::_spawn_despawn(ResourceUID::ID p_scene_id, Object * args[0] = p_peer; args[1] = p_scene_id; args[2] = p_obj; - args[3] = true; + args[3] = p_spawn; const Variant *argp[] = { &args[0], &args[1], &args[2], &args[3] }; Callable::CallError ce; Variant ret; diff --git a/core/multiplayer/rpc_manager.cpp b/core/multiplayer/rpc_manager.cpp index 20ab7a25bb..d8e875c3e6 100644 --- a/core/multiplayer/rpc_manager.cpp +++ b/core/multiplayer/rpc_manager.cpp @@ -476,9 +476,9 @@ void RPCManager::rpcp(Node *p_node, int p_peer_id, const StringName &p_method, c vformat("Unable to get the RPC configuration for the function \"%s\" at path: \"%s\". This happens when the method is not marked for RPCs.", p_method, p_node->get_path())); if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { if (rpc_id & (1 << 15)) { - call_local_native = config.sync; + call_local_native = config.call_local; } else { - call_local_script = config.sync; + call_local_script = config.call_local; } } @@ -521,5 +521,5 @@ void RPCManager::rpcp(Node *p_node, int p_peer_id, const StringName &p_method, c } } - ERR_FAIL_COND_MSG(p_peer_id == node_id && !config.sync, "RPC '" + p_method + "' on yourself is not allowed by selected mode."); + ERR_FAIL_COND_MSG(p_peer_id == node_id && !config.call_local, "RPC '" + p_method + "' on yourself is not allowed by selected mode."); } diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index d5509c50f1..4b3c8b123f 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -37,8 +37,6 @@ #define OBJTYPE_RLOCK RWLockRead _rw_lockr_(lock); #define OBJTYPE_WLOCK RWLockWrite _rw_lockw_(lock); -#ifdef DEBUG_METHODS_ENABLED - MethodDefinition D_METHOD(const char *p_name) { MethodDefinition md; md.name = StaticCString::create(p_name); @@ -226,8 +224,6 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ return md; } -#endif - ClassDB::APIType ClassDB::current_api = API_CORE; void ClassDB::set_current_api(APIType p_api) { @@ -589,7 +585,6 @@ void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherit } } -#ifdef DEBUG_METHODS_ENABLED static MethodInfo info_from_bind(MethodBind *p_method) { MethodInfo minfo; minfo.name = p_method->get_name(); @@ -610,7 +605,6 @@ static MethodInfo info_from_bind(MethodBind *p_method) { return minfo; } -#endif void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) { OBJTYPE_RLOCK; @@ -650,9 +644,8 @@ void ClassDB::get_method_list(const StringName &p_class, List<MethodInfo> *p_met while ((K = type->method_map.next(K))) { MethodBind *m = type->method_map[*K]; - MethodInfo mi; - mi.name = m->get_name(); - p_methods->push_back(mi); + MethodInfo minfo = info_from_bind(m); + p_methods->push_back(minfo); } #endif @@ -698,9 +691,8 @@ bool ClassDB::get_method_info(const StringName &p_class, const StringName &p_met if (type->method_map.has(p_method)) { if (r_info) { MethodBind *m = type->method_map[p_method]; - MethodInfo mi; - mi.name = m->get_name(); - *r_info = mi; + MethodInfo minfo = info_from_bind(m); + *r_info = minfo; } return true; } @@ -1411,13 +1403,8 @@ void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method type->method_map[p_method->get_name()] = p_method; } -#ifdef DEBUG_METHODS_ENABLED MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) { StringName mdname = method_name.name; -#else -MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const char *method_name, const Variant **p_defs, int p_defcount) { - StringName mdname = StaticCString::create(method_name); -#endif OBJTYPE_WLOCK; ERR_FAIL_COND_V(!p_bind, nullptr); diff --git a/core/object/class_db.h b/core/object/class_db.h index 3a1cbf8559..d9eec4e4a8 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -45,8 +45,6 @@ #define DEFVAL(m_defval) (m_defval) -#ifdef DEBUG_METHODS_ENABLED - struct MethodDefinition { StringName name; Vector<StringName> args; @@ -72,26 +70,6 @@ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_ MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12); MethodDefinition D_METHOD(const char *p_name, const char *p_arg1, const char *p_arg2, const char *p_arg3, const char *p_arg4, const char *p_arg5, const char *p_arg6, const char *p_arg7, const char *p_arg8, const char *p_arg9, const char *p_arg10, const char *p_arg11, const char *p_arg12, const char *p_arg13); -#else - -//#define NO_VARIADIC_MACROS - -#ifdef NO_VARIADIC_MACROS - -static _FORCE_INLINE_ const char *D_METHOD(const char *m_name, ...) { - return m_name; -} - -#else - -// When DEBUG_METHODS_ENABLED is set this will let the engine know -// the argument names for easier debugging. -#define D_METHOD(m_c, ...) m_c - -#endif - -#endif - class ClassDB { public: enum APIType { @@ -156,11 +134,7 @@ public: static HashMap<StringName, StringName> resource_base_extensions; static HashMap<StringName, StringName> compat_classes; -#ifdef DEBUG_METHODS_ENABLED static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount); -#else - static MethodBind *bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const char *method_name, const Variant **p_defs, int p_defcount); -#endif static APIType current_api; @@ -190,6 +164,7 @@ public: t->creation_func = &creator<T>; t->exposed = true; t->class_ptr = T::get_class_ptr_static(); + t->api = current_api; T::register_custom_data_to_otdb(); } @@ -201,6 +176,7 @@ public: ERR_FAIL_COND(!t); t->exposed = true; t->class_ptr = T::get_class_ptr_static(); + t->api = current_api; //nothing } @@ -221,6 +197,7 @@ public: t->creation_func = &_create_ptr_func<T>; t->exposed = true; t->class_ptr = T::get_class_ptr_static(); + t->api = current_api; T::register_custom_data_to_otdb(); } diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp index c53104fe3f..642e27c41d 100644 --- a/core/object/method_bind.cpp +++ b/core/object/method_bind.cpp @@ -63,12 +63,15 @@ uint32_t MethodBind::get_hash() const { return hash; } -#ifdef DEBUG_METHODS_ENABLED PropertyInfo MethodBind::get_argument_info(int p_argument) const { ERR_FAIL_INDEX_V(p_argument, get_argument_count(), PropertyInfo()); PropertyInfo info = _gen_argument_type_info(p_argument); +#ifdef DEBUG_METHODS_ENABLED info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("arg" + itos(p_argument)); +#else + info.name = String("arg" + itos(p_argument)); +#endif return info; } @@ -76,7 +79,6 @@ PropertyInfo MethodBind::get_return_info() const { return _gen_argument_type_info(-1); } -#endif void MethodBind::_set_const(bool p_const) { _const = p_const; } @@ -109,7 +111,6 @@ void MethodBind::set_default_arguments(const Vector<Variant> &p_defargs) { default_argument_count = default_arguments.size(); } -#ifdef DEBUG_METHODS_ENABLED void MethodBind::_generate_argument_types(int p_count) { set_argument_count(p_count); @@ -123,17 +124,13 @@ void MethodBind::_generate_argument_types(int p_count) { argument_types = argt; } -#endif - MethodBind::MethodBind() { static int last_id = 0; method_id = last_id++; } MethodBind::~MethodBind() { -#ifdef DEBUG_METHODS_ENABLED if (argument_types) { memdelete_arr(argument_types); } -#endif } diff --git a/core/object/method_bind.h b/core/object/method_bind.h index b0b379873e..ee003099a0 100644 --- a/core/object/method_bind.h +++ b/core/object/method_bind.h @@ -64,18 +64,16 @@ class MethodBind { bool _returns = false; protected: -#ifdef DEBUG_METHODS_ENABLED Variant::Type *argument_types = nullptr; +#ifdef DEBUG_METHODS_ENABLED Vector<StringName> arg_names; #endif void _set_const(bool p_const); void _set_returns(bool p_returns); -#ifdef DEBUG_METHODS_ENABLED virtual Variant::Type _gen_argument_type(int p_arg) const = 0; virtual PropertyInfo _gen_argument_type_info(int p_arg) const = 0; void _generate_argument_types(int p_count); -#endif void set_argument_count(int p_count) { argument_count = p_count; } public: @@ -102,7 +100,6 @@ public: } } -#ifdef DEBUG_METHODS_ENABLED _FORCE_INLINE_ Variant::Type get_argument_type(int p_argument) const { ERR_FAIL_COND_V(p_argument < -1 || p_argument > argument_count, Variant::NIL); return argument_types[p_argument + 1]; @@ -111,6 +108,7 @@ public: PropertyInfo get_argument_info(int p_argument) const; PropertyInfo get_return_info() const; +#ifdef DEBUG_METHODS_ENABLED void set_argument_names(const Vector<StringName> &p_names); // Set by ClassDB, can't be inferred otherwise. Vector<StringName> get_argument_names() const; @@ -149,12 +147,9 @@ public: protected: NativeCall call_method = nullptr; -#ifdef DEBUG_METHODS_ENABLED MethodInfo arguments; -#endif public: -#ifdef DEBUG_METHODS_ENABLED virtual PropertyInfo _gen_argument_type_info(int p_arg) const { if (p_arg < 0) { return arguments.return_val; @@ -169,13 +164,10 @@ public: return _gen_argument_type_info(p_arg).type; } +#ifdef DEBUG_METHODS_ENABLED virtual GodotTypeInfo::Metadata get_argument_meta(int) const { return GodotTypeInfo::METADATA_NONE; } -#else - virtual Variant::Type _gen_argument_type(int p_arg) const { - return Variant::NIL; - } #endif virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { @@ -185,25 +177,29 @@ public: void set_method_info(const MethodInfo &p_info, bool p_return_nil_is_variant) { set_argument_count(p_info.arguments.size()); -#ifdef DEBUG_METHODS_ENABLED Variant::Type *at = memnew_arr(Variant::Type, p_info.arguments.size() + 1); at[0] = p_info.return_val.type; if (p_info.arguments.size()) { +#ifdef DEBUG_METHODS_ENABLED Vector<StringName> names; names.resize(p_info.arguments.size()); +#endif for (int i = 0; i < p_info.arguments.size(); i++) { at[i + 1] = p_info.arguments[i].type; +#ifdef DEBUG_METHODS_ENABLED names.write[i] = p_info.arguments[i].name; +#endif } +#ifdef DEBUG_METHODS_ENABLED set_argument_names(names); +#endif } argument_types = at; arguments = p_info; if (p_return_nil_is_variant) { arguments.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; } -#endif } virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) { @@ -248,7 +244,6 @@ class MethodBindT : public MethodBind { void (MB_T::*method)(P...); protected: -#ifdef DEBUG_METHODS_ENABLED // GCC raises warnings in the case P = {} as the comparison is always false... #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push @@ -270,7 +265,6 @@ protected: call_get_argument_type_info<P...>(p_arg, pi); return pi; } -#endif public: #ifdef DEBUG_METHODS_ENABLED @@ -298,9 +292,7 @@ public: MethodBindT(void (MB_T::*p_method)(P...)) { method = p_method; -#ifdef DEBUG_METHODS_ENABLED _generate_argument_types(sizeof...(P)); -#endif set_argument_count(sizeof...(P)); } }; @@ -327,7 +319,6 @@ class MethodBindTC : public MethodBind { void (MB_T::*method)(P...) const; protected: -#ifdef DEBUG_METHODS_ENABLED // GCC raises warnings in the case P = {} as the comparison is always false... #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push @@ -349,7 +340,6 @@ protected: call_get_argument_type_info<P...>(p_arg, pi); return pi; } -#endif public: #ifdef DEBUG_METHODS_ENABLED @@ -378,9 +368,7 @@ public: MethodBindTC(void (MB_T::*p_method)(P...) const) { method = p_method; _set_const(true); -#ifdef DEBUG_METHODS_ENABLED _generate_argument_types(sizeof...(P)); -#endif set_argument_count(sizeof...(P)); } }; @@ -408,7 +396,6 @@ class MethodBindTR : public MethodBind { (P...); protected: -#ifdef DEBUG_METHODS_ENABLED // GCC raises warnings in the case P = {} as the comparison is always false... #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push @@ -434,7 +421,6 @@ protected: #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif -#endif public: #ifdef DEBUG_METHODS_ENABLED @@ -468,9 +454,7 @@ public: MethodBindTR(R (MB_T::*p_method)(P...)) { method = p_method; _set_returns(true); -#ifdef DEBUG_METHODS_ENABLED _generate_argument_types(sizeof...(P)); -#endif set_argument_count(sizeof...(P)); } }; @@ -499,7 +483,6 @@ class MethodBindTRC : public MethodBind { (P...) const; protected: -#ifdef DEBUG_METHODS_ENABLED // GCC raises warnings in the case P = {} as the comparison is always false... #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push @@ -525,7 +508,6 @@ protected: #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif -#endif public: #ifdef DEBUG_METHODS_ENABLED @@ -560,9 +542,7 @@ public: method = p_method; _set_returns(true); _set_const(true); -#ifdef DEBUG_METHODS_ENABLED _generate_argument_types(sizeof...(P)); -#endif set_argument_count(sizeof...(P)); } }; diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index b7d2bac96d..9c84c2add7 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -32,6 +32,7 @@ #include "core/io/resource.h" #include "core/os/os.h" +#include "core/templates/local_vector.h" void UndoRedo::_discard_redo() { if (current_action == actions.size() - 1) { @@ -85,10 +86,17 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { current_action = actions.size() - 2; if (p_mode == MERGE_ENDS) { - // Clear all do ops from last action, and delete all object references - List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front(); + // Clear all do ops from last action if they are not forced kept + LocalVector<List<Operation>::Element *> to_remove; + for (List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front(); E; E = E->next()) { + if (!E->get().force_keep_in_merge_ends) { + to_remove.push_back(E); + } + } - while (E) { + for (unsigned int i = 0; i < to_remove.size(); i++) { + List<Operation>::Element *E = to_remove[i]; + // Delete all object references if (E->get().type == Operation::TYPE_REFERENCE) { Object *obj = ObjectDB::get_instance(E->get().object); @@ -96,9 +104,7 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { memdelete(obj); } } - - E = E->next(); - actions.write[current_action + 1].do_ops.pop_front(); + E->erase(); } } @@ -117,6 +123,8 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { } action_level++; + + force_keep_in_merge_ends = false; } void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) { @@ -146,7 +154,7 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR ERR_FAIL_COND((current_action + 1) >= actions.size()); // No undo if the merge mode is MERGE_ENDS - if (merge_mode == MERGE_ENDS) { + if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) { return; } @@ -157,6 +165,7 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR } undo_op.type = Operation::TYPE_METHOD; + undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; undo_op.name = p_method; for (int i = 0; i < VARIANT_ARG_MAX; i++) { @@ -187,7 +196,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, ERR_FAIL_COND((current_action + 1) >= actions.size()); // No undo if the merge mode is MERGE_ENDS - if (merge_mode == MERGE_ENDS) { + if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) { return; } @@ -198,6 +207,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, } undo_op.type = Operation::TYPE_PROPERTY; + undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; undo_op.name = p_property; undo_op.args[0] = p_value; actions.write[current_action + 1].undo_ops.push_back(undo_op); @@ -223,7 +233,7 @@ void UndoRedo::add_undo_reference(Object *p_object) { ERR_FAIL_COND((current_action + 1) >= actions.size()); // No undo if the merge mode is MERGE_ENDS - if (merge_mode == MERGE_ENDS) { + if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) { return; } @@ -234,9 +244,24 @@ void UndoRedo::add_undo_reference(Object *p_object) { } undo_op.type = Operation::TYPE_REFERENCE; + undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; actions.write[current_action + 1].undo_ops.push_back(undo_op); } +void UndoRedo::start_force_keep_in_merge_ends() { + ERR_FAIL_COND(action_level <= 0); + ERR_FAIL_COND((current_action + 1) >= actions.size()); + + force_keep_in_merge_ends = true; +} + +void UndoRedo::end_force_keep_in_merge_ends() { + ERR_FAIL_COND(action_level <= 0); + ERR_FAIL_COND((current_action + 1) >= actions.size()); + + force_keep_in_merge_ends = false; +} + void UndoRedo::_pop_history_tail() { _discard_redo(); @@ -538,6 +563,9 @@ void UndoRedo::_bind_methods() { ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference); ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &UndoRedo::add_undo_reference); + ClassDB::bind_method(D_METHOD("start_force_keep_in_merge_ends"), &UndoRedo::start_force_keep_in_merge_ends); + ClassDB::bind_method(D_METHOD("end_force_keep_in_merge_ends"), &UndoRedo::end_force_keep_in_merge_ends); + ClassDB::bind_method(D_METHOD("get_history_count"), &UndoRedo::get_history_count); ClassDB::bind_method(D_METHOD("get_current_action"), &UndoRedo::get_current_action); ClassDB::bind_method(D_METHOD("get_action_name", "id"), &UndoRedo::get_action_name); diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index d1ce252d86..a757d154e2 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -61,6 +61,7 @@ private: }; Type type; + bool force_keep_in_merge_ends; Ref<RefCounted> ref; ObjectID object; StringName name; @@ -76,6 +77,7 @@ private: Vector<Action> actions; int current_action = -1; + bool force_keep_in_merge_ends = false; int action_level = 0; MergeMode merge_mode = MERGE_DISABLE; bool merging = false; @@ -109,6 +111,9 @@ public: void add_do_reference(Object *p_object); void add_undo_reference(Object *p_object); + void start_force_keep_in_merge_ends(); + void end_force_keep_in_merge_ends(); + bool is_committing_action() const; void commit_action(bool p_execute = true); diff --git a/core/os/os.cpp b/core/os/os.cpp index 12f85858c3..7404ffdcd5 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -75,12 +75,12 @@ void OS::add_logger(Logger *p_logger) { } } -void OS::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type) { +void OS::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, Logger::ErrorType p_type) { if (!_stderr_enabled) { return; } - _logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_type); + _logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_editor_notify, p_type); } void OS::print(const char *p_format, ...) { diff --git a/core/os/os.h b/core/os/os.h index 29d33ce4f0..6d7bc47407 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -110,7 +110,7 @@ public: static OS *get_singleton(); - void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type = Logger::ERR_ERROR); + void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, Logger::ErrorType p_type = Logger::ERR_ERROR); void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; diff --git a/core/string/optimized_translation.cpp b/core/string/optimized_translation.cpp index 839b7a9c01..f8be564740 100644 --- a/core/string/optimized_translation.cpp +++ b/core/string/optimized_translation.cpp @@ -64,7 +64,6 @@ void OptimizedTranslation::generate(const Ref<Translation> &p_from) { int idx = 0; int total_compression_size = 0; - int total_string_size = 0; for (const StringName &E : keys) { //hash string @@ -102,7 +101,6 @@ void OptimizedTranslation::generate(const Ref<Translation> &p_from) { compressed.write[idx] = ps; total_compression_size += ps.compressed.size(); - total_string_size += src_s.size(); idx++; } @@ -147,15 +145,12 @@ void OptimizedTranslation::generate(const Ref<Translation> &p_from) { uint32_t *btw = (uint32_t *)&btwb[0]; int btindex = 0; - int collisions = 0; for (int i = 0; i < size; i++) { const Map<uint32_t, int> &t = table[i]; if (t.size() == 0) { htw[i] = 0xFFFFFFFF; //nothing continue; - } else if (t.size() > 1) { - collisions += t.size() - 1; } htw[i] = btindex; diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h index 1257b54449..1634219c23 100644 --- a/core/templates/hash_map.h +++ b/core/templates/hash_map.h @@ -62,7 +62,9 @@ public: TKey key; TData data; - Pair() {} + Pair(const TKey &p_key) : + key(p_key), + data() {} Pair(const TKey &p_key, const TData &p_data) : key(p_key), data(p_data) { @@ -90,6 +92,12 @@ public: const TData &value() const { return pair.value(); } + + Element(const TKey &p_key) : + pair(p_key) {} + Element(const Element &p_other) : + hash(p_other.hash), + pair(p_other.pair.key, p_other.pair.data) {} }; private: @@ -192,14 +200,12 @@ private: Element *create_element(const TKey &p_key) { /* if element doesn't exist, create it */ - Element *e = memnew(Element); + Element *e = memnew(Element(p_key)); ERR_FAIL_COND_V_MSG(!e, nullptr, "Out of memory."); uint32_t hash = Hasher::hash(p_key); uint32_t index = hash & ((1 << hash_table_power) - 1); e->next = hash_table[index]; e->hash = hash; - e->pair.key = p_key; - e->pair.data = TData(); hash_table[index] = e; elements++; @@ -228,9 +234,7 @@ private: const Element *e = p_t.hash_table[i]; while (e) { - Element *le = memnew(Element); /* local element */ - - *le = *e; /* copy data */ + Element *le = memnew(Element(*e)); /* local element */ /* add to list and reassign pointers */ le->next = hash_table[i]; diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h index 2e932f9f26..c1a7c4146e 100644 --- a/core/templates/hashfuncs.h +++ b/core/templates/hashfuncs.h @@ -74,6 +74,13 @@ static inline uint32_t hash_djb2_one_32(uint32_t p_in, uint32_t p_prev = 5381) { return ((p_prev << 5) + p_prev) + p_in; } +/** + * Thomas Wang's 64-bit to 32-bit Hash function: + * https://web.archive.org/web/20071223173210/https:/www.concentric.net/~Ttwang/tech/inthash.htm + * + * @param p_int - 64-bit unsigned integer key to be hashed + * @return unsigned 32-bit value representing hashcode + */ static inline uint32_t hash_one_uint64(const uint64_t p_int) { uint64_t v = p_int; v = (~v) + (v << 18); // v = (v << 18) - v - 1; @@ -82,7 +89,7 @@ static inline uint32_t hash_one_uint64(const uint64_t p_int) { v = v ^ (v >> 11); v = v + (v << 6); v = v ^ (v >> 22); - return (int)v; + return uint32_t(v); } static inline uint32_t hash_djb2_one_float(double p_in, uint32_t p_prev = 5381) { diff --git a/core/typedefs.h b/core/typedefs.h index dde254af23..8ca3d13e63 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -62,9 +62,9 @@ #endif #endif -// Should always inline, except in debug builds because it makes debugging harder. +// Should always inline, except in dev builds because it makes debugging harder. #ifndef _FORCE_INLINE_ -#ifdef DISABLE_FORCED_INLINE +#ifdef DEV_ENABLED #define _FORCE_INLINE_ inline #else #define _FORCE_INLINE_ _ALWAYS_INLINE_ diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index 3b2c837096..8592a1dc62 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -563,13 +563,11 @@ void call_with_validated_variant_args_static_method_ret(R (*p_method)(P...), con // GCC raises "parameter 'p_args' set but not used" when P = {}, // it's not clever enough to treat other P values as making this branch valid. -#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__) +#if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-but-set-parameter" #endif -#ifdef DEBUG_METHODS_ENABLED - template <class Q> void call_get_argument_type_helper(int p_arg, int &index, Variant::Type &type) { if (p_arg == index) { @@ -608,6 +606,7 @@ void call_get_argument_type_info(int p_arg, PropertyInfo &info) { (void)index; // Suppress GCC warning. } +#ifdef DEBUG_METHODS_ENABLED template <class Q> void call_get_argument_metadata_helper(int p_arg, int &index, GodotTypeInfo::Metadata &md) { if (p_arg == index) { @@ -629,13 +628,6 @@ GodotTypeInfo::Metadata call_get_argument_metadata(int p_arg) { return md; } -#else - -template <class... P> -Variant::Type call_get_argument_type(int p_arg) { - return Variant::NIL; -} - #endif // DEBUG_METHODS_ENABLED ////////////////////// @@ -915,7 +907,7 @@ void call_with_variant_args_static_dv(void (*p_method)(P...), const Variant **p_ call_with_variant_args_static(p_method, args, r_error, BuildIndexSequence<sizeof...(P)>{}); } -#if defined(DEBUG_METHODS_ENABLED) && defined(__GNUC__) && !defined(__clang__) +#if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 0dbeb6e4cb..3214fc125d 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -1624,6 +1624,19 @@ Variant::operator String() const { return stringify(stack); } +template <class T> +String stringify_vector(const T &vec, List<const void *> &stack) { + String str("["); + for (int i = 0; i < vec.size(); i++) { + if (i > 0) { + str += ", "; + } + str = str + Variant(vec[i]).stringify(stack); + } + str += "]"; + return str; +} + String Variant::stringify(List<const void *> &stack) const { switch (type) { case NIL: @@ -1703,88 +1716,31 @@ String Variant::stringify(List<const void *> &stack) const { return str; } break; case PACKED_VECTOR2_ARRAY: { - Vector<Vector2> vec = operator Vector<Vector2>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + Variant(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<Vector2>(), stack); } break; case PACKED_VECTOR3_ARRAY: { - Vector<Vector3> vec = operator Vector<Vector3>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + Variant(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<Vector3>(), stack); + } break; + case PACKED_COLOR_ARRAY: { + return stringify_vector(operator Vector<Color>(), stack); } break; case PACKED_STRING_ARRAY: { - Vector<String> vec = operator Vector<String>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + vec[i]; - } - str += "]"; - return str; + return stringify_vector(operator Vector<String>(), stack); + } break; + case PACKED_BYTE_ARRAY: { + return stringify_vector(operator Vector<uint8_t>(), stack); } break; case PACKED_INT32_ARRAY: { - Vector<int32_t> vec = operator Vector<int32_t>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + itos(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<int32_t>(), stack); } break; case PACKED_INT64_ARRAY: { - Vector<int64_t> vec = operator Vector<int64_t>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + itos(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<int64_t>(), stack); } break; case PACKED_FLOAT32_ARRAY: { - Vector<float> vec = operator Vector<float>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + rtos(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<float>(), stack); } break; case PACKED_FLOAT64_ARRAY: { - Vector<double> vec = operator Vector<double>(); - String str("["); - for (int i = 0; i < vec.size(); i++) { - if (i > 0) { - str += ", "; - } - str = str + rtos(vec[i]); - } - str += "]"; - return str; + return stringify_vector(operator Vector<double>(), stack); } break; case ARRAY: { Array arr = operator Array(); @@ -1793,16 +1749,8 @@ String Variant::stringify(List<const void *> &stack) const { } stack.push_back(arr.id()); - String str("["); - for (int i = 0; i < arr.size(); i++) { - if (i) { - str += ", "; - } - - str += arr[i].stringify(stack); - } + String str = stringify_vector(arr, stack); - str += "]"; stack.erase(arr.id()); return str; @@ -3145,10 +3093,18 @@ bool Variant::hash_compare(const Variant &p_variant) const { } switch (type) { + case INT: { + return _data._int == p_variant._data._int; + } break; + case FLOAT: { return hash_compare_scalar(_data._float, p_variant._data._float); } break; + case STRING: { + return *reinterpret_cast<const String *>(_data._mem) == *reinterpret_cast<const String *>(p_variant._data._mem); + } break; + case VECTOR2: { const Vector2 *l = reinterpret_cast<const Vector2 *>(_data._mem); const Vector2 *r = reinterpret_cast<const Vector2 *>(p_variant._data._mem); diff --git a/core/variant/variant.h b/core/variant/variant.h index 9ec131a1b8..d3f694e7ca 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -641,6 +641,7 @@ public: static UtilityFunctionType get_utility_function_type(const StringName &p_name); + static MethodInfo get_utility_function_info(const StringName &p_name); static int get_utility_function_argument_count(const StringName &p_name); static Variant::Type get_utility_function_argument_type(const StringName &p_name, int p_arg); static String get_utility_function_argument_name(const StringName &p_name, int p_arg); diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp index 4317b9dc98..6aba7d7d58 100644 --- a/core/variant/variant_construct.cpp +++ b/core/variant/variant_construct.cpp @@ -119,8 +119,9 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructNoArgs<Plane>>(sarray()); add_constructor<VariantConstructor<Plane, Plane>>(sarray("from")); + add_constructor<VariantConstructor<Plane, Vector3>>(sarray("normal")); add_constructor<VariantConstructor<Plane, Vector3, double>>(sarray("normal", "d")); - add_constructor<VariantConstructor<Plane, Vector3, Vector3>>(sarray("point", "normal")); + add_constructor<VariantConstructor<Plane, Vector3, Vector3>>(sarray("normal", "point")); add_constructor<VariantConstructor<Plane, Vector3, Vector3, Vector3>>(sarray("point1", "point2", "point3")); add_constructor<VariantConstructor<Plane, double, double, double, double>>(sarray("a", "b", "c", "d")); diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 40c8a1bfde..37383ff2ec 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -1301,12 +1301,12 @@ struct VariantZeroAssigner<Signal> { template <> struct VariantZeroAssigner<Dictionary> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_dictionary(v) = Dictionary(); } }; template <> struct VariantZeroAssigner<Array> { - static _FORCE_INLINE_ void zero(Variant *v) {} + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_array(v) = Array(); } }; template <> diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index b94588f480..b85ece338c 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -641,7 +641,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNotFloat>(Variant::OP_NOT, Variant::FLOAT, Variant::NIL); register_op<OperatorEvaluatorNotObject>(Variant::OP_NOT, Variant::OBJECT, Variant::NIL); - register_op<OperatorEvaluatorInStringFind>(Variant::OP_IN, Variant::STRING, Variant::STRING); + register_op<OperatorEvaluatorInStringFind<String>>(Variant::OP_IN, Variant::STRING, Variant::STRING); + register_op<OperatorEvaluatorInStringFind<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::STRING); + register_op<OperatorEvaluatorInStringNameFind<String>>(Variant::OP_IN, Variant::STRING, Variant::STRING_NAME); + register_op<OperatorEvaluatorInStringNameFind<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::STRING_NAME); register_op<OperatorEvaluatorInDictionaryHasNil>(Variant::OP_IN, Variant::NIL, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<bool>>(Variant::OP_IN, Variant::BOOL, Variant::DICTIONARY); diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h index 3c9f849a4f..353524469a 100644 --- a/core/variant/variant_op.h +++ b/core/variant/variant_op.h @@ -1213,22 +1213,44 @@ public: //// +template <class Left> class OperatorEvaluatorInStringFind { public: static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &str_a = *VariantGetInternalPtr<String>::get_ptr(&p_left); + const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(&p_left); const String &str_b = *VariantGetInternalPtr<String>::get_ptr(&p_right); *r_ret = str_b.find(str_a) != -1; r_valid = true; } static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const String &str_a = *VariantGetInternalPtr<String>::get_ptr(left); + const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(left); const String &str_b = *VariantGetInternalPtr<String>::get_ptr(right); *VariantGetInternalPtr<bool>::get_ptr(r_ret) = str_b.find(str_a) != -1; } static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<String>::convert(right).find(PtrToArg<String>::convert(left)) != -1, r_ret); + PtrToArg<bool>::encode(PtrToArg<String>::convert(right).find(PtrToArg<Left>::convert(left)) != -1, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class Left> +class OperatorEvaluatorInStringNameFind { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(&p_left); + const String str_b = VariantGetInternalPtr<StringName>::get_ptr(&p_right)->operator String(); + + *r_ret = str_b.find(str_a) != -1; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Left &str_a = *VariantGetInternalPtr<Left>::get_ptr(left); + const String str_b = VariantGetInternalPtr<StringName>::get_ptr(right)->operator String(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = str_b.find(str_a) != -1; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<StringName>::convert(right).operator String().find(PtrToArg<Left>::convert(left)) != -1, r_ret); } static Variant::Type get_return_type() { return Variant::BOOL; } }; diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index a214a238a6..221a8c4f98 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -90,6 +90,17 @@ const char *VariantParser::tk_name[TK_MAX] = { "ERROR" }; +static double stor_fix(const String &p_str) { + if (p_str == "inf") { + return INFINITY; + } else if (p_str == "inf_neg") { + return -INFINITY; + } else if (p_str == "nan") { + return NAN; + } + return -1; +} + Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, String &r_err_str) { bool string_name = false; @@ -469,8 +480,19 @@ Error VariantParser::_parse_construct(Stream *p_stream, Vector<T> &r_construct, if (first && token.type == TK_PARENTHESIS_CLOSE) { break; } else if (token.type != TK_NUMBER) { - r_err_str = "Expected float in constructor"; - return ERR_PARSE_ERROR; + bool valid = false; + if (token.type == TK_IDENTIFIER) { + double real = stor_fix(token.value); + if (real != -1) { + token.type = TK_NUMBER; + token.value = real; + valid = true; + } + } + if (!valid) { + r_err_str = "Expected float in constructor"; + return ERR_PARSE_ERROR; + } } r_construct.push_back(token.value); @@ -507,6 +529,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, value = Variant(); } else if (id == "inf") { value = INFINITY; + } else if (id == "inf_neg") { + value = -INFINITY; } else if (id == "nan") { value = NAN; } else if (id == "Vector2") { @@ -1401,11 +1425,19 @@ Error VariantParser::parse(Stream *p_stream, Variant &r_ret, String &r_err_str, ////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// -static String rtosfix(double p_value) { +static String rtos_fix(double p_value) { if (p_value == 0.0) { return "0"; //avoid negative zero (-0) being written, which may annoy git, svn, etc. for changes when they don't exist. + } else if (isnan(p_value)) { + return "nan"; + } else if (isinf(p_value)) { + if (p_value > 0) { + return "inf"; + } else { + return "inf_neg"; + } } else { return rtoss(p_value); } @@ -1423,8 +1455,8 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, itos(p_variant.operator int64_t())); } break; case Variant::FLOAT: { - String s = rtosfix(p_variant.operator double()); - if (s != "inf" && s != "nan") { + String s = rtos_fix(p_variant.operator double()); + if (s != "inf" && s != "inf_neg" && s != "nan") { if (s.find(".") == -1 && s.find("e") == -1) { s += ".0"; } @@ -1439,7 +1471,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::VECTOR2: { Vector2 v = p_variant; - p_store_string_func(p_store_string_ud, "Vector2(" + rtosfix(v.x) + ", " + rtosfix(v.y) + ")"); + p_store_string_func(p_store_string_ud, "Vector2(" + rtos_fix(v.x) + ", " + rtos_fix(v.y) + ")"); } break; case Variant::VECTOR2I: { Vector2i v = p_variant; @@ -1447,7 +1479,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::RECT2: { Rect2 aabb = p_variant; - p_store_string_func(p_store_string_ud, "Rect2(" + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ")"); + p_store_string_func(p_store_string_ud, "Rect2(" + rtos_fix(aabb.position.x) + ", " + rtos_fix(aabb.position.y) + ", " + rtos_fix(aabb.size.x) + ", " + rtos_fix(aabb.size.y) + ")"); } break; case Variant::RECT2I: { @@ -1457,7 +1489,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::VECTOR3: { Vector3 v = p_variant; - p_store_string_func(p_store_string_ud, "Vector3(" + rtosfix(v.x) + ", " + rtosfix(v.y) + ", " + rtosfix(v.z) + ")"); + p_store_string_func(p_store_string_ud, "Vector3(" + rtos_fix(v.x) + ", " + rtos_fix(v.y) + ", " + rtos_fix(v.z) + ")"); } break; case Variant::VECTOR3I: { Vector3i v = p_variant; @@ -1465,17 +1497,17 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::PLANE: { Plane p = p_variant; - p_store_string_func(p_store_string_ud, "Plane(" + rtosfix(p.normal.x) + ", " + rtosfix(p.normal.y) + ", " + rtosfix(p.normal.z) + ", " + rtosfix(p.d) + ")"); + p_store_string_func(p_store_string_ud, "Plane(" + rtos_fix(p.normal.x) + ", " + rtos_fix(p.normal.y) + ", " + rtos_fix(p.normal.z) + ", " + rtos_fix(p.d) + ")"); } break; case Variant::AABB: { AABB aabb = p_variant; - p_store_string_func(p_store_string_ud, "AABB(" + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.position.z) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ", " + rtosfix(aabb.size.z) + ")"); + p_store_string_func(p_store_string_ud, "AABB(" + rtos_fix(aabb.position.x) + ", " + rtos_fix(aabb.position.y) + ", " + rtos_fix(aabb.position.z) + ", " + rtos_fix(aabb.size.x) + ", " + rtos_fix(aabb.size.y) + ", " + rtos_fix(aabb.size.z) + ")"); } break; case Variant::QUATERNION: { Quaternion quaternion = p_variant; - p_store_string_func(p_store_string_ud, "Quaternion(" + rtosfix(quaternion.x) + ", " + rtosfix(quaternion.y) + ", " + rtosfix(quaternion.z) + ", " + rtosfix(quaternion.w) + ")"); + p_store_string_func(p_store_string_ud, "Quaternion(" + rtos_fix(quaternion.x) + ", " + rtos_fix(quaternion.y) + ", " + rtos_fix(quaternion.z) + ", " + rtos_fix(quaternion.w) + ")"); } break; case Variant::TRANSFORM2D: { @@ -1486,7 +1518,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i != 0 || j != 0) { s += ", "; } - s += rtosfix(m3.elements[i][j]); + s += rtos_fix(m3.elements[i][j]); } } @@ -1501,7 +1533,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i != 0 || j != 0) { s += ", "; } - s += rtosfix(m3.elements[i][j]); + s += rtos_fix(m3.elements[i][j]); } } @@ -1517,11 +1549,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i != 0 || j != 0) { s += ", "; } - s += rtosfix(m3.elements[i][j]); + s += rtos_fix(m3.elements[i][j]); } } - s = s + ", " + rtosfix(t.origin.x) + ", " + rtosfix(t.origin.y) + ", " + rtosfix(t.origin.z); + s = s + ", " + rtos_fix(t.origin.x) + ", " + rtos_fix(t.origin.y) + ", " + rtos_fix(t.origin.z); p_store_string_func(p_store_string_ud, s + ")"); } break; @@ -1529,7 +1561,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str // misc types case Variant::COLOR: { Color c = p_variant; - p_store_string_func(p_store_string_ud, "Color(" + rtosfix(c.r) + ", " + rtosfix(c.g) + ", " + rtosfix(c.b) + ", " + rtosfix(c.a) + ")"); + p_store_string_func(p_store_string_ud, "Color(" + rtos_fix(c.r) + ", " + rtos_fix(c.g) + ", " + rtos_fix(c.b) + ", " + rtos_fix(c.a) + ")"); } break; case Variant::STRING_NAME: { @@ -1707,7 +1739,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i > 0) { p_store_string_func(p_store_string_ud, ", "); } - p_store_string_func(p_store_string_ud, rtosfix(ptr[i])); + p_store_string_func(p_store_string_ud, rtos_fix(ptr[i])); } p_store_string_func(p_store_string_ud, ")"); @@ -1723,7 +1755,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i > 0) { p_store_string_func(p_store_string_ud, ", "); } - p_store_string_func(p_store_string_ud, rtosfix(ptr[i])); + p_store_string_func(p_store_string_ud, rtos_fix(ptr[i])); } p_store_string_func(p_store_string_ud, ")"); @@ -1759,7 +1791,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i > 0) { p_store_string_func(p_store_string_ud, ", "); } - p_store_string_func(p_store_string_ud, rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y)); + p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].x) + ", " + rtos_fix(ptr[i].y)); } p_store_string_func(p_store_string_ud, ")"); @@ -1775,7 +1807,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (i > 0) { p_store_string_func(p_store_string_ud, ", "); } - p_store_string_func(p_store_string_ud, rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y) + ", " + rtosfix(ptr[i].z)); + p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].x) + ", " + rtos_fix(ptr[i].y) + ", " + rtos_fix(ptr[i].z)); } p_store_string_func(p_store_string_ud, ")"); @@ -1792,7 +1824,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, ", "); } - p_store_string_func(p_store_string_ud, rtosfix(ptr[i].r) + ", " + rtosfix(ptr[i].g) + ", " + rtosfix(ptr[i].b) + ", " + rtosfix(ptr[i].a)); + p_store_string_func(p_store_string_ud, rtos_fix(ptr[i].r) + ", " + rtos_fix(ptr[i].g) + ", " + rtos_fix(ptr[i].b) + ", " + rtos_fix(ptr[i].a)); } p_store_string_func(p_store_string_ud, ")"); diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 3bba68d75e..4abb51ca7c 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -239,7 +239,8 @@ void Variant::set_named(const StringName &p_member, const Variant &p_value, bool *v = p_value; r_valid = true; } else { - r_valid = false; + VariantGetInternalPtr<Dictionary>::get_ptr(this)->operator[](p_member) = p_value; + r_valid = true; } } else { diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 55c1376031..666b582e39 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -1333,6 +1333,28 @@ Variant::UtilityFunctionType Variant::get_utility_function_type(const StringName return bfi->type; } +MethodInfo Variant::get_utility_function_info(const StringName &p_name) { + MethodInfo info; + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); + if (bfi) { + info.name = p_name; + if (bfi->returns_value && bfi->return_type == Variant::NIL) { + info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + } + info.return_val.type = bfi->return_type; + if (bfi->is_vararg) { + info.flags |= METHOD_FLAG_VARARG; + } + for (int i = 0; i < bfi->argnames.size(); ++i) { + PropertyInfo arg; + arg.type = bfi->get_arg_type(i); + arg.name = bfi->argnames[i]; + info.arguments.push_back(arg); + } + } + return info; +} + int Variant::get_utility_function_argument_count(const StringName &p_name) { const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { |