feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -39,7 +39,6 @@
#include "core/io/marshalls.h"
#include "core/io/resource_uid.h"
#include "core/object/script_language.h"
#include "core/os/keyboard.h"
#include "core/templates/rb_set.h"
#include "core/variant/typed_array.h"
#include "core/variant/variant_parser.h"
@ -194,7 +193,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 +213,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 +261,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 +305,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(".");
@ -348,7 +353,6 @@ bool ProjectSettings::_get(const StringName &p_name, Variant &r_ret) const {
_THREAD_SAFE_METHOD_
if (!props.has(p_name)) {
WARN_PRINT("Property not found: " + String(p_name));
return false;
}
r_ret = props[p_name].variant;
@ -372,7 +376,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;
@ -436,7 +440,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);
}
@ -468,13 +472,30 @@ void ProjectSettings::_emit_changed() {
emit_signal("settings_changed");
}
bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset) {
bool ProjectSettings::load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset) {
return ProjectSettings::_load_resource_pack(p_pack, p_replace_files, p_offset, false);
}
bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_files, int p_offset, bool p_main_pack) {
if (PackedData::get_singleton()->is_disabled()) {
return false;
}
bool ok = PackedData::get_singleton()->add_pack(p_pack, p_replace_files, p_offset) == OK;
if (p_pack == "res://") {
// Loading the resource directory as a pack source is reserved for internal use only.
return false;
}
if (!p_main_pack && !using_datapack && !OS::get_singleton()->get_resource_dir().is_empty()) {
// Add the project's resource file system to PackedData so directory access keeps working when
// the game is running without a main pack, like in the editor or on Android.
PackedData::get_singleton()->add_pack_source(memnew(PackedSourceDirectory));
PackedData::get_singleton()->add_pack("res://", false, 0);
DirAccess::make_default<DirAccessPack>(DirAccess::ACCESS_RESOURCES);
using_datapack = true;
}
bool ok = PackedData::get_singleton()->add_pack(p_pack, p_replace_files, p_offset) == OK;
if (!ok) {
return false;
}
@ -487,14 +508,17 @@ bool ProjectSettings::_load_resource_pack(const String &p_pack, bool p_replace_f
ResourceUID::get_singleton()->load_from_cache(false);
}
//if data.pck is found, all directory access will be from here
DirAccess::make_default<DirAccessPack>(DirAccess::ACCESS_RESOURCES);
using_datapack = true;
// If the data pack was found, all directory access will be from here.
if (!using_datapack) {
DirAccess::make_default<DirAccessPack>(DirAccess::ACCESS_RESOURCES);
using_datapack = true;
}
return true;
}
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) {
@ -508,6 +532,7 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
}
}
}
#endif // DISABLE_DEPRECATED
}
/*
@ -548,8 +573,8 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// Attempt with a user-defined main pack first
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 + "'.");
bool ok = _load_resource_pack(p_main_pack, false, 0, true);
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) {
@ -567,7 +592,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// and if so, we attempt loading it at the end.
// Attempt with PCK bundled into executable.
bool found = _load_resource_pack(exec_path);
bool found = _load_resource_pack(exec_path, false, 0, true);
// Attempt with exec_name.pck.
// (This is the usual case when distributing a Godot game.)
@ -583,20 +608,20 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
#ifdef MACOS_ENABLED
if (!found) {
// Attempt to load PCK from macOS .app bundle resources.
found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_filename + ".pck"));
found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_basename + ".pck"), false, 0, true) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_filename + ".pck"), false, 0, true);
}
#endif
if (!found) {
// Try to load data pack at the location of the executable.
// As mentioned above, we have two potential names to attempt.
found = _load_resource_pack(exec_dir.path_join(exec_basename + ".pck")) || _load_resource_pack(exec_dir.path_join(exec_filename + ".pck"));
found = _load_resource_pack(exec_dir.path_join(exec_basename + ".pck"), false, 0, true) || _load_resource_pack(exec_dir.path_join(exec_filename + ".pck"), false, 0, true);
}
if (!found) {
// If we couldn't find them next to the executable, we attempt
// the current working directory. Same story, two tests.
found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck");
found = _load_resource_pack(exec_basename + ".pck", false, 0, true) || _load_resource_pack(exec_filename + ".pck", false, 0, true);
}
// If we opened our package, try and load our project.
@ -624,11 +649,33 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
return err;
}
#ifdef MACOS_ENABLED
// Attempt to load project file from macOS .app bundle resources.
resource_path = OS::get_singleton()->get_bundle_resource_dir();
if (!resource_path.is_empty()) {
if (resource_path[resource_path.length() - 1] == '/') {
resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
}
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V_MSG(d.is_null(), ERR_CANT_CREATE, vformat("Cannot create DirAccess for path '%s'.", resource_path));
d->change_dir(resource_path);
Error err;
err = _load_settings_text_or_binary(resource_path.path_join("project.godot"), resource_path.path_join("project.binary"));
if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails.
_load_settings_text(resource_path.path_join("override.cfg"));
return err;
}
}
#endif
// Nothing was found, try to find a project file in provided path (`p_path`)
// 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();
@ -724,7 +771,7 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) {
cs[slen] = 0;
f->get_buffer((uint8_t *)cs.ptr(), slen);
String key;
key.parse_utf8(cs.ptr());
key.parse_utf8(cs.ptr(), slen);
uint32_t vlen = f->get_32();
Vector<uint8_t> d;
@ -732,7 +779,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);
}
@ -774,7 +821,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") {
@ -800,7 +847,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.
@ -808,7 +855,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;
@ -822,17 +869,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++;
}
@ -840,12 +887,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);
}
@ -860,7 +907,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);
@ -873,7 +920,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
if (!p_custom_features.is_empty()) {
// Store how many properties are saved, add one for custom features, which must always go first.
file->store_32(count + 1);
file->store_32(uint32_t(count + 1));
String key = CoreStringName(_custom_features);
file->store_pascal_string(key);
@ -886,12 +933,12 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
err = encode_variant(p_custom_features, buff.ptrw(), len, false);
ERR_FAIL_COND_V(err != OK, err);
file->store_32(len);
file->store_32(uint32_t(len));
file->store_buffer(buff.ptr(), buff.size());
} else {
// Store how many properties are saved.
file->store_32(count);
file->store_32(uint32_t(count));
}
for (const KeyValue<String, List<String>> &E : p_props) {
@ -918,7 +965,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
err = encode_variant(value, buff.ptrw(), len, true);
ERR_FAIL_COND_V_MSG(err != OK, ERR_INVALID_DATA, "Error when trying to encode Variant.");
file->store_32(len);
file->store_32(uint32_t(len));
file->store_buffer(buff.ptr(), buff.size());
}
}
@ -930,7 +977,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,");
@ -1016,7 +1063,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
}
// Check for the existence of a csproj file.
if (_csproj_exists(p_path.get_base_dir())) {
if (_csproj_exists(get_resource_path())) {
// If there is a csproj file, add the C# feature if it doesn't already exist.
if (!project_features.has("C#")) {
project_features.append("C#");
@ -1076,7 +1123,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 = "";
@ -1103,7 +1150,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));
}
}
@ -1168,22 +1215,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) {
@ -1204,10 +1245,10 @@ void ProjectSettings::refresh_global_class_list() {
Array script_classes = get_global_class_list();
for (int i = 0; i < script_classes.size(); i++) {
Dictionary c = script_classes[i];
if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base")) {
if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base") || !c.has("is_abstract") || !c.has("is_tool")) {
continue;
}
ScriptServer::add_global_class(c["class"], c["base"], c["language"], c["path"]);
ScriptServer::add_global_class(c["class"], c["base"], c["language"], c["path"], c["is_abstract"], c["is_tool"]);
}
}
@ -1378,7 +1419,7 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path);
ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path);
ClassDB::bind_method(D_METHOD("save"), &ProjectSettings::save);
ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files", "offset"), &ProjectSettings::_load_resource_pack, DEFVAL(true), DEFVAL(0));
ClassDB::bind_method(D_METHOD("load_resource_pack", "pack", "replace_files", "offset"), &ProjectSettings::load_resource_pack, DEFVAL(true), DEFVAL(0));
ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);
@ -1398,7 +1439,7 @@ void ProjectSettings::_add_builtin_input_map() {
}
Dictionary action;
action["deadzone"] = Variant(0.5f);
action["deadzone"] = Variant(InputMap::DEFAULT_DEADZONE);
action["events"] = events;
String action_name = "input/" + E.key;
@ -1467,15 +1508,12 @@ 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
GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
#ifdef TOOLS_ENABLED
GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor_hint", false);
#endif
GLOBAL_DEF("animation/warnings/check_invalid_track_paths", true);
GLOBAL_DEF("animation/warnings/check_angle_interpolation_type_conflicting", true);
@ -1489,15 +1527,6 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "audio/general/ios/session_category", PROPERTY_HINT_ENUM, "Ambient,Multi Route,Play and Record,Playback,Record,Solo Ambient"), 0);
GLOBAL_DEF("audio/general/ios/mix_with_others", false);
PackedStringArray extensions;
extensions.push_back("gd");
if (ClassDB::class_exists("CSharpScript")) {
extensions.push_back("cs");
}
extensions.push_back("gdshader");
GLOBAL_DEF(PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions"), extensions);
_add_builtin_input_map();
// Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum.
@ -1505,7 +1534,15 @@ 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");
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("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);
#ifdef DISABLE_DEPRECATED
custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Safe:1,Separate");
#else
custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Unsafe (deprecated),Safe,Separate");
#endif
GLOBAL_DEF("physics/2d/run_on_separate_thread", false);
GLOBAL_DEF("physics/3d/run_on_separate_thread", false);
@ -1548,6 +1585,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/block_size_kb", PROPERTY_HINT_RANGE, "4,2048,1,or_greater"), 256);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/max_size_mb", PROPERTY_HINT_RANGE, "1,1024,1,or_greater"), 128);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_upload_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/staging_buffer/texture_download_region_size_px", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
GLOBAL_DEF_RST(PropertyInfo(Variant::BOOL, "rendering/rendering_device/pipeline_cache/enable"), true);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/rendering_device/pipeline_cache/save_chunk_size_mb", PROPERTY_HINT_RANGE, "0.000001,64.0,0.001,or_greater"), 3.0);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/rendering_device/vulkan/max_descriptors_per_pool", PROPERTY_HINT_RANGE, "1,256,1,or_greater"), 64);
@ -1563,13 +1601,18 @@ ProjectSettings::ProjectSettings() {
// installed by the scripts provided in the repository
// (check `misc/scripts/install_d3d12_sdk_windows.py`).
// For example, if the script installs 1.613.3, the default value must be 613.
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/agility_sdk_version"), 613);
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/rendering_device/d3d12/agility_sdk_version", PROPERTY_HINT_RANGE, "0,10000,1,or_greater,hide_slider"), 613);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), 1);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"), 0);
GLOBAL_DEF("collada/use_ambient", false);
// Input settings
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_long_press_as_right_click", false);
GLOBAL_DEF_BASIC("input_devices/pointing/android/enable_pan_and_scale_gestures", false);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "input_devices/pointing/android/rotary_input_scroll_axis", PROPERTY_HINT_ENUM, "Horizontal,Vertical"), 1);
// These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix().
GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());
GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray());
@ -1582,6 +1625,7 @@ ProjectSettings::ProjectSettings() {
ProjectSettings::ProjectSettings(const String &p_path) {
if (load_custom(p_path) == OK) {
resource_path = p_path.get_base_dir();
project_loaded = true;
}
}