diff options
Diffstat (limited to 'core/config/project_settings.cpp')
-rw-r--r-- | core/config/project_settings.cpp | 101 |
1 files changed, 63 insertions, 38 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 9fe54e57a7..6c28b00f48 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -194,7 +194,7 @@ String ProjectSettings::localize_path(const String &p_path) const { return cwd.replace_first(res_path, "res://"); } else { - int sep = path.rfind("/"); + int sep = path.rfind_char('/'); if (sep == -1) { return "res://" + path; } @@ -214,36 +214,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 @@ -262,6 +262,12 @@ String ProjectSettings::globalize_path(const String &p_path) const { return p_path.replace("res:/", resource_path); } return p_path.replace("res://", ""); + } else if (p_path.begins_with("uid://")) { + const String path = ResourceUID::uid_to_path(p_path); + if (!resource_path.is_empty()) { + return path.replace("res:/", resource_path); + } + return path.replace("res://", ""); } else if (p_path.begins_with("user://")) { String data_dir = OS::get_singleton()->get_user_data_dir(); if (!data_dir.is_empty()) { @@ -300,7 +306,7 @@ bool ProjectSettings::_set(const StringName &p_name, const Variant &p_value) { } { // Feature overrides. - int dot = p_name.operator String().find("."); + int dot = p_name.operator String().find_char('.'); if (dot != -1) { Vector<String> s = p_name.operator String().split("."); @@ -371,7 +377,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; @@ -435,7 +441,7 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const { for (const _VCSort &E : vclist) { String prop_info_name = E.name; - int dot = prop_info_name.find("."); + int dot = prop_info_name.find_char('.'); if (dot != -1 && !custom_prop_info.has(prop_info_name)) { prop_info_name = prop_info_name.substr(0, dot); } @@ -494,6 +500,7 @@ bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_f } void ProjectSettings::_convert_to_last_version(int p_from_version) { +#ifndef DISABLE_DEPRECATED if (p_from_version <= 3) { // Converts the actions from array to dictionary (array of events to dictionary with deadzone + events) for (KeyValue<StringName, ProjectSettings::VariantContainer> &E : props) { @@ -507,6 +514,25 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) { } } } + if (p_from_version == 5) { + // Converts the device in events from -3 to -1. + // -3 was introduced in GH-97707 as a way to prevent a clash in device IDs, but as reported in GH-99243, this leads to problems. + // -3 was used during dev-releases, so this conversion helps to revert such affected projects. + // This conversion doesn't affect any other projects, since -3 is not used otherwise. + for (KeyValue<StringName, ProjectSettings::VariantContainer> &E : props) { + if (String(E.key).begins_with("input/")) { + Dictionary action = E.value.variant; + Array events = action["events"]; + for (int i = 0; i < events.size(); i++) { + Ref<InputEvent> ev = events[i]; + if (ev.is_valid() && ev->get_device() == -3) { + ev->set_device(-1); + } + } + } + } + } +#endif // DISABLE_DEPRECATED } /* @@ -548,7 +574,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) { @@ -627,7 +653,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b // or, if requested (`p_upwards`) in parent directories. Ref<DirAccess> 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(); @@ -731,7 +757,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); } @@ -773,7 +799,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") { @@ -799,7 +825,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. @@ -807,7 +833,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; @@ -821,17 +847,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++; } @@ -839,12 +865,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); } @@ -859,7 +885,7 @@ Error ProjectSettings::save() { Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<String, List<String>> &p_props, const CustomMap &p_custom, const String &p_custom_features) { Error err; Ref<FileAccess> 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); @@ -929,7 +955,7 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<Str Error err; Ref<FileAccess> 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,"); @@ -1075,7 +1101,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust String category = E.name; String name = E.name; - int div = category.find("/"); + int div = category.find_char('/'); if (div < 0) { category = ""; @@ -1102,7 +1128,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)); } } @@ -1167,22 +1193,16 @@ bool ProjectSettings::is_project_loaded() const { } bool ProjectSettings::_property_can_revert(const StringName &p_name) const { - if (!props.has(p_name)) { - return false; - } - - return props[p_name].initial != props[p_name].variant; + return props.has(p_name); } bool ProjectSettings::_property_get_revert(const StringName &p_name, Variant &r_property) const { - if (!props.has(p_name)) { - return false; + const RBMap<StringName, ProjectSettings::VariantContainer>::Element *value = props.find(p_name); + if (value) { + r_property = value->value().initial.duplicate(); + return true; } - - // Duplicate so that if value is array or dictionary, changing the setting will not change the stored initial value. - r_property = props[p_name].initial.duplicate(); - - return true; + return false; } void ProjectSettings::set_setting(const String &p_setting, const Variant &p_value) { @@ -1397,7 +1417,7 @@ void ProjectSettings::_add_builtin_input_map() { } Dictionary action; - action["deadzone"] = Variant(0.2f); + action["deadzone"] = Variant(InputMap::DEFAULT_DEADZONE); action["events"] = events; String action_name = "input/" + E.key; @@ -1466,6 +1486,7 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("display/window/size/transparent", false); GLOBAL_DEF("display/window/size/extend_to_title", false); GLOBAL_DEF("display/window/size/no_focus", false); + GLOBAL_DEF("display/window/size/sharp_corners", false); GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"), 0); // 8K resolution GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"), 0); // 8K resolution @@ -1491,6 +1512,10 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("display/window/subwindows/embed_subwindows", true); // Keep the enum values in sync with the `DisplayServer::VSyncMode` enum. custom_prop_info["display/window/vsync/vsync_mode"] = PropertyInfo(Variant::INT, "display/window/vsync/vsync_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Adaptive,Mailbox"); + + GLOBAL_DEF("display/window/frame_pacing/android/enable_frame_pacing", true); + GLOBAL_DEF(PropertyInfo(Variant::INT, "display/window/frame_pacing/android/swappy_mode", PROPERTY_HINT_ENUM, "pipeline_forced_on,auto_fps_pipeline_forced_on,auto_fps_auto_pipeline"), 2); + custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded"); GLOBAL_DEF("physics/2d/run_on_separate_thread", false); GLOBAL_DEF("physics/3d/run_on_separate_thread", false); |