diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 2735a1aa67..bcec1a0ad4 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -119,6 +119,10 @@ void Engine::set_time_scale(double p_scale) { } double Engine::get_time_scale() const { + return freeze_time_scale ? 0 : _time_scale; +} + +double Engine::get_unfrozen_time_scale() const { return _time_scale; } @@ -457,6 +461,10 @@ bool Engine::notify_frame_server_synced() { return server_syncs > SERVER_SYNC_FRAME_COUNT_WARNING; } +void Engine::set_freeze_time_scale(bool p_frozen) { + freeze_time_scale = p_frozen; +} + Engine::Engine() { singleton = this; } diff --git a/core/config/engine.h b/core/config/engine.h index ec089923b3..737f0eb87e 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -101,6 +101,8 @@ private: int server_syncs = 0; bool frame_server_synced = false; + bool freeze_time_scale = false; + public: static Engine *get_singleton(); @@ -132,6 +134,7 @@ public: void set_time_scale(double p_scale); double get_time_scale() const; + double get_unfrozen_time_scale() const; void set_print_to_stdout(bool p_enabled); bool is_printing_to_stdout() const; @@ -202,6 +205,8 @@ public: void increment_frames_drawn(); bool notify_frame_server_synced(); + void set_freeze_time_scale(bool p_frozen); + Engine(); virtual ~Engine(); }; diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 5ac7f05a76..08ce6c0e07 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -216,36 +216,36 @@ String ProjectSettings::localize_path(const String &p_path) const { } void ProjectSettings::set_initial_value(const String &p_name, const Variant &p_value) { - ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name)); // Duplicate so that if value is array or dictionary, changing the setting will not change the stored initial value. props[p_name].initial = p_value.duplicate(); } void ProjectSettings::set_restart_if_changed(const String &p_name, bool p_restart) { - ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name)); props[p_name].restart_if_changed = p_restart; } void ProjectSettings::set_as_basic(const String &p_name, bool p_basic) { - ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name)); props[p_name].basic = p_basic; } void ProjectSettings::set_as_internal(const String &p_name, bool p_internal) { - ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name)); props[p_name].internal = p_internal; } void ProjectSettings::set_ignore_value_in_docs(const String &p_name, bool p_ignore) { - ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name)); #ifdef DEBUG_METHODS_ENABLED props[p_name].ignore_value_in_docs = p_ignore; #endif } bool ProjectSettings::get_ignore_value_in_docs(const String &p_name) const { - ERR_FAIL_COND_V_MSG(!props.has(p_name), false, "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_V_MSG(!props.has(p_name), false, vformat("Request for nonexistent project setting: '%s'.", p_name)); #ifdef DEBUG_METHODS_ENABLED return props[p_name].ignore_value_in_docs; #else @@ -373,7 +373,7 @@ Variant ProjectSettings::get_setting_with_override(const StringName &p_name) con } if (!props.has(name)) { - WARN_PRINT("Property not found: " + String(name)); + WARN_PRINT(vformat("Property not found: '%s'.", String(name))); return Variant(); } return props[name].variant; @@ -567,7 +567,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b if (!p_main_pack.is_empty()) { bool ok = _load_resource_pack(p_main_pack); - ERR_FAIL_COND_V_MSG(!ok, ERR_CANT_OPEN, "Cannot open resource pack '" + p_main_pack + "'."); + ERR_FAIL_COND_V_MSG(!ok, ERR_CANT_OPEN, vformat("Cannot open resource pack '%s'.", p_main_pack)); Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); if (err == OK && !p_ignore_override) { @@ -646,7 +646,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b // or, if requested (`p_upwards`) in parent directories. Ref d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V_MSG(d.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(d.is_null(), ERR_CANT_CREATE, vformat("Cannot create DirAccess for path '%s'.", p_path)); d->change_dir(p_path); String current_dir = d->get_current_dir(); @@ -750,7 +750,7 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) { f->get_buffer(d.ptrw(), vlen); Variant value; err = decode_variant(value, d.ptr(), d.size(), nullptr, true); - ERR_CONTINUE_MSG(err != OK, "Error decoding property: " + key + "."); + ERR_CONTINUE_MSG(err != OK, vformat("Error decoding property: '%s'.", key)); set(key, value); } @@ -792,7 +792,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) { last_save_time = FileAccess::get_modified_time(get_resource_path().path_join("project.godot")); return OK; } - ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted."); + ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Error parsing '%s' at line %d: %s File might be corrupted.", p_path, lines, error_text)); if (!assign.is_empty()) { if (section.is_empty() && assign == "config_version") { @@ -818,7 +818,7 @@ Error ProjectSettings::_load_settings_text_or_binary(const String &p_text_path, return OK; } else if (err != ERR_FILE_NOT_FOUND) { // If the file exists but can't be loaded, we want to know it. - ERR_PRINT("Couldn't load file '" + p_bin_path + "', error code " + itos(err) + "."); + ERR_PRINT(vformat("Couldn't load file '%s', error code %d.", p_bin_path, err)); } // Fallback to text-based project.godot file if binary was not found. @@ -826,7 +826,7 @@ Error ProjectSettings::_load_settings_text_or_binary(const String &p_text_path, if (err == OK) { return OK; } else if (err != ERR_FILE_NOT_FOUND) { - ERR_PRINT("Couldn't load file '" + p_text_path + "', error code " + itos(err) + "."); + ERR_PRINT(vformat("Couldn't load file '%s', error code %d.", p_text_path, err)); } return err; @@ -840,17 +840,17 @@ Error ProjectSettings::load_custom(const String &p_path) { } int ProjectSettings::get_order(const String &p_name) const { - ERR_FAIL_COND_V_MSG(!props.has(p_name), -1, "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_V_MSG(!props.has(p_name), -1, vformat("Request for nonexistent project setting: '%s'.", p_name)); return props[p_name].order; } void ProjectSettings::set_order(const String &p_name, int p_order) { - ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name)); props[p_name].order = p_order; } void ProjectSettings::set_builtin_order(const String &p_name) { - ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name)); if (props[p_name].order >= NO_BUILTIN_ORDER_BASE) { props[p_name].order = last_builtin_order++; } @@ -858,12 +858,12 @@ void ProjectSettings::set_builtin_order(const String &p_name) { bool ProjectSettings::is_builtin_setting(const String &p_name) const { // Return true because a false negative is worse than a false positive. - ERR_FAIL_COND_V_MSG(!props.has(p_name), true, "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_V_MSG(!props.has(p_name), true, vformat("Request for nonexistent project setting: '%s'.", p_name)); return props[p_name].order < NO_BUILTIN_ORDER_BASE; } void ProjectSettings::clear(const String &p_name) { - ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); + ERR_FAIL_COND_MSG(!props.has(p_name), vformat("Request for nonexistent project setting: '%s'.", p_name)); props.erase(p_name); } @@ -878,7 +878,7 @@ Error ProjectSettings::save() { Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap> &p_props, const CustomMap &p_custom, const String &p_custom_features) { Error err; Ref file = FileAccess::open(p_file, FileAccess::WRITE, &err); - ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.binary at " + p_file + "."); + ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Couldn't save project.binary at '%s'.", p_file)); uint8_t hdr[4] = { 'E', 'C', 'F', 'G' }; file->store_buffer(hdr, 4); @@ -948,7 +948,7 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap file = FileAccess::open(p_file, FileAccess::WRITE, &err); - ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.godot - " + p_file + "."); + ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Couldn't save project.godot - %s.", p_file)); file->store_line("; Engine configuration file."); file->store_line("; It's best edited using the editor UI and not directly,"); @@ -1121,7 +1121,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust } else if (p_path.ends_with(".binary")) { return _save_settings_binary(p_path, save_props, p_custom, save_features); } else { - ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unknown config file format: " + p_path); + ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, vformat("Unknown config file format: '%s'.", p_path)); } } diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 16467c9615..172ca71370 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -77,7 +77,7 @@ Ref ResourceLoader::load(const String &p_path, const String &p_type_hi Error err = OK; Ref ret = ::ResourceLoader::load(p_path, p_type_hint, ResourceFormatLoader::CacheMode(p_cache_mode), &err); - ERR_FAIL_COND_V_MSG(err != OK, ret, "Error loading resource: '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(err != OK, ret, vformat("Error loading resource: '%s'.", p_path)); return ret; } @@ -1317,7 +1317,7 @@ void Thread::_start_func(void *ud) { } if (ce.error != Callable::CallError::CALL_OK) { - ERR_FAIL_MSG("Could not call function '" + func_name + "' to start thread " + t->get_id() + ": " + Variant::get_callable_error_text(t->target_callable, nullptr, 0, ce) + "."); + ERR_FAIL_MSG(vformat("Could not call function '%s' to start thread %d: %s.", func_name, t->get_id(), Variant::get_callable_error_text(t->target_callable, nullptr, 0, ce))); } } @@ -1542,7 +1542,7 @@ TypedArray ClassDB::class_get_method_list(const StringName &p_class, return ret; } -Variant ClassDB::class_call_static_method(const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) { +Variant ClassDB::class_call_static(const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) { if (p_argcount < 2) { r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; return Variant::NIL; @@ -1683,7 +1683,7 @@ void ClassDB::_bind_methods() { ::ClassDB::bind_method(D_METHOD("class_get_method_list", "class", "no_inheritance"), &ClassDB::class_get_method_list, DEFVAL(false)); - ::ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "class_call_static_method", &ClassDB::class_call_static_method, MethodInfo("class_call_static_method", PropertyInfo(Variant::STRING_NAME, "class"), PropertyInfo(Variant::STRING_NAME, "method"))); + ::ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "class_call_static", &ClassDB::class_call_static, MethodInfo("class_call_static", PropertyInfo(Variant::STRING_NAME, "class"), PropertyInfo(Variant::STRING_NAME, "method"))); ::ClassDB::bind_method(D_METHOD("class_get_integer_constant_list", "class", "no_inheritance"), &ClassDB::class_get_integer_constant_list, DEFVAL(false)); @@ -1828,8 +1828,8 @@ Object *Engine::get_singleton_object(const StringName &p_name) const { } void Engine::register_singleton(const StringName &p_name, Object *p_object) { - ERR_FAIL_COND_MSG(has_singleton(p_name), "Singleton already registered: " + String(p_name)); - ERR_FAIL_COND_MSG(!String(p_name).is_valid_ascii_identifier(), "Singleton name is not a valid identifier: " + p_name); + ERR_FAIL_COND_MSG(has_singleton(p_name), vformat("Singleton already registered: '%s'.", String(p_name))); + ERR_FAIL_COND_MSG(!String(p_name).is_valid_ascii_identifier(), vformat("Singleton name is not a valid identifier: '%s'.", p_name)); ::Engine::Singleton s; s.class_name = p_name; s.name = p_name; @@ -1839,8 +1839,8 @@ void Engine::register_singleton(const StringName &p_name, Object *p_object) { } void Engine::unregister_singleton(const StringName &p_name) { - ERR_FAIL_COND_MSG(!has_singleton(p_name), "Attempt to remove unregistered singleton: " + String(p_name)); - ERR_FAIL_COND_MSG(!::Engine::get_singleton()->is_singleton_user_created(p_name), "Attempt to remove non-user created singleton: " + String(p_name)); + ERR_FAIL_COND_MSG(!has_singleton(p_name), vformat("Attempt to remove unregistered singleton: '%s'.", String(p_name))); + ERR_FAIL_COND_MSG(!::Engine::get_singleton()->is_singleton_user_created(p_name), vformat("Attempt to remove non-user created singleton: '%s'.", String(p_name))); ::Engine::get_singleton()->remove_singleton(p_name); } @@ -1987,14 +1987,14 @@ bool EngineDebugger::is_active() { void EngineDebugger::register_profiler(const StringName &p_name, Ref p_profiler) { ERR_FAIL_COND(p_profiler.is_null()); ERR_FAIL_COND_MSG(p_profiler->is_bound(), "Profiler already registered."); - ERR_FAIL_COND_MSG(profilers.has(p_name) || has_profiler(p_name), "Profiler name already in use: " + p_name); + ERR_FAIL_COND_MSG(profilers.has(p_name) || has_profiler(p_name), vformat("Profiler name already in use: '%s'.", p_name)); Error err = p_profiler->bind(p_name); - ERR_FAIL_COND_MSG(err != OK, "Profiler failed to register with error: " + itos(err)); + ERR_FAIL_COND_MSG(err != OK, vformat("Profiler failed to register with error: %d.", err)); profilers.insert(p_name, p_profiler); } void EngineDebugger::unregister_profiler(const StringName &p_name) { - ERR_FAIL_COND_MSG(!profilers.has(p_name), "Profiler not registered: " + p_name); + ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Profiler not registered: '%s'.", p_name)); profilers[p_name]->unbind(); profilers.erase(p_name); } @@ -2018,7 +2018,7 @@ void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, c } void EngineDebugger::register_message_capture(const StringName &p_name, const Callable &p_callable) { - ERR_FAIL_COND_MSG(captures.has(p_name) || has_capture(p_name), "Capture already registered: " + p_name); + ERR_FAIL_COND_MSG(captures.has(p_name) || has_capture(p_name), vformat("Capture already registered: '%s'.", p_name)); captures.insert(p_name, p_callable); Callable &c = captures[p_name]; ::EngineDebugger::Capture capture(&c, &EngineDebugger::call_capture); @@ -2026,7 +2026,7 @@ void EngineDebugger::register_message_capture(const StringName &p_name, const Ca } void EngineDebugger::unregister_message_capture(const StringName &p_name) { - ERR_FAIL_COND_MSG(!captures.has(p_name), "Capture not registered: " + p_name); + ERR_FAIL_COND_MSG(!captures.has(p_name), vformat("Capture not registered: '%s'.", p_name)); ::EngineDebugger::unregister_message_capture(p_name); captures.erase(p_name); } @@ -2060,8 +2060,8 @@ Error EngineDebugger::call_capture(void *p_user, const String &p_cmd, const Arra Variant retval; Callable::CallError err; capture.callp(args, 2, retval, err); - ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, FAILED, "Error calling 'capture' to callable: " + Variant::get_callable_error_text(capture, args, 2, err)); - ERR_FAIL_COND_V_MSG(retval.get_type() != Variant::BOOL, FAILED, "Error calling 'capture' to callable: " + String(capture) + ". Return type is not bool."); + ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, FAILED, vformat("Error calling 'capture' to callable: %s.", Variant::get_callable_error_text(capture, args, 2, err))); + ERR_FAIL_COND_V_MSG(retval.get_type() != Variant::BOOL, FAILED, vformat("Error calling 'capture' to callable: '%s'. Return type is not bool.", String(capture))); r_captured = retval; return OK; } diff --git a/core/core_bind.h b/core/core_bind.h index e44268d539..86828365f9 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -486,7 +486,7 @@ public: int class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const; TypedArray class_get_method_list(const StringName &p_class, bool p_no_inheritance = false) const; - Variant class_call_static_method(const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error); + Variant class_call_static(const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error); PackedStringArray class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const; bool class_has_integer_constant(const StringName &p_class, const StringName &p_name) const; diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp index d41a4233f4..9ba219d73a 100644 --- a/core/crypto/crypto.cpp +++ b/core/crypto/crypto.cpp @@ -242,7 +242,7 @@ Error ResourceFormatSaverCrypto::save(const Ref &p_resource, const Str } else { ERR_FAIL_V(ERR_INVALID_PARAMETER); } - ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save Crypto resource to file '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot save Crypto resource to file '%s'.", p_path)); return OK; } diff --git a/core/crypto/crypto_core.cpp b/core/crypto/crypto_core.cpp index 1071a0f0ae..c191066709 100644 --- a/core/crypto/crypto_core.cpp +++ b/core/crypto/crypto_core.cpp @@ -72,7 +72,7 @@ int CryptoCore::RandomGenerator::_entropy_poll(void *p_data, unsigned char *r_bu Error CryptoCore::RandomGenerator::init() { int ret = mbedtls_ctr_drbg_seed((mbedtls_ctr_drbg_context *)ctx, mbedtls_entropy_func, (mbedtls_entropy_context *)entropy, nullptr, 0); if (ret) { - ERR_FAIL_COND_V_MSG(ret, FAILED, " failed\n ! mbedtls_ctr_drbg_seed returned an error" + itos(ret)); + ERR_FAIL_COND_V_MSG(ret, FAILED, vformat(" failed\n ! mbedtls_ctr_drbg_seed returned an error %d.", ret)); } return OK; } @@ -80,7 +80,7 @@ Error CryptoCore::RandomGenerator::init() { Error CryptoCore::RandomGenerator::get_random_bytes(uint8_t *r_buffer, size_t p_bytes) { ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED); int ret = mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *)ctx, r_buffer, p_bytes); - ERR_FAIL_COND_V_MSG(ret, FAILED, " failed\n ! mbedtls_ctr_drbg_seed returned an error" + itos(ret)); + ERR_FAIL_COND_V_MSG(ret, FAILED, vformat(" failed\n ! mbedtls_ctr_drbg_seed returned an error %d.", ret)); return OK; } diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp index 3c27691857..0928180591 100644 --- a/core/debugger/engine_debugger.cpp +++ b/core/debugger/engine_debugger.cpp @@ -48,12 +48,12 @@ HashMap EngineDebugger::protocols; void (*EngineDebugger::allow_focus_steal_fn)(); void EngineDebugger::register_profiler(const StringName &p_name, const Profiler &p_func) { - ERR_FAIL_COND_MSG(profilers.has(p_name), "Profiler already registered: " + p_name); + ERR_FAIL_COND_MSG(profilers.has(p_name), vformat("Profiler already registered: '%s'.", p_name)); profilers.insert(p_name, p_func); } void EngineDebugger::unregister_profiler(const StringName &p_name) { - ERR_FAIL_COND_MSG(!profilers.has(p_name), "Profiler not registered: " + p_name); + ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Profiler not registered: '%s'.", p_name)); Profiler &p = profilers[p_name]; if (p.active && p.toggle) { p.toggle(p.data, false, Array()); @@ -63,22 +63,22 @@ void EngineDebugger::unregister_profiler(const StringName &p_name) { } void EngineDebugger::register_message_capture(const StringName &p_name, Capture p_func) { - ERR_FAIL_COND_MSG(captures.has(p_name), "Capture already registered: " + p_name); + ERR_FAIL_COND_MSG(captures.has(p_name), vformat("Capture already registered: '%s'.", p_name)); captures.insert(p_name, p_func); } void EngineDebugger::unregister_message_capture(const StringName &p_name) { - ERR_FAIL_COND_MSG(!captures.has(p_name), "Capture not registered: " + p_name); + ERR_FAIL_COND_MSG(!captures.has(p_name), vformat("Capture not registered: '%s'.", p_name)); captures.erase(p_name); } void EngineDebugger::register_uri_handler(const String &p_protocol, CreatePeerFunc p_func) { - ERR_FAIL_COND_MSG(protocols.has(p_protocol), "Protocol handler already registered: " + p_protocol); + ERR_FAIL_COND_MSG(protocols.has(p_protocol), vformat("Protocol handler already registered: '%s'.", p_protocol)); protocols.insert(p_protocol, p_func); } void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts) { - ERR_FAIL_COND_MSG(!profilers.has(p_name), "Can't change profiler state, no profiler: " + p_name); + ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Can't change profiler state, no profiler: '%s'.", p_name)); Profiler &p = profilers[p_name]; if (p.toggle) { p.toggle(p.data, p_enabled, p_opts); @@ -87,7 +87,7 @@ void EngineDebugger::profiler_enable(const StringName &p_name, bool p_enabled, c } void EngineDebugger::profiler_add_frame_data(const StringName &p_name, const Array &p_data) { - ERR_FAIL_COND_MSG(!profilers.has(p_name), "Can't add frame data, no profiler: " + p_name); + ERR_FAIL_COND_MSG(!profilers.has(p_name), vformat("Can't add frame data, no profiler: '%s'.", p_name)); Profiler &p = profilers[p_name]; if (p.add) { p.add(p.data, p_data); @@ -108,7 +108,7 @@ bool EngineDebugger::has_capture(const StringName &p_name) { Error EngineDebugger::capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured) { r_captured = false; - ERR_FAIL_COND_V_MSG(!captures.has(p_name), ERR_UNCONFIGURED, "Capture not registered: " + p_name); + ERR_FAIL_COND_V_MSG(!captures.has(p_name), ERR_UNCONFIGURED, vformat("Capture not registered: '%s'.", p_name)); const Capture &cap = captures[p_name]; return cap.capture(cap.data, p_msg, p_args, r_captured); } @@ -166,7 +166,7 @@ void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, co for (int i = 0; i < p_breakpoints.size(); i++) { const String &bp = p_breakpoints[i]; int sp = bp.rfind(":"); - ERR_CONTINUE_MSG(sp == -1, "Invalid breakpoint: '" + bp + "', expected file:line format."); + ERR_CONTINUE_MSG(sp == -1, vformat("Invalid breakpoint: '%s', expected file:line format.", bp)); singleton_script_debugger->insert_breakpoint(bp.substr(sp + 1, bp.length()).to_int(), bp.substr(0, sp)); } diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index aca5f56505..b69a7db989 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -81,7 +81,7 @@ public: for (int i = 0; i < custom_monitor_names.size(); i++) { Variant monitor_value = performance->call("get_custom_monitor", custom_monitor_names[i]); if (!monitor_value.is_num()) { - ERR_PRINT("Value of custom monitor '" + String(custom_monitor_names[i]) + "' is not a number"); + ERR_PRINT(vformat("Value of custom monitor '%s' is not a number.", String(custom_monitor_names[i]))); arr[i + max] = Variant(); } else { arr[i + max] = monitor_value; @@ -571,7 +571,7 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { bool captured = false; ERR_CONTINUE(_try_capture(command, data, captured) != OK); if (!captured) { - WARN_PRINT("Unknown message received from debugger: " + command); + WARN_PRINT(vformat("Unknown message received from debugger: %s.", command)); } } } else { diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp index 233893dc4f..45a433e125 100644 --- a/core/debugger/remote_debugger_peer.cpp +++ b/core/debugger/remote_debugger_peer.cpp @@ -180,7 +180,7 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po } if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) { - ERR_PRINT("Remote Debugger: Unable to connect. Status: " + String::num(tcp_client->get_status()) + "."); + ERR_PRINT(vformat("Remote Debugger: Unable to connect. Status: %s.", String::num(tcp_client->get_status()))); return FAILED; } connected = true; diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index 2033ff2b43..b70bd23918 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -1366,7 +1366,7 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_ return true; // May just not have this array and its still good. Probably added recently. } bool failed = false; - ERR_FAIL_COND_V_MSG(!p_new_api.has(p_base_array), false, "New API lacks base array: " + p_base_array); + ERR_FAIL_COND_V_MSG(!p_new_api.has(p_base_array), false, vformat("New API lacks base array: %s", p_base_array)); Array new_api = p_new_api[p_base_array]; HashMap new_api_assoc; @@ -1374,6 +1374,9 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_ Dictionary elem = var; ERR_FAIL_COND_V_MSG(!elem.has(p_name_field), false, vformat("Validate extension JSON: Element of base_array '%s' is missing field '%s'. This is a bug.", base_array, p_name_field)); String name = elem[p_name_field]; + if (name.is_valid_float()) { + name = name.trim_suffix(".0"); // Make "integers" stringified as integers. + } if (p_compare_operators && elem.has("right_type")) { name += " " + String(elem["right_type"]); } @@ -1389,6 +1392,9 @@ static bool compare_dict_array(const Dictionary &p_old_api, const Dictionary &p_ continue; } String name = old_elem[p_name_field]; + if (name.is_valid_float()) { + name = name.trim_suffix(".0"); // Make "integers" stringified as integers. + } if (p_compare_operators && old_elem.has("right_type")) { name += " " + String(old_elem["right_type"]); } @@ -1518,7 +1524,7 @@ static bool compare_sub_dict_array(HashSet &r_removed_classes_registered return true; // May just not have this array and its still good. Probably added recently or optional. } bool failed = false; - ERR_FAIL_COND_V_MSG(!p_new_api.has(p_outer), false, "New API lacks base array: " + p_outer); + ERR_FAIL_COND_V_MSG(!p_new_api.has(p_outer), false, vformat("New API lacks base array: %s", p_outer)); Array new_api = p_new_api[p_outer]; HashMap new_api_assoc; diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 50f83c9d4d..2dc2735fc5 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -357,8 +357,8 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr StringName class_name = *reinterpret_cast(p_class_name); StringName parent_class_name = *reinterpret_cast(p_parent_class_name); - ERR_FAIL_COND_MSG(!String(class_name).is_valid_unicode_identifier(), "Attempt to register extension class '" + class_name + "', which is not a valid class identifier."); - ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), "Attempt to register extension class '" + class_name + "', which appears to be already registered."); + ERR_FAIL_COND_MSG(!String(class_name).is_valid_unicode_identifier(), vformat("Attempt to register extension class '%s', which is not a valid class identifier.", class_name)); + ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), vformat("Attempt to register extension class '%s', which appears to be already registered.", class_name)); Extension *parent_extension = nullptr; @@ -372,7 +372,7 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr //inheriting from engine class } } else { - ERR_FAIL_MSG("Attempt to register an extension class '" + String(class_name) + "' using non-existing parent class '" + String(parent_class_name) + "'."); + ERR_FAIL_MSG(vformat("Attempt to register an extension class '%s' using non-existing parent class '%s'.", String(class_name), String(parent_class_name))); } #ifdef TOOLS_ENABLED @@ -465,7 +465,7 @@ void GDExtension::_register_extension_class_method(GDExtensionClassLibraryPtr p_ StringName class_name = *reinterpret_cast(p_class_name); StringName method_name = *reinterpret_cast(p_method_info->name); - ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension method '" + String(method_name) + "' for unexisting class '" + class_name + "'."); + ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension method '%s' for unexisting class '%s'.", String(method_name), class_name)); #ifdef TOOLS_ENABLED Extension *extension = &self->extension_classes[class_name]; @@ -515,7 +515,7 @@ void GDExtension::_register_extension_class_integer_constant(GDExtensionClassLib StringName class_name = *reinterpret_cast(p_class_name); StringName enum_name = *reinterpret_cast(p_enum_name); StringName constant_name = *reinterpret_cast(p_constant_name); - ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension constant '" + constant_name + "' for unexisting class '" + class_name + "'."); + ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension constant '%s' for unexisting class '%s'.", constant_name, class_name)); #ifdef TOOLS_ENABLED // If the extension is still marked as reloading, that means it failed to register again. @@ -539,7 +539,7 @@ void GDExtension::_register_extension_class_property_indexed(GDExtensionClassLib StringName setter = *reinterpret_cast(p_setter); StringName getter = *reinterpret_cast(p_getter); String property_name = *reinterpret_cast(p_info->name); - ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + property_name + "' for unexisting class '" + class_name + "'."); + ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension class property '%s' for unexisting class '%s'.", property_name, class_name)); #ifdef TOOLS_ENABLED // If the extension is still marked as reloading, that means it failed to register again. @@ -560,7 +560,7 @@ void GDExtension::_register_extension_class_property_group(GDExtensionClassLibra StringName class_name = *reinterpret_cast(p_class_name); String group_name = *reinterpret_cast(p_group_name); String prefix = *reinterpret_cast(p_prefix); - ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property group '" + group_name + "' for unexisting class '" + class_name + "'."); + ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension class property group '%s' for unexisting class '%s'.", group_name, class_name)); #ifdef TOOLS_ENABLED // If the extension is still marked as reloading, that means it failed to register again. @@ -579,7 +579,7 @@ void GDExtension::_register_extension_class_property_subgroup(GDExtensionClassLi StringName class_name = *reinterpret_cast(p_class_name); String subgroup_name = *reinterpret_cast(p_subgroup_name); String prefix = *reinterpret_cast(p_prefix); - ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property subgroup '" + subgroup_name + "' for unexisting class '" + class_name + "'."); + ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension class property subgroup '%s' for unexisting class '%s'.", subgroup_name, class_name)); #ifdef TOOLS_ENABLED // If the extension is still marked as reloading, that means it failed to register again. @@ -597,7 +597,7 @@ void GDExtension::_register_extension_class_signal(GDExtensionClassLibraryPtr p_ StringName class_name = *reinterpret_cast(p_class_name); StringName signal_name = *reinterpret_cast(p_signal_name); - ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class signal '" + signal_name + "' for unexisting class '" + class_name + "'."); + ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to register extension class signal '%s' for unexisting class '%s'.", signal_name, class_name)); #ifdef TOOLS_ENABLED // If the extension is still marked as reloading, that means it failed to register again. @@ -620,7 +620,7 @@ void GDExtension::_unregister_extension_class(GDExtensionClassLibraryPtr p_libra GDExtension *self = reinterpret_cast(p_library); StringName class_name = *reinterpret_cast(p_class_name); - ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'."); + ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), vformat("Attempt to unregister unexisting extension class '%s'.", class_name)); Extension *ext = &self->extension_classes[class_name]; #ifdef TOOLS_ENABLED @@ -628,7 +628,7 @@ void GDExtension::_unregister_extension_class(GDExtensionClassLibraryPtr p_libra self->_clear_extension(ext); } #endif - ERR_FAIL_COND_MSG(ext->gdextension.children.size(), "Attempt to unregister class '" + class_name + "' while other extension classes inherit from it."); + ERR_FAIL_COND_MSG(ext->gdextension.children.size(), vformat("Attempt to unregister class '%s' while other extension classes inherit from it.", class_name)); #ifdef TOOLS_ENABLED ClassDB::unregister_extension_class(class_name, !ext->is_reloading); @@ -666,13 +666,13 @@ void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExte HashMap GDExtension::gdextension_interface_functions; void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) { - ERR_FAIL_COND_MSG(gdextension_interface_functions.has(p_function_name), "Attempt to register interface function '" + p_function_name + "', which appears to be already registered."); + ERR_FAIL_COND_MSG(gdextension_interface_functions.has(p_function_name), vformat("Attempt to register interface function '%s', which appears to be already registered.", p_function_name)); gdextension_interface_functions.insert(p_function_name, p_function_pointer); } GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(const StringName &p_function_name) { GDExtensionInterfaceFunctionPtr *function = gdextension_interface_functions.getptr(p_function_name); - ERR_FAIL_NULL_V_MSG(function, nullptr, "Attempt to get non-existent interface function: " + String(p_function_name) + "."); + ERR_FAIL_NULL_V_MSG(function, nullptr, vformat("Attempt to get non-existent interface function: '%s'.", String(p_function_name))); return *function; } @@ -682,8 +682,8 @@ Error GDExtension::open_library(const String &p_path, const Refopen_library(p_path); - ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, "GDExtension dynamic library not found: " + p_path); - ERR_FAIL_COND_V_MSG(err != OK, err, "Can't open GDExtension dynamic library: " + p_path); + ERR_FAIL_COND_V_MSG(err == ERR_FILE_NOT_FOUND, err, vformat("GDExtension dynamic library not found: '%s'.", p_path)); + ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Can't open GDExtension dynamic library: '%s'.", p_path)); err = loader->initialize(&gdextension_get_proc_address, this, &initialization); diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp index 9d5f71e5a6..7ae7355219 100644 --- a/core/extension/gdextension_interface.cpp +++ b/core/extension/gdextension_interface.cpp @@ -1528,7 +1528,7 @@ static GDExtensionMethodBindPtr gdextension_classdb_get_method_bind(GDExtensionC #endif if (!mb && exists) { - ERR_PRINT("Method '" + classname + "." + methodname + "' has changed and no compatibility fallback has been provided. Please open an issue."); + ERR_PRINT(vformat("Method '%s.%s' has changed and no compatibility fallback has been provided. Please open an issue.", classname, methodname)); return nullptr; } ERR_FAIL_NULL_V(mb, nullptr); diff --git a/core/extension/gdextension_library_loader.cpp b/core/extension/gdextension_library_loader.cpp index 48eec44a8c..3ff4f24ed7 100644 --- a/core/extension/gdextension_library_loader.cpp +++ b/core/extension/gdextension_library_loader.cpp @@ -221,7 +221,7 @@ Error GDExtensionLibraryLoader::initialize(GDExtensionInterfaceGetProcAddress p_ Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, entry_symbol, entry_funcptr, false); if (err != OK) { - ERR_PRINT("GDExtension entry point '" + entry_symbol + "' not found in library " + library_path); + ERR_PRINT(vformat("GDExtension entry point '%s' not found in library %s.", entry_symbol, library_path)); return err; } @@ -232,7 +232,7 @@ Error GDExtensionLibraryLoader::initialize(GDExtensionInterfaceGetProcAddress p_ if (ret) { return OK; } else { - ERR_PRINT("GDExtension initialization function '" + entry_symbol + "' returned an error."); + ERR_PRINT(vformat("GDExtension initialization function '%s' returned an error.", entry_symbol)); return FAILED; } } @@ -274,12 +274,12 @@ Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) { Error err = config->load(p_path); if (err != OK) { - ERR_PRINT("Error loading GDExtension configuration file: " + p_path); + ERR_PRINT(vformat("Error loading GDExtension configuration file: '%s'.", p_path)); return err; } if (!config->has_section_key("configuration", "entry_symbol")) { - ERR_PRINT("GDExtension configuration file must contain a \"configuration/entry_symbol\" key: " + p_path); + ERR_PRINT(vformat("GDExtension configuration file must contain a \"configuration/entry_symbol\" key: '%s'.", p_path)); return ERR_INVALID_DATA; } @@ -298,7 +298,7 @@ Error GDExtensionLibraryLoader::parse_gdextension_file(const String &p_path) { } } } else { - ERR_PRINT("GDExtension configuration file must contain a \"configuration/compatibility_minimum\" key: " + p_path); + ERR_PRINT(vformat("GDExtension configuration file must contain a \"configuration/compatibility_minimum\" key: '%s'.", p_path)); return ERR_INVALID_DATA; } diff --git a/core/extension/gdextension_manager.cpp b/core/extension/gdextension_manager.cpp index 98596bda27..66203cbbad 100644 --- a/core/extension/gdextension_manager.cpp +++ b/core/extension/gdextension_manager.cpp @@ -260,7 +260,7 @@ void GDExtensionManager::load_extensions() { String s = f->get_line().strip_edges(); if (!s.is_empty()) { LoadStatus err = load_extension(s); - ERR_CONTINUE_MSG(err == LOAD_STATUS_FAILED, "Error loading extension: " + s); + ERR_CONTINUE_MSG(err == LOAD_STATUS_FAILED, vformat("Error loading extension: '%s'.", s)); } } diff --git a/core/input/input.cpp b/core/input/input.cpp index 695d3f131a..0b82292c7c 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -89,11 +89,50 @@ Input *Input::get_singleton() { void Input::set_mouse_mode(MouseMode p_mode) { ERR_FAIL_INDEX((int)p_mode, 5); + + if (p_mode == mouse_mode) { + return; + } + + // Allow to be set even if overridden, to see if the platform allows the mode. set_mouse_mode_func(p_mode); + mouse_mode = get_mouse_mode_func(); + + if (mouse_mode_override_enabled) { + set_mouse_mode_func(mouse_mode_override); + } } Input::MouseMode Input::get_mouse_mode() const { - return get_mouse_mode_func(); + return mouse_mode; +} + +void Input::set_mouse_mode_override_enabled(bool p_enabled) { + if (p_enabled == mouse_mode_override_enabled) { + return; + } + + mouse_mode_override_enabled = p_enabled; + + if (p_enabled) { + set_mouse_mode_func(mouse_mode_override); + mouse_mode_override = get_mouse_mode_func(); + } else { + set_mouse_mode_func(mouse_mode); + } +} + +void Input::set_mouse_mode_override(MouseMode p_mode) { + ERR_FAIL_INDEX((int)p_mode, 5); + + if (p_mode == mouse_mode_override) { + return; + } + + if (mouse_mode_override_enabled) { + set_mouse_mode_func(p_mode); + mouse_mode_override = get_mouse_mode_func(); + } } void Input::_bind_methods() { @@ -254,6 +293,10 @@ Input::VelocityTrack::VelocityTrack() { bool Input::is_anything_pressed() const { _THREAD_SAFE_METHOD_ + if (disable_input) { + return false; + } + if (!keys_pressed.is_empty() || !joy_buttons_pressed.is_empty() || !mouse_button_mask.is_empty()) { return true; } @@ -269,21 +312,41 @@ bool Input::is_anything_pressed() const { bool Input::is_key_pressed(Key p_keycode) const { _THREAD_SAFE_METHOD_ + + if (disable_input) { + return false; + } + return keys_pressed.has(p_keycode); } bool Input::is_physical_key_pressed(Key p_keycode) const { _THREAD_SAFE_METHOD_ + + if (disable_input) { + return false; + } + return physical_keys_pressed.has(p_keycode); } bool Input::is_key_label_pressed(Key p_keycode) const { _THREAD_SAFE_METHOD_ + + if (disable_input) { + return false; + } + return key_label_pressed.has(p_keycode); } bool Input::is_mouse_button_pressed(MouseButton p_button) const { _THREAD_SAFE_METHOD_ + + if (disable_input) { + return false; + } + return mouse_button_mask.has_flag(mouse_button_to_mask(p_button)); } @@ -297,11 +360,21 @@ static JoyButton _combine_device(JoyButton p_value, int p_device) { bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const { _THREAD_SAFE_METHOD_ + + if (disable_input) { + return false; + } + return joy_buttons_pressed.has(_combine_device(p_button, p_device)); } bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const { ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action)); + + if (disable_input) { + return false; + } + HashMap::ConstIterator E = action_states.find(p_action); if (!E) { return false; @@ -312,6 +385,11 @@ bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const { bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const { ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action)); + + if (disable_input) { + return false; + } + HashMap::ConstIterator E = action_states.find(p_action); if (!E) { return false; @@ -333,6 +411,11 @@ bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) con bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const { ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), false, InputMap::get_singleton()->suggest_actions(p_action)); + + if (disable_input) { + return false; + } + HashMap::ConstIterator E = action_states.find(p_action); if (!E) { return false; @@ -354,6 +437,11 @@ bool Input::is_action_just_released(const StringName &p_action, bool p_exact) co float Input::get_action_strength(const StringName &p_action, bool p_exact) const { ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action)); + + if (disable_input) { + return 0.0f; + } + HashMap::ConstIterator E = action_states.find(p_action); if (!E) { return 0.0f; @@ -368,6 +456,11 @@ float Input::get_action_strength(const StringName &p_action, bool p_exact) const float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const { ERR_FAIL_COND_V_MSG(!InputMap::get_singleton()->has_action(p_action), 0.0, InputMap::get_singleton()->suggest_actions(p_action)); + + if (disable_input) { + return 0.0f; + } + HashMap::ConstIterator E = action_states.find(p_action); if (!E) { return 0.0f; @@ -412,6 +505,11 @@ Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_po float Input::get_joy_axis(int p_device, JoyAxis p_axis) const { _THREAD_SAFE_METHOD_ + + if (disable_input) { + return 0; + } + JoyAxis c = _combine_device(p_axis, p_device); if (_joy_axis.has(c)) { return _joy_axis[c]; @@ -1666,6 +1764,14 @@ int Input::get_unused_joy_id() { return -1; } +void Input::set_disable_input(bool p_disable) { + disable_input = p_disable; +} + +bool Input::is_input_disabled() const { + return disable_input; +} + Input::Input() { singleton = this; diff --git a/core/input/input.h b/core/input/input.h index 32db2c0f2f..a4c8bd1d6a 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -105,6 +105,11 @@ private: Vector2 mouse_pos; int64_t mouse_window = 0; bool legacy_just_pressed_behavior = false; + bool disable_input = false; + + MouseMode mouse_mode = MOUSE_MODE_VISIBLE; + bool mouse_mode_override_enabled = false; + MouseMode mouse_mode_override = MOUSE_MODE_VISIBLE; struct ActionState { uint64_t pressed_physics_frame = UINT64_MAX; @@ -281,6 +286,8 @@ protected: public: void set_mouse_mode(MouseMode p_mode); MouseMode get_mouse_mode() const; + void set_mouse_mode_override_enabled(bool p_enabled); + void set_mouse_mode_override(MouseMode p_mode); #ifdef TOOLS_ENABLED void get_argument_options(const StringName &p_function, int p_idx, List *r_options) const override; @@ -382,6 +389,9 @@ public: void set_event_dispatch_function(EventDispatchFunc p_function); + void set_disable_input(bool p_disable); + bool is_input_disabled() const; + Input(); ~Input(); }; diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 9c10b143dd..553de4af9c 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -116,7 +116,7 @@ void InputMap::get_argument_options(const StringName &p_function, int p_idx, Lis #endif void InputMap::add_action(const StringName &p_action, float p_deadzone) { - ERR_FAIL_COND_MSG(input_map.has(p_action), "InputMap already has action \"" + String(p_action) + "\"."); + ERR_FAIL_COND_MSG(input_map.has(p_action), vformat("InputMap already has action \"%s\".", String(p_action))); input_map[p_action] = Action(); static int last_id = 1; input_map[p_action].id = last_id; diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp index 7d76156309..18df616332 100644 --- a/core/io/dir_access.cpp +++ b/core/io/dir_access.cpp @@ -179,7 +179,7 @@ Error DirAccess::make_dir_recursive(const String &p_dir) { curpath = curpath.path_join(subdirs[i]); Error err = make_dir(curpath); if (err != OK && err != ERR_ALREADY_EXISTS) { - ERR_FAIL_V_MSG(err, "Could not create directory: " + curpath); + ERR_FAIL_V_MSG(err, vformat("Could not create directory: '%s'.", curpath)); } } @@ -241,7 +241,7 @@ Ref DirAccess::create_for_path(const String &p_path) { Ref DirAccess::open(const String &p_path, Error *r_error) { Ref da = create_for_path(p_path); - ERR_FAIL_COND_V_MSG(da.is_null(), nullptr, "Cannot create DirAccess for path '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(da.is_null(), nullptr, vformat("Cannot create DirAccess for path '%s'.", p_path)); Error err = da->change_dir(p_path); if (r_error) { *r_error = err; @@ -347,10 +347,10 @@ Error DirAccess::copy(const String &p_from, const String &p_to, int p_chmod_flag Error err; { Ref fsrc = FileAccess::open(p_from, FileAccess::READ, &err); - ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_from); + ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Failed to open '%s'.", p_from)); Ref fdst = FileAccess::open(p_to, FileAccess::WRITE, &err); - ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to open " + p_to); + ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Failed to open '%s'.", p_to)); const size_t copy_buffer_limit = 65536; // 64 KB @@ -446,11 +446,11 @@ Error DirAccess::_copy_dir(Ref &p_target_da, const String &p_to, int String target_dir = p_to + rel_path; if (!p_target_da->dir_exists(target_dir)) { Error err = p_target_da->make_dir(target_dir); - ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + target_dir + "'."); + ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot create directory '%s'.", target_dir)); } Error err = change_dir(rel_path); - ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot change current directory to '" + rel_path + "'."); + ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot change current directory to '%s'.", rel_path)); err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags, p_copy_links); if (err) { @@ -468,11 +468,11 @@ Error DirAccess::copy_dir(const String &p_from, String p_to, int p_chmod_flags, ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist."); Ref target_da = DirAccess::create_for_path(p_to); - ERR_FAIL_COND_V_MSG(target_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_to + "'."); + ERR_FAIL_COND_V_MSG(target_da.is_null(), ERR_CANT_CREATE, vformat("Cannot create DirAccess for path '%s'.", p_to)); if (!target_da->dir_exists(p_to)) { Error err = target_da->make_dir_recursive(p_to); - ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + p_to + "'."); + ERR_FAIL_COND_V_MSG(err != OK, err, vformat("Cannot create directory '%s'.", p_to)); } if (!p_to.ends_with("/")) { diff --git a/core/io/dir_access.h b/core/io/dir_access.h index 2567764e55..670c512ea9 100644 --- a/core/io/dir_access.h +++ b/core/io/dir_access.h @@ -118,10 +118,10 @@ public: Ref da = create(ACCESS_FILESYSTEM); if (da->file_exists(p_path)) { if (da->remove(p_path) != OK) { - ERR_FAIL_MSG("Cannot remove file or directory: " + p_path); + ERR_FAIL_MSG(vformat("Cannot remove file or directory: '%s'.", p_path)); } } else { - ERR_FAIL_MSG("Cannot remove non-existent file or directory: " + p_path); + ERR_FAIL_MSG(vformat("Cannot remove non-existent file or directory: '%s'.", p_path)); } } diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 69ad8bbeda..e10462adcd 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -461,7 +461,7 @@ Vector FileAccess::get_buffer(int64_t p_length) const { } Error err = data.resize(p_length); - ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements."); + ERR_FAIL_COND_V_MSG(err != OK, data, vformat("Can't resize data to %d elements.", p_length)); uint8_t *w = data.ptrw(); int64_t len = get_buffer(w, p_length); @@ -542,7 +542,7 @@ uint64_t FileAccess::get_modified_time(const String &p_file) { } Ref fa = create_for_path(p_file); - ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, vformat("Cannot create FileAccess for path '%s'.", p_file)); uint64_t mt = fa->_get_modified_time(p_file); return mt; @@ -554,7 +554,7 @@ BitField FileAccess::get_unix_permissions(const } Ref fa = create_for_path(p_file); - ERR_FAIL_COND_V_MSG(fa.is_null(), 0, "Cannot create FileAccess for path '" + p_file + "'."); + ERR_FAIL_COND_V_MSG(fa.is_null(), 0, vformat("Cannot create FileAccess for path '%s'.", p_file)); return fa->_get_unix_permissions(p_file); } @@ -565,7 +565,7 @@ Error FileAccess::set_unix_permissions(const String &p_file, BitField fa = create_for_path(p_file); - ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'."); + ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, vformat("Cannot create FileAccess for path '%s'.", p_file)); Error err = fa->_set_unix_permissions(p_file, p_permissions); return err; @@ -577,7 +577,7 @@ bool FileAccess::get_hidden_attribute(const String &p_file) { } Ref fa = create_for_path(p_file); - ERR_FAIL_COND_V_MSG(fa.is_null(), false, "Cannot create FileAccess for path '" + p_file + "'."); + ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("Cannot create FileAccess for path '%s'.", p_file)); return fa->_get_hidden_attribute(p_file); } @@ -588,7 +588,7 @@ Error FileAccess::set_hidden_attribute(const String &p_file, bool p_hidden) { } Ref fa = create_for_path(p_file); - ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'."); + ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, vformat("Cannot create FileAccess for path '%s'.", p_file)); Error err = fa->_set_hidden_attribute(p_file, p_hidden); return err; @@ -600,7 +600,7 @@ bool FileAccess::get_read_only_attribute(const String &p_file) { } Ref fa = create_for_path(p_file); - ERR_FAIL_COND_V_MSG(fa.is_null(), false, "Cannot create FileAccess for path '" + p_file + "'."); + ERR_FAIL_COND_V_MSG(fa.is_null(), false, vformat("Cannot create FileAccess for path '%s'.", p_file)); return fa->_get_read_only_attribute(p_file); } @@ -611,7 +611,7 @@ Error FileAccess::set_read_only_attribute(const String &p_file, bool p_ro) { } Ref fa = create_for_path(p_file); - ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'."); + ERR_FAIL_COND_V_MSG(fa.is_null(), ERR_CANT_CREATE, vformat("Cannot create FileAccess for path '%s'.", p_file)); Error err = fa->_set_read_only_attribute(p_file, p_ro); return err; @@ -699,7 +699,7 @@ Vector FileAccess::get_file_as_bytes(const String &p_path, Error *r_err if (r_error) { // if error requested, do not throw error return Vector(); } - ERR_FAIL_V_MSG(Vector(), "Can't open file from path '" + String(p_path) + "'."); + ERR_FAIL_V_MSG(Vector(), vformat("Can't open file from path '%s'.", String(p_path))); } Vector data; data.resize(f->get_length()); @@ -717,7 +717,7 @@ String FileAccess::get_file_as_string(const String &p_path, Error *r_error) { if (r_error) { return String(); } - ERR_FAIL_V_MSG(String(), "Can't get file as string from path '" + String(p_path) + "'."); + ERR_FAIL_V_MSG(String(), vformat("Can't get file as string from path '%s'.", String(p_path))); } String ret; diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index 05335df9e9..84137251ef 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -60,7 +60,7 @@ Error FileAccessCompressed::open_after_magic(Ref p_base) { block_size = f->get_32(); if (block_size == 0) { f.unref(); - ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Can't open compressed file '" + p_base->get_path() + "' with block size 0, it is corrupted."); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, vformat("Can't open compressed file '%s' with block size 0, it is corrupted.", p_base->get_path())); } read_total = f->get_32(); uint32_t bc = (read_total / block_size) + 1; diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index 6c406afff0..a84aa4c800 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -39,7 +39,7 @@ #include Error FileAccessEncrypted::open_and_parse(Ref p_base, const Vector &p_key, Mode p_mode, bool p_with_magic) { - ERR_FAIL_COND_V_MSG(file.is_valid(), ERR_ALREADY_IN_USE, "Can't open file while another file from path '" + file->get_path_absolute() + "' is open."); + ERR_FAIL_COND_V_MSG(file.is_valid(), ERR_ALREADY_IN_USE, vformat("Can't open file while another file from path '%s' is open.", file->get_path_absolute())); ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER); pos = 0; diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 199a51e86d..2ead49ba81 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -87,7 +87,7 @@ Error FileAccessMemory::open_internal(const String &p_path, int p_mode_flags) { //name = DirAccess::normalize_path(name); HashMap>::Iterator E = files->find(name); - ERR_FAIL_COND_V_MSG(!E, ERR_FILE_NOT_FOUND, "Can't find file '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(!E, ERR_FILE_NOT_FOUND, vformat("Can't find file '%s'.", p_path)); data = E->value.ptrw(); length = E->value.size(); diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 6f2685163e..7bc96c4644 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -225,8 +225,8 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint32_t ver_minor = f->get_32(); f->get_32(); // patch number, not used for validation. - ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION, false, "Pack version unsupported: " + itos(version) + "."); - ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + "."); + ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION, false, vformat("Pack version unsupported: %d.", version)); + ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, vformat("Pack created with a newer version of the engine: %d.%d.", ver_major, ver_minor)); uint32_t pack_flags = f->get_32(); uint64_t file_base = f->get_64(); @@ -388,7 +388,7 @@ void FileAccessPack::close() { FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file) : pf(p_file), f(FileAccess::open(pf.pack, FileAccess::READ)) { - ERR_FAIL_COND_MSG(f.is_null(), "Can't open pack-referenced file '" + String(pf.pack) + "'."); + ERR_FAIL_COND_MSG(f.is_null(), vformat("Can't open pack-referenced file '%s'.", String(pf.pack))); f->seek(pf.offset); off = pf.offset; @@ -396,7 +396,7 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil if (pf.encrypted) { Ref fae; fae.instantiate(); - ERR_FAIL_COND_MSG(fae.is_null(), "Can't open encrypted pack-referenced file '" + String(pf.pack) + "'."); + ERR_FAIL_COND_MSG(fae.is_null(), vformat("Can't open encrypted pack-referenced file '%s'.", String(pf.pack))); Vector key; key.resize(32); @@ -405,7 +405,7 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil } Error err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_READ, false); - ERR_FAIL_COND_MSG(err, "Can't open encrypted pack-referenced file '" + String(pf.pack) + "'."); + ERR_FAIL_COND_MSG(err, vformat("Can't open encrypted pack-referenced file '%s'.", String(pf.pack))); f = fae; off = 0; } diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index 38f86bd04d..71ce18145a 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -118,7 +118,7 @@ void ZipArchive::close_handle(unzFile p_file) const { } unzFile ZipArchive::get_file_handle(const String &p_file) const { - ERR_FAIL_COND_V_MSG(!file_exists(p_file), nullptr, "File '" + p_file + " doesn't exist."); + ERR_FAIL_COND_V_MSG(!file_exists(p_file), nullptr, vformat("File '%s' doesn't exist.", p_file)); File file = files[p_file]; zlib_filefunc_def io; @@ -138,7 +138,7 @@ unzFile ZipArchive::get_file_handle(const String &p_file) const { io.free_mem = godot_free; unzFile pkg = unzOpen2(packages[file.package].filename.utf8().get_data(), &io); - ERR_FAIL_NULL_V_MSG(pkg, nullptr, "Cannot open file '" + packages[file.package].filename + "'."); + ERR_FAIL_NULL_V_MSG(pkg, nullptr, vformat("Cannot open file '%s'.", packages[file.package].filename)); int unz_err = unzGoToFilePos(pkg, &file.file_pos); if (unz_err != UNZ_OK || unzOpenCurrentFile(pkg) != UNZ_OK) { unzClose(pkg); diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 323990ef7e..9d2adb2fcf 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -102,9 +102,9 @@ String HTTPClient::query_string_from_dict(const Dictionary &p_dict) { Error HTTPClient::verify_headers(const Vector &p_headers) { for (int i = 0; i < p_headers.size(); i++) { String sanitized = p_headers[i].strip_edges(); - ERR_FAIL_COND_V_MSG(sanitized.is_empty(), ERR_INVALID_PARAMETER, "Invalid HTTP header at index " + itos(i) + ": empty."); + ERR_FAIL_COND_V_MSG(sanitized.is_empty(), ERR_INVALID_PARAMETER, vformat("Invalid HTTP header at index %d: empty.", i)); ERR_FAIL_COND_V_MSG(sanitized.find(":") < 1, ERR_INVALID_PARAMETER, - "Invalid HTTP header at index " + itos(i) + ": String must contain header-value pair, delimited by ':', but was: " + p_headers[i]); + vformat("Invalid HTTP header at index %d: String must contain header-value pair, delimited by ':', but was: '%s'.", i, p_headers[i])); } return OK; diff --git a/core/io/image.cpp b/core/io/image.cpp index 40f1499f77..613e740dd6 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -537,7 +537,7 @@ static bool _are_formats_compatible(Image::Format p_format0, Image::Format p_for } void Image::convert(Format p_new_format) { - ERR_FAIL_INDEX_MSG(p_new_format, FORMAT_MAX, "The Image format specified (" + itos(p_new_format) + ") is out of range. See Image's Format enum."); + ERR_FAIL_INDEX_MSG(p_new_format, FORMAT_MAX, vformat("The Image format specified (%d) is out of range. See Image's Format enum.", p_new_format)); if (data.size() == 0) { return; } @@ -1134,9 +1134,9 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { ERR_FAIL_COND_MSG(p_width <= 0, "Image width must be greater than 0."); ERR_FAIL_COND_MSG(p_height <= 0, "Image height must be greater than 0."); - ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + "."); - ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + "."); - ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS)); + ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, vformat("Image width cannot be greater than %d pixels.", MAX_WIDTH)); + ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, vformat("Image height cannot be greater than %d pixels.", MAX_HEIGHT)); + ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, vformat("Too many pixels for image, maximum is %d pixels.", MAX_PIXELS)); if (p_width == width && p_height == height) { return; @@ -1437,8 +1437,8 @@ void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) { ERR_FAIL_COND_MSG(p_y < 0, "Start y position cannot be smaller than 0."); ERR_FAIL_COND_MSG(p_width <= 0, "Width of image must be greater than 0."); ERR_FAIL_COND_MSG(p_height <= 0, "Height of image must be greater than 0."); - ERR_FAIL_COND_MSG(p_x + p_width > MAX_WIDTH, "End x position cannot be greater than " + itos(MAX_WIDTH) + "."); - ERR_FAIL_COND_MSG(p_y + p_height > MAX_HEIGHT, "End y position cannot be greater than " + itos(MAX_HEIGHT) + "."); + ERR_FAIL_COND_MSG(p_x + p_width > MAX_WIDTH, vformat("End x position cannot be greater than %d.", MAX_WIDTH)); + ERR_FAIL_COND_MSG(p_y + p_height > MAX_HEIGHT, vformat("End y position cannot be greater than %d.", MAX_HEIGHT)); /* to save memory, cropping should be done in-place, however, since this function will most likely either not be used much, or in critical areas, for now it won't, because @@ -1486,8 +1486,8 @@ void Image::crop(int p_width, int p_height) { void Image::rotate_90(ClockDirection p_direction) { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); - ERR_FAIL_COND_MSG(width <= 0, "The Image width specified (" + itos(width) + " pixels) must be greater than 0 pixels."); - ERR_FAIL_COND_MSG(height <= 0, "The Image height specified (" + itos(height) + " pixels) must be greater than 0 pixels."); + ERR_FAIL_COND_MSG(width <= 0, vformat("The Image width specified (%d pixels) must be greater than 0 pixels.", width)); + ERR_FAIL_COND_MSG(height <= 0, vformat("The Image height specified (%d pixels) must be greater than 0 pixels.", height)); bool used_mipmaps = has_mipmaps(); if (used_mipmaps) { @@ -1604,8 +1604,8 @@ void Image::rotate_90(ClockDirection p_direction) { void Image::rotate_180() { ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot rotate in compressed or custom image formats."); - ERR_FAIL_COND_MSG(width <= 0, "The Image width specified (" + itos(width) + " pixels) must be greater than 0 pixels."); - ERR_FAIL_COND_MSG(height <= 0, "The Image height specified (" + itos(height) + " pixels) must be greater than 0 pixels."); + ERR_FAIL_COND_MSG(width <= 0, vformat("The Image width specified (%d pixels) must be greater than 0 pixels.", width)); + ERR_FAIL_COND_MSG(height <= 0, vformat("The Image height specified (%d pixels) must be greater than 0 pixels.", height)); bool used_mipmaps = has_mipmaps(); if (used_mipmaps) { @@ -2251,15 +2251,15 @@ void Image::set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_for } void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format) { - ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels."); - ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels."); + ERR_FAIL_COND_MSG(p_width <= 0, vformat("The Image width specified (%d pixels) must be greater than 0 pixels.", p_width)); + ERR_FAIL_COND_MSG(p_height <= 0, vformat("The Image height specified (%d pixels) must be greater than 0 pixels.", p_height)); ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, - "The Image width specified (" + itos(p_width) + " pixels) cannot be greater than " + itos(MAX_WIDTH) + "pixels."); + vformat("The Image width specified (%d pixels) cannot be greater than %d pixels.", p_width, MAX_WIDTH)); ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, - "The Image height specified (" + itos(p_height) + " pixels) cannot be greater than " + itos(MAX_HEIGHT) + "pixels."); + vformat("The Image height specified (%d pixels) cannot be greater than %d pixels.", p_height, MAX_HEIGHT)); ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, - "Too many pixels for Image. Maximum is " + itos(MAX_WIDTH) + "x" + itos(MAX_HEIGHT) + " = " + itos(MAX_PIXELS) + "pixels."); - ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "The Image format specified (" + itos(p_format) + ") is out of range. See Image's Format enum."); + vformat("Too many pixels for Image. Maximum is %dx%d = %d pixels.", MAX_WIDTH, MAX_HEIGHT, MAX_PIXELS)); + ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, vformat("The Image format specified (%d) is out of range. See Image's Format enum.", p_format)); int mm = 0; int64_t size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); @@ -2277,15 +2277,15 @@ void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Forma } void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector &p_data) { - ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels."); - ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels."); + ERR_FAIL_COND_MSG(p_width <= 0, vformat("The Image width specified (%d pixels) must be greater than 0 pixels.", p_width)); + ERR_FAIL_COND_MSG(p_height <= 0, vformat("The Image height specified (%d pixels) must be greater than 0 pixels.", p_height)); ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, - "The Image width specified (" + itos(p_width) + " pixels) cannot be greater than " + itos(MAX_WIDTH) + " pixels."); + vformat("The Image width specified (%d pixels) cannot be greater than %d pixels.", p_width, MAX_WIDTH)); ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, - "The Image height specified (" + itos(p_height) + " pixels) cannot be greater than " + itos(MAX_HEIGHT) + " pixels."); + vformat("The Image height specified (%d pixels) cannot be greater than %d pixels.", p_height, MAX_HEIGHT)); ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, - "Too many pixels for Image. Maximum is " + itos(MAX_WIDTH) + "x" + itos(MAX_HEIGHT) + " = " + itos(MAX_PIXELS) + "pixels ."); - ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "The Image format specified (" + itos(p_format) + ") is out of range. See Image's Format enum."); + vformat("Too many pixels for Image. Maximum is %dx%d = %d pixels.", MAX_WIDTH, MAX_HEIGHT, MAX_PIXELS)); + ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, vformat("The Image format specified (%d) is out of range. See Image's Format enum.", p_format)); int mm; int64_t size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); @@ -2579,7 +2579,7 @@ Image::AlphaMode Image::detect_alpha() const { Error Image::load(const String &p_path) { #ifdef DEBUG_ENABLED if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) { - WARN_PRINT("Loaded resource as image file, this will not work on export: '" + p_path + "'. Instead, import the image file as an Image resource and load it normally as a resource."); + WARN_PRINT(vformat("Loaded resource as image file, this will not work on export: '%s'. Instead, import the image file as an Image resource and load it normally as a resource.", p_path)); } #endif return ImageLoader::load_image(p_path, this); @@ -2588,7 +2588,7 @@ Error Image::load(const String &p_path) { Ref Image::load_from_file(const String &p_path) { #ifdef DEBUG_ENABLED if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) { - WARN_PRINT("Loaded resource as image file, this will not work on export: '" + p_path + "'. Instead, import the image file as an Image resource and load it normally as a resource."); + WARN_PRINT(vformat("Loaded resource as image file, this will not work on export: '%s'. Instead, import the image file as an Image resource and load it normally as a resource.", p_path)); } #endif Ref image; @@ -2651,7 +2651,7 @@ Error Image::save_webp(const String &p_path, const bool p_lossy, const float p_q if (save_webp_func == nullptr) { return ERR_UNAVAILABLE; } - ERR_FAIL_COND_V_MSG(p_lossy && !(0.0f <= p_quality && p_quality <= 1.0f), ERR_INVALID_PARAMETER, "The WebP lossy quality was set to " + rtos(p_quality) + ", which is not valid. WebP lossy quality must be between 0.0 and 1.0 (inclusive)."); + ERR_FAIL_COND_V_MSG(p_lossy && !(0.0f <= p_quality && p_quality <= 1.0f), ERR_INVALID_PARAMETER, vformat("The WebP lossy quality was set to %f, which is not valid. WebP lossy quality must be between 0.0 and 1.0 (inclusive).", p_quality)); return save_webp_func(p_path, Ref((Image *)this), p_lossy, p_quality); } @@ -2660,7 +2660,7 @@ Vector Image::save_webp_to_buffer(const bool p_lossy, const float p_qua if (save_webp_buffer_func == nullptr) { return Vector(); } - ERR_FAIL_COND_V_MSG(p_lossy && !(0.0f <= p_quality && p_quality <= 1.0f), Vector(), "The WebP lossy quality was set to " + rtos(p_quality) + ", which is not valid. WebP lossy quality must be between 0.0 and 1.0 (inclusive)."); + ERR_FAIL_COND_V_MSG(p_lossy && !(0.0f <= p_quality && p_quality <= 1.0f), Vector(), vformat("The WebP lossy quality was set to %f, which is not valid. WebP lossy quality must be between 0.0 and 1.0 (inclusive).", p_quality)); return save_webp_buffer_func(Ref((Image *)this), p_lossy, p_quality); } diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index 5724cd66a9..8e87569d7c 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -89,7 +89,7 @@ Error ImageLoader::load_image(const String &p_file, Ref p_image, Ref p_image, Refload_image(p_image, f, p_flags, p_scale); if (err != OK) { - ERR_PRINT("Error loading image: " + p_file); + ERR_PRINT(vformat("Error loading image: '%s'.", p_file)); } if (err != ERR_FILE_UNRECOGNIZED) { diff --git a/core/io/ip.cpp b/core/io/ip.cpp index cf152cb41a..381436dc7a 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -203,7 +203,7 @@ IPAddress IP::get_resolve_item_address(ResolverID p_id) const { MutexLock lock(resolver->mutex); if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) { - ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet."); + ERR_PRINT(vformat("Resolve of '%s' didn't complete yet.", resolver->queue[p_id].hostname)); return IPAddress(); } @@ -222,7 +222,7 @@ Array IP::get_resolve_item_addresses(ResolverID p_id) const { MutexLock lock(resolver->mutex); if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) { - ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet."); + ERR_PRINT(vformat("Resolve of '%s' didn't complete yet.", resolver->queue[p_id].hostname)); return Array(); } diff --git a/core/io/json.cpp b/core/io/json.cpp index 0bbe79a0d1..989b292cbd 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -1404,7 +1404,7 @@ Error ResourceFormatSaverJSON::save(const Ref &p_resource, const Strin Error err; Ref file = FileAccess::open(p_path, FileAccess::WRITE, &err); - ERR_FAIL_COND_V_MSG(err, err, "Cannot save json '" + p_path + "'."); + ERR_FAIL_COND_V_MSG(err, err, vformat("Cannot save json '%s'.", p_path)); file->store_string(source); if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 8d6334b4ab..d425af0afd 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -700,9 +700,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int if (str == "script" && value.get_type() != Variant::NIL) { ERR_FAIL_COND_V_MSG(value.get_type() != Variant::STRING, ERR_INVALID_DATA, "Invalid value for \"script\" property, expected script path as String."); String path = value; - ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, "Invalid script path: '" + path + "'."); + ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, vformat("Invalid script path: '%s'.", path)); Ref