summaryrefslogtreecommitdiffstats
path: root/core/config/project_settings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/config/project_settings.cpp')
-rw-r--r--core/config/project_settings.cpp134
1 files changed, 83 insertions, 51 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 7145e628c1..001a351e0b 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -41,7 +41,10 @@
#include "core/os/keyboard.h"
#include "core/variant/variant_parser.h"
#include "core/version.h"
+
+#ifdef TOOLS_ENABLED
#include "modules/modules_enabled.gen.h" // For mono.
+#endif // TOOLS_ENABLED
const String ProjectSettings::PROJECT_DATA_DIR_NAME_SUFFIX = "godot";
@@ -72,9 +75,10 @@ String ProjectSettings::get_safe_project_name() const {
}
String ProjectSettings::get_imported_files_path() const {
- return get_project_data_path().plus_file("imported");
+ return get_project_data_path().path_join("imported");
}
+#ifdef TOOLS_ENABLED
// Returns the features that a project must have when opened with this build of Godot.
// This is used by the project manager to provide the initial_settings for config/features.
const PackedStringArray ProjectSettings::get_required_features() {
@@ -97,10 +101,15 @@ const PackedStringArray ProjectSettings::_get_supported_features() {
features.append(VERSION_BRANCH "." _MKSTR(VERSION_PATCH));
features.append(VERSION_FULL_CONFIG);
features.append(VERSION_FULL_BUILD);
- // For now, assume Vulkan is always supported.
- // This should be removed if it's possible to build the editor without Vulkan.
- features.append("Vulkan Clustered");
- features.append("Vulkan Mobile");
+
+#ifdef VULKAN_ENABLED
+ features.append("Forward Plus");
+ features.append("Mobile");
+#endif
+
+#ifdef GLES3_ENABLED
+ features.append("GL Compatibility");
+#endif
return features;
}
@@ -110,6 +119,10 @@ const PackedStringArray ProjectSettings::get_unsupported_features(const PackedSt
PackedStringArray supported_features = singleton->_get_supported_features();
for (int i = 0; i < p_project_features.size(); i++) {
if (!supported_features.has(p_project_features[i])) {
+ // Temporary compatibility code to ease upgrade to 4.0 beta 2+.
+ if (p_project_features[i].begins_with("Vulkan")) {
+ continue;
+ }
unsupported_features.append(p_project_features[i]);
}
}
@@ -137,6 +150,7 @@ const PackedStringArray ProjectSettings::_trim_to_supported_features(const Packe
features.sort();
return features;
}
+#endif // TOOLS_ENABLED
String ProjectSettings::localize_path(const String &p_path) const {
if (resource_path.is_empty() || p_path.begins_with("res://") || p_path.begins_with("user://") ||
@@ -157,12 +171,12 @@ String ProjectSettings::localize_path(const String &p_path) const {
// in an absolute path that just happens to contain this string but points to a
// different folder (e.g. "/my/project" as resource_path would be contained in
// "/my/project_data", even though the latter is not part of res://.
- // `plus_file("")` is an easy way to ensure we have a trailing '/'.
- const String res_path = resource_path.plus_file("");
+ // `path_join("")` is an easy way to ensure we have a trailing '/'.
+ const String res_path = resource_path.path_join("");
// DirAccess::get_current_dir() is not guaranteed to return a path that with a trailing '/',
// so we must make sure we have it as well in order to compare with 'res_path'.
- cwd = cwd.plus_file("");
+ cwd = cwd.path_join("");
if (!cwd.begins_with(res_path)) {
return p_path;
@@ -442,6 +456,15 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
* If nothing was found, error out.
*/
Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, bool p_upwards, bool p_ignore_override) {
+ if (!OS::get_singleton()->get_resource_dir().is_empty()) {
+ // OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
+ // If the OS would rather use a specific location, then it will not be empty.
+ resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
+ if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') {
+ resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
+ }
+ }
+
// If looking for files in a network client, use it directly
if (FileAccessNetworkClient::get_singleton()) {
@@ -463,7 +486,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
if (err == OK && !p_ignore_override) {
// Load override from location of the main pack
// Optional, we don't mind if it fails
- _load_settings_text(p_main_pack.get_base_dir().plus_file("override.cfg"));
+ _load_settings_text(p_main_pack.get_base_dir().path_join("override.cfg"));
}
return err;
}
@@ -488,17 +511,17 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// We need to test both possibilities as extensions for Linux binaries are optional
// (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck').
-#ifdef OSX_ENABLED
+#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().plus_file(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_filename + ".pck"));
+ 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"));
}
#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.plus_file(exec_basename + ".pck")) || _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck"));
+ found = _load_resource_pack(exec_dir.path_join(exec_basename + ".pck")) || _load_resource_pack(exec_dir.path_join(exec_filename + ".pck"));
}
if (!found) {
@@ -511,9 +534,10 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
if (found) {
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK && !p_ignore_override) {
- // Load override from location of the executable.
- // Optional, we don't mind if it fails.
- _load_settings_text(exec_path.get_base_dir().plus_file("override.cfg"));
+ // Load overrides from the PCK and the executable location.
+ // Optional, we don't mind if either fails.
+ _load_settings_text("res://override.cfg");
+ _load_settings_text(exec_path.get_base_dir().path_join("override.cfg"));
}
return err;
}
@@ -523,13 +547,6 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// (Only Android -when reading from pck- and iOS use this.)
if (!OS::get_singleton()->get_resource_dir().is_empty()) {
- // OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
- // If the OS would rather use a specific location, then it will not be empty.
- resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
- if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') {
- resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
- }
-
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails.
@@ -553,10 +570,10 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// Set the resource path early so things can be resolved when loading.
resource_path = current_dir;
resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
- err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
+ err = _load_settings_text_or_binary(current_dir.path_join("project.godot"), current_dir.path_join("project.binary"));
if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails.
- _load_settings_text(current_dir.plus_file("override.cfg"));
+ _load_settings_text(current_dir.path_join("override.cfg"));
found = true;
break;
}
@@ -682,7 +699,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
// If we're loading a project.godot from source code, we can operate some
// ProjectSettings conversions if need be.
_convert_to_last_version(config_version);
- last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+ 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.");
@@ -761,14 +778,14 @@ void ProjectSettings::clear(const String &p_name) {
}
Error ProjectSettings::save() {
- Error error = save_custom(get_resource_path().plus_file("project.godot"));
+ Error error = save_custom(get_resource_path().path_join("project.godot"));
if (error == OK) {
- last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+ last_save_time = FileAccess::get_modified_time(get_resource_path().path_join("project.godot"));
}
return error;
}
-Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
+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 + ".");
@@ -778,7 +795,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
int count = 0;
- for (const KeyValue<String, List<String>> &E : props) {
+ for (const KeyValue<String, List<String>> &E : p_props) {
count += E.value.size();
}
@@ -804,7 +821,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
file->store_32(count); //store how many properties are saved
}
- for (const KeyValue<String, List<String>> &E : props) {
+ for (const KeyValue<String, List<String>> &E : p_props) {
for (const String &key : E.value) {
String k = key;
if (!E.key.is_empty()) {
@@ -836,7 +853,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
return OK;
}
-Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
+Error ProjectSettings::_save_settings_text(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);
@@ -857,8 +874,8 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<Str
}
file->store_string("\n");
- for (const KeyValue<String, List<String>> &E : props) {
- if (E.key != props.begin()->key) {
+ for (const KeyValue<String, List<String>> &E : p_props) {
+ if (E.key != p_props.begin()->key) {
file->store_string("\n");
}
@@ -894,13 +911,14 @@ Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other par
Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features, bool p_merge_with_current) {
ERR_FAIL_COND_V_MSG(p_path.is_empty(), ERR_INVALID_PARAMETER, "Project settings save path cannot be empty.");
+#ifdef TOOLS_ENABLED
PackedStringArray project_features = get_setting("application/config/features");
// If there is no feature list currently present, force one to generate.
if (project_features.is_empty()) {
project_features = ProjectSettings::get_required_features();
}
// Check the rendering API.
- const String rendering_api = has_setting("rendering/quality/driver/driver_name") ? (String)get_setting("rendering/quality/driver/driver_name") : String();
+ const String rendering_api = has_setting("rendering/renderer/rendering_method") ? (String)get_setting("rendering/renderer/rendering_method") : String();
if (!rendering_api.is_empty()) {
// Add the rendering API as a project feature if it doesn't already exist.
if (!project_features.has(rendering_api)) {
@@ -908,7 +926,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
}
// Check for the existence of a csproj file.
- if (FileAccess::exists(get_resource_path().plus_file(get_safe_project_name() + ".csproj"))) {
+ if (FileAccess::exists(get_resource_path().path_join(get_safe_project_name() + ".csproj"))) {
// 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#");
@@ -921,6 +939,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
project_features = _trim_to_supported_features(project_features);
set_setting("application/config/features", project_features);
+#endif // TOOLS_ENABLED
RBSet<_VCSort> vclist;
@@ -961,7 +980,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
vclist.insert(vc);
}
- RBMap<String, List<String>> props;
+ RBMap<String, List<String>> save_props;
for (const _VCSort &E : vclist) {
String category = E.name;
@@ -975,24 +994,24 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
category = category.substr(0, div);
name = name.substr(div + 1, name.size());
}
- props[category].push_back(name);
+ save_props[category].push_back(name);
}
- String custom_features;
+ String save_features;
for (int i = 0; i < p_custom_features.size(); i++) {
if (i > 0) {
- custom_features += ",";
+ save_features += ",";
}
String f = p_custom_features[i].strip_edges().replace("\"", "");
- custom_features += f;
+ save_features += f;
}
if (p_path.ends_with(".godot") || p_path.ends_with("override.cfg")) {
- return _save_settings_text(p_path, props, p_custom, custom_features);
+ return _save_settings_text(p_path, save_props, p_custom, save_features);
} else if (p_path.ends_with(".binary")) {
- return _save_settings_binary(p_path, props, p_custom, custom_features);
+ 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 + ".");
}
@@ -1069,7 +1088,7 @@ bool ProjectSettings::is_using_datapack() const {
return using_datapack;
}
-bool ProjectSettings::property_can_revert(const String &p_name) {
+bool ProjectSettings::_property_can_revert(const StringName &p_name) const {
if (!props.has(p_name)) {
return false;
}
@@ -1077,12 +1096,13 @@ bool ProjectSettings::property_can_revert(const String &p_name) {
return props[p_name].initial != props[p_name].variant;
}
-Variant ProjectSettings::property_get_revert(const String &p_name) {
+bool ProjectSettings::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (!props.has(p_name)) {
- return Variant();
+ return false;
}
- return props[p_name].initial;
+ r_property = props[p_name].initial;
+ return true;
}
void ProjectSettings::set_setting(const String &p_setting, const Variant &p_value) {
@@ -1128,13 +1148,12 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order);
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value);
ClassDB::bind_method(D_METHOD("add_property_info", "hint"), &ProjectSettings::_add_property_info_bind);
+ ClassDB::bind_method(D_METHOD("set_restart_if_changed", "name", "restart"), &ProjectSettings::set_restart_if_changed);
ClassDB::bind_method(D_METHOD("clear", "name"), &ProjectSettings::clear);
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("property_can_revert", "name"), &ProjectSettings::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &ProjectSettings::property_get_revert);
ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);
}
@@ -1182,21 +1201,34 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/config/custom_user_dir_name", "");
GLOBAL_DEF("application/config/project_settings_override", "");
- GLOBAL_DEF_BASIC("display/window/size/viewport_width", 1024);
+ // The default window size is tuned to:
+ // - Have a 16:9 aspect ratio,
+ // - Have both dimensions divisible by 8 to better play along with video recording,
+ // - Be displayable correctly in windowed mode on a 1366×768 display (tested on Windows 10 with default settings).
+ GLOBAL_DEF_BASIC("display/window/size/viewport_width", 1152);
custom_prop_info["display/window/size/viewport_width"] = PropertyInfo(Variant::INT, "display/window/size/viewport_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
- GLOBAL_DEF_BASIC("display/window/size/viewport_height", 600);
+ GLOBAL_DEF_BASIC("display/window/size/viewport_height", 648);
custom_prop_info["display/window/size/viewport_height"] = PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+ GLOBAL_DEF_BASIC("display/window/size/mode", 0);
+ custom_prop_info["display/window/size/mode"] = PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen");
+
GLOBAL_DEF_BASIC("display/window/size/resizable", true);
GLOBAL_DEF_BASIC("display/window/size/borderless", false);
- GLOBAL_DEF_BASIC("display/window/size/fullscreen", false);
GLOBAL_DEF("display/window/size/always_on_top", false);
+ 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/window_width_override", 0);
custom_prop_info["display/window/size/window_width_override"] = PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
GLOBAL_DEF("display/window/size/window_height_override", 0);
custom_prop_info["display/window/size/window_height_override"] = PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+ GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
+ GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor", false);
+
GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres");
custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
GLOBAL_DEF_RST("audio/general/2d_panning_strength", 1.0f);