diff --git a/SConstruct b/SConstruct index 7a76472517d..4f9afa537f1 100644 --- a/SConstruct +++ b/SConstruct @@ -961,7 +961,7 @@ methods.sort_module_list(env) if env.editor_build: # Add editor-specific dependencies to the dependency graph. - env.module_add_dependencies("editor", ["freetype", "svg"]) + env.module_add_dependencies("editor", ["freetype", "regex", "svg"]) # And check if they are met. if not env.module_check_dependencies("editor"): diff --git a/core/config/engine.h b/core/config/engine.h index e1fb1f4f902..8cd2740d82c 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -89,6 +89,7 @@ class Engine { bool project_manager_hint = false; bool extension_reloading = false; bool embedded_in_editor = false; + bool recovery_mode_hint = false; bool _print_header = true; @@ -164,6 +165,9 @@ class Engine { _FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) { extension_reloading = p_enabled; } _FORCE_INLINE_ bool is_extension_reloading_enabled() const { return extension_reloading; } + + _FORCE_INLINE_ void set_recovery_mode_hint(bool p_enabled) { recovery_mode_hint = p_enabled; } + _FORCE_INLINE_ bool is_recovery_mode_hint() const { return recovery_mode_hint; } #else _FORCE_INLINE_ void set_editor_hint(bool p_enabled) {} _FORCE_INLINE_ bool is_editor_hint() const { return false; } @@ -173,6 +177,9 @@ class Engine { _FORCE_INLINE_ void set_extension_reloading_enabled(bool p_enabled) {} _FORCE_INLINE_ bool is_extension_reloading_enabled() const { return false; } + + _FORCE_INLINE_ void set_recovery_mode_hint(bool p_enabled) {} + _FORCE_INLINE_ bool is_recovery_mode_hint() const { return false; } #endif Dictionary get_version_info() const; diff --git a/core/extension/gdextension_manager.cpp b/core/extension/gdextension_manager.cpp index edfed513b2f..847145dc400 100644 --- a/core/extension/gdextension_manager.cpp +++ b/core/extension/gdextension_manager.cpp @@ -86,6 +86,10 @@ GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(co } GDExtensionManager::LoadStatus GDExtensionManager::load_extension(const String &p_path) { + if (Engine::get_singleton()->is_recovery_mode_hint()) { + return LOAD_STATUS_FAILED; + } + Ref loader; loader.instantiate(); return GDExtensionManager::get_singleton()->load_extension_with_loader(p_path, loader); @@ -121,6 +125,10 @@ GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String #else ERR_FAIL_COND_V_MSG(!Engine::get_singleton()->is_extension_reloading_enabled(), LOAD_STATUS_FAILED, "GDExtension reloading is disabled."); + if (Engine::get_singleton()->is_recovery_mode_hint()) { + return LOAD_STATUS_FAILED; + } + if (!gdextension_map.has(p_path)) { return LOAD_STATUS_NOT_LOADED; } @@ -163,6 +171,10 @@ GDExtensionManager::LoadStatus GDExtensionManager::reload_extension(const String } GDExtensionManager::LoadStatus GDExtensionManager::unload_extension(const String &p_path) { + if (Engine::get_singleton()->is_recovery_mode_hint()) { + return LOAD_STATUS_FAILED; + } + if (!gdextension_map.has(p_path)) { return LOAD_STATUS_NOT_LOADED; } @@ -209,6 +221,10 @@ String GDExtensionManager::class_get_icon_path(const String &p_class) const { } void GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel p_level) { + if (Engine::get_singleton()->is_recovery_mode_hint()) { + return; + } + ERR_FAIL_COND(int32_t(p_level) - 1 != level); for (KeyValue> &E : gdextension_map) { E.value->initialize_library(p_level); @@ -223,6 +239,10 @@ void GDExtensionManager::initialize_extensions(GDExtension::InitializationLevel } void GDExtensionManager::deinitialize_extensions(GDExtension::InitializationLevel p_level) { + if (Engine::get_singleton()->is_recovery_mode_hint()) { + return; + } + ERR_FAIL_COND(int32_t(p_level) != level); for (KeyValue> &E : gdextension_map) { E.value->deinitialize_library(p_level); @@ -261,6 +281,10 @@ void GDExtensionManager::_reload_all_scripts() { #endif // TOOLS_ENABLED void GDExtensionManager::load_extensions() { + if (Engine::get_singleton()->is_recovery_mode_hint()) { + return; + } + Ref f = FileAccess::open(GDExtension::get_extension_list_config_file(), FileAccess::READ); while (f.is_valid() && !f->eof_reached()) { String s = f->get_line().strip_edges(); @@ -275,6 +299,9 @@ void GDExtensionManager::load_extensions() { void GDExtensionManager::reload_extensions() { #ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_recovery_mode_hint()) { + return; + } bool reloaded = false; for (const KeyValue> &E : gdextension_map) { if (!E.value->is_reloadable()) { diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 9f6e76b10cb..7f2d8a62b11 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -256,8 +256,8 @@ bool InputMap::event_is_action(const Ref &p_event, const StringName int InputMap::event_get_index(const Ref &p_event, const StringName &p_action, bool p_exact_match) const { int index = -1; - event_get_action_status(p_event, p_action, p_exact_match, nullptr, nullptr, nullptr, &index); - return index; + bool valid = event_get_action_status(p_event, p_action, p_exact_match, nullptr, nullptr, nullptr, &index); + return valid ? index : -1; } bool InputMap::event_get_action_status(const Ref &p_event, const StringName &p_action, bool p_exact_match, bool *r_pressed, float *r_strength, float *r_raw_strength, int *r_event_index) const { diff --git a/core/io/json.cpp b/core/io/json.cpp index 65534800276..64123e8b729 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -200,7 +200,7 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to String str; while (true) { if (p_str[index] == 0) { - r_err_str = "Unterminated String"; + r_err_str = "Unterminated string"; return ERR_PARSE_ERROR; } else if (p_str[index] == '"') { index++; @@ -210,7 +210,7 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to index++; char32_t next = p_str[index]; if (next == 0) { - r_err_str = "Unterminated String"; + r_err_str = "Unterminated string"; return ERR_PARSE_ERROR; } char32_t res = 0; @@ -236,7 +236,7 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to for (int j = 0; j < 4; j++) { char32_t c = p_str[index + j + 1]; if (c == 0) { - r_err_str = "Unterminated String"; + r_err_str = "Unterminated string"; return ERR_PARSE_ERROR; } if (!is_hex_digit(c)) { @@ -272,7 +272,7 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to for (int j = 0; j < 4; j++) { char32_t c = p_str[index + j + 1]; if (c == 0) { - r_err_str = "Unterminated String"; + r_err_str = "Unterminated string"; return ERR_PARSE_ERROR; } if (!is_hex_digit(c)) { @@ -315,7 +315,7 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to res = next; } break; default: { - r_err_str = "Invalid escape sequence."; + r_err_str = "Invalid escape sequence"; return ERR_PARSE_ERROR; } } @@ -363,19 +363,20 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to r_token.value = id; return OK; } else { - r_err_str = "Unexpected character."; + r_err_str = "Unexpected character"; return ERR_PARSE_ERROR; } } } } + r_err_str = "Unknown error getting token"; return ERR_PARSE_ERROR; } Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) { if (p_depth > Variant::MAX_RECURSION_DEPTH) { - r_err_str = "JSON structure is too deep. Bailing."; + r_err_str = "JSON structure is too deep"; return ERR_OUT_OF_MEMORY; } @@ -402,7 +403,7 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in } else if (id == "null") { value = Variant(); } else { - r_err_str = "Expected 'true','false' or 'null', got '" + id + "'."; + r_err_str = vformat("Expected 'true', 'false', or 'null', got '%s'", id); return ERR_PARSE_ERROR; } } else if (token.type == TK_NUMBER) { @@ -410,7 +411,7 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in } else if (token.type == TK_STRING) { value = token.value; } else { - r_err_str = "Expected value, got " + String(tk_name[token.type]) + "."; + r_err_str = vformat("Expected value, got '%s'", String(tk_name[token.type])); return ERR_PARSE_ERROR; } diff --git a/core/io/logger.cpp b/core/io/logger.cpp index ee6410b9634..3ae4ac4b09b 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -37,6 +37,11 @@ #include "core/os/time.h" #include "modules/modules_enabled.gen.h" // For regex. +#ifdef MODULE_REGEX_ENABLED +#include "modules/regex/regex.h" +#else +class RegEx : public RefCounted {}; +#endif // MODULE_REGEX_ENABLED #if defined(MINGW_ENABLED) || defined(_MSC_VER) #define sprintf sprintf_s diff --git a/core/io/logger.h b/core/io/logger.h index 03b4b3a0532..9a0d48dae5b 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -36,13 +36,11 @@ #include "core/io/file_access.h" #include "core/string/ustring.h" #include "core/templates/vector.h" -#include "modules/modules_enabled.gen.h" // For regex. -#ifdef MODULE_REGEX_ENABLED -#include "modules/regex/regex.h" -#endif // MODULE_REGEX_ENABLED #include +class RegEx; + class Logger { protected: bool should_log(bool p_err); @@ -92,9 +90,7 @@ class RotatedFileLogger : public Logger { void clear_old_backups(); void rotate_file(); -#ifdef MODULE_REGEX_ENABLED Ref strip_ansi_regex; -#endif // MODULE_REGEX_ENABLED public: explicit RotatedFileLogger(const String &p_base_path, int p_max_files = 10); diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index c00ddb50106..3ef08933f58 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -200,11 +200,12 @@ Error PCKPacker::flush(bool p_verbose) { } for (int i = 0; i < files.size(); i++) { - int string_len = files[i].path.utf8().length(); + CharString utf8_string = files[i].path.utf8(); + int string_len = utf8_string.length(); int pad = _get_pad(4, string_len); fhead->store_32(uint32_t(string_len + pad)); - fhead->store_buffer((const uint8_t *)files[i].path.utf8().get_data(), string_len); + fhead->store_buffer((const uint8_t *)utf8_string.get_data(), string_len); for (int j = 0; j < pad; j++) { fhead->store_8(0); } diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp index 023fc967098..f571f23b28e 100644 --- a/core/io/resource_uid.cpp +++ b/core/io/resource_uid.cpp @@ -49,7 +49,7 @@ String ResourceUID::get_cache_file() { static constexpr uint8_t uuid_characters[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', '0', '1', '2', '3', '4', '5', '6', '7', '8' }; static constexpr uint32_t uuid_characters_element_count = (sizeof(uuid_characters) / sizeof(*uuid_characters)); -static constexpr uint8_t max_uuid_number_length = 19; // Max 0x7FFFFFFFFFFFFFFF size is 19 digits. +static constexpr uint8_t max_uuid_number_length = 13; // Max 0x7FFFFFFFFFFFFFFF (uid://d4n4ub6itg400) size is 13 characters. String ResourceUID::id_to_text(ID p_id) const { if (p_id < 0) { @@ -58,12 +58,12 @@ String ResourceUID::id_to_text(ID p_id) const { char32_t tmp[max_uuid_number_length]; uint32_t tmp_size = 0; - while (p_id) { + do { uint32_t c = p_id % uuid_characters_element_count; tmp[tmp_size] = uuid_characters[c]; p_id /= uuid_characters_element_count; ++tmp_size; - } + } while (p_id); // tmp_size + uid:// (6) + 1 for null. String txt; diff --git a/core/object/object.cpp b/core/object/object.cpp index 5a2b5dfecb5..1e25af7e3da 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -522,7 +522,13 @@ void Object::get_property_list(List *p_list, bool p_reversed) cons PropertyInfo pi = PropertyInfo(K.value.get_type(), "metadata/" + K.key.operator String()); if (K.value.get_type() == Variant::OBJECT) { pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "Resource"; + Object *obj = K.value; + if (Object::cast_to