summaryrefslogtreecommitdiff
path: root/core/project_settings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/project_settings.cpp')
-rw-r--r--core/project_settings.cpp248
1 files changed, 160 insertions, 88 deletions
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 146b4870e8..407bb78375 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -30,16 +30,17 @@
#include "project_settings.h"
-#include "bind/core_bind.h"
-#include "core_string_names.h"
-#include "io/file_access_network.h"
-#include "io/file_access_pack.h"
-#include "io/marshalls.h"
-#include "os/dir_access.h"
-#include "os/file_access.h"
-#include "os/keyboard.h"
-#include "os/os.h"
-#include "variant_parser.h"
+#include "core/bind/core_bind.h"
+#include "core/core_string_names.h"
+#include "core/io/file_access_network.h"
+#include "core/io/file_access_pack.h"
+#include "core/io/marshalls.h"
+#include "core/os/dir_access.h"
+#include "core/os/file_access.h"
+#include "core/os/keyboard.h"
+#include "core/os/os.h"
+#include "core/variant_parser.h"
+
#include <zlib.h>
#define FORMAT_VERSION 4
@@ -59,7 +60,7 @@ String ProjectSettings::get_resource_path() const {
String ProjectSettings::localize_path(const String &p_path) const {
if (resource_path == "")
- return p_path; //not initialied yet
+ return p_path; //not initialized yet
if (p_path.begins_with("res://") || p_path.begins_with("user://") ||
(p_path.is_abs_path() && !p_path.begins_with(resource_path)))
@@ -191,7 +192,7 @@ bool ProjectSettings::_get(const StringName &p_name, Variant &r_ret) const {
name = feature_overrides[name];
}
if (!props.has(name)) {
- print_line("WARNING: not found: " + String(name));
+ WARN_PRINTS("Property not found: " + String(name));
return false;
}
r_ret = props[name].variant;
@@ -287,9 +288,28 @@ void ProjectSettings::_convert_to_last_version() {
}
}
+/*
+ * This method is responsible for loading a project.godot file and/or data file
+ * using the following merit order:
+ * - If using NetworkClient, try to lookup project file or fail.
+ * - If --main-pack was passed by the user (`p_main_pack`), load it or fail.
+ * - Search for .pck file matching binary name. There are two possibilities:
+ * o exec_path.get_basename() + '.pck' (e.g. 'win_game.exe' -> 'win_game.pck')
+ * o exec_path + '.pck' (e.g. 'linux_game' -> 'linux_game.pck')
+ * For each tentative, if the file exists, load it or fail.
+ * - On relevant platforms (Android/iOS), lookup project file in OS resource path.
+ * If found, load it or fail.
+ * - Lookup project file in passed `p_path` (--path passed by the user), i.e. we
+ * are running from source code.
+ * If not found and `p_upwards` is true (--upwards passed by the user), look for
+ * project files in parent folders up to the system root (used to run a game
+ * from command line while in a subfolder).
+ * If a project file is found, load it or fail.
+ * If nothing was found, error out.
+ */
Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards) {
- //If looking for files in network, just use network!
+ // If looking for files in a network client, use it directly
if (FileAccessNetworkClient::get_singleton()) {
@@ -301,9 +321,7 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
return err;
}
- String exec_path = OS::get_singleton()->get_executable_path();
-
- //Attempt with a passed main pack first
+ // Attempt with a user-defined main pack first
if (p_main_pack != "") {
@@ -319,25 +337,39 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
return err;
}
- //Attempt with execname.pck
+ // Attempt with exec_name.pck
+ // (This is the usual case when distributing a Godot game.)
+
+ // Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle)
+ // or the exec path's basename + '.pck' (Windows).
+ // 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').
+
+ String exec_path = OS::get_singleton()->get_executable_path();
+
if (exec_path != "") {
bool found = false;
- // get our filename without our path (note, using exec_path.get_file before get_basename anymore because not all file systems have dots in their file names!)
- String filebase_name = exec_path.get_file().get_basename();
+ String exec_dir = exec_path.get_base_dir();
+ String exec_filename = exec_path.get_file();
+ String exec_basename = exec_filename.get_basename();
+
+ // Try to load data pack at the location of the executable
+ // As mentioned above, we have two potential names to attempt
- // try to open at the location of executable
- String datapack_name = exec_path.get_base_dir().plus_file(filebase_name) + ".pck";
- if (_load_resource_pack(datapack_name)) {
+ if (_load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) ||
+ _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck"))) {
found = true;
} else {
- datapack_name = filebase_name + ".pck";
- if (_load_resource_pack(datapack_name)) {
+ // If we couldn't find them next to the executable, we attempt
+ // the current working directory. Same story, two tests.
+ if (_load_resource_pack(exec_basename + ".pck") ||
+ _load_resource_pack(exec_filename + ".pck")) {
found = true;
}
}
- // if we opened our package, try and load our project...
+ // If we opened our package, try and load our project
if (found) {
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK) {
@@ -349,17 +381,15 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
}
}
- //Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this)
- if (OS::get_singleton()->get_resource_dir() != "") {
- //OS will call Globals->get_resource_path which will be empty if not overridden!
- //if the OS would rather use somewhere else, then it will not be empty.
+ // Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this)
+ if (OS::get_singleton()->get_resource_dir() != "") {
+ // 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.length() && resource_path[resource_path.length() - 1] == '/')
+ if (resource_path != "" && resource_path[resource_path.length() - 1] == '/') {
resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
-
- // data.pck and data.zip are deprecated and no longer supported, apologies.
- // make sure this is loaded from the resource path
+ }
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK) {
@@ -370,21 +400,19 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
return err;
}
- //Nothing was found, try to find a project.godot somewhere!
+ // Nothing was found, try to find a project file in provided path (`p_path`)
+ // or, if requested (`p_upwards`) in parent directories.
DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!d, ERR_CANT_CREATE);
-
d->change_dir(p_path);
- String candidate = d->get_current_dir();
String current_dir = d->get_current_dir();
-
+ String candidate = current_dir;
bool found = false;
Error err;
while (true) {
-
err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
if (err == OK) {
// Optional, we don't mind if it fails
@@ -395,10 +423,10 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
}
if (p_upwards) {
- // Try to load settings ascending through dirs shape!
+ // Try to load settings ascending through parent directories
d->change_dir("..");
if (d->get_current_dir() == current_dir)
- break; //not doing anything useful
+ break; // not doing anything useful
current_dir = d->get_current_dir();
} else {
break;
@@ -415,6 +443,8 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
if (resource_path.length() && resource_path[resource_path.length() - 1] == '/')
resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
+ // If we're loading a project.godot from source code, we can operate some
+ // ProjectSettings conversions if need be.
_convert_to_last_version();
return OK;
@@ -953,7 +983,8 @@ ProjectSettings::ProjectSettings() {
disable_feature_overrides = false;
registering_order = true;
- Array va;
+ Array events;
+ Dictionary action;
Ref<InputEventKey> key;
Ref<InputEventJoypadButton> joyb;
@@ -965,122 +996,162 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/config/use_custom_user_dir", false);
GLOBAL_DEF("application/config/custom_user_dir_name", "");
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_ENTER);
- va.push_back(key);
+ events.push_back(key);
key.instance();
key->set_scancode(KEY_KP_ENTER);
- va.push_back(key);
+ events.push_back(key);
key.instance();
key->set_scancode(KEY_SPACE);
- va.push_back(key);
+ events.push_back(key);
joyb.instance();
joyb->set_button_index(JOY_BUTTON_0);
- va.push_back(joyb);
- GLOBAL_DEF("input/ui_accept", va);
+ events.push_back(joyb);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_accept", action);
input_presets.push_back("input/ui_accept");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_SPACE);
- va.push_back(key);
+ events.push_back(key);
joyb.instance();
joyb->set_button_index(JOY_BUTTON_3);
- va.push_back(joyb);
- GLOBAL_DEF("input/ui_select", va);
+ events.push_back(joyb);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_select", action);
input_presets.push_back("input/ui_select");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_ESCAPE);
- va.push_back(key);
+ events.push_back(key);
joyb.instance();
joyb->set_button_index(JOY_BUTTON_1);
- va.push_back(joyb);
- GLOBAL_DEF("input/ui_cancel", va);
+ events.push_back(joyb);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_cancel", action);
input_presets.push_back("input/ui_cancel");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_TAB);
- va.push_back(key);
- GLOBAL_DEF("input/ui_focus_next", va);
+ events.push_back(key);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_focus_next", action);
input_presets.push_back("input/ui_focus_next");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_TAB);
key->set_shift(true);
- va.push_back(key);
- GLOBAL_DEF("input/ui_focus_prev", va);
+ events.push_back(key);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_focus_prev", action);
input_presets.push_back("input/ui_focus_prev");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_LEFT);
- va.push_back(key);
+ events.push_back(key);
joyb.instance();
joyb->set_button_index(JOY_DPAD_LEFT);
- va.push_back(joyb);
- GLOBAL_DEF("input/ui_left", va);
+ events.push_back(joyb);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_left", action);
input_presets.push_back("input/ui_left");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_RIGHT);
- va.push_back(key);
+ events.push_back(key);
joyb.instance();
joyb->set_button_index(JOY_DPAD_RIGHT);
- va.push_back(joyb);
- GLOBAL_DEF("input/ui_right", va);
+ events.push_back(joyb);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_right", action);
input_presets.push_back("input/ui_right");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_UP);
- va.push_back(key);
+ events.push_back(key);
joyb.instance();
joyb->set_button_index(JOY_DPAD_UP);
- va.push_back(joyb);
- GLOBAL_DEF("input/ui_up", va);
+ events.push_back(joyb);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_up", action);
input_presets.push_back("input/ui_up");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_DOWN);
- va.push_back(key);
+ events.push_back(key);
joyb.instance();
joyb->set_button_index(JOY_DPAD_DOWN);
- va.push_back(joyb);
- GLOBAL_DEF("input/ui_down", va);
+ events.push_back(joyb);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_down", action);
input_presets.push_back("input/ui_down");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_PAGEUP);
- va.push_back(key);
- GLOBAL_DEF("input/ui_page_up", va);
+ events.push_back(key);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_page_up", action);
input_presets.push_back("input/ui_page_up");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_PAGEDOWN);
- va.push_back(key);
- GLOBAL_DEF("input/ui_page_down", va);
+ events.push_back(key);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_page_down", action);
input_presets.push_back("input/ui_page_down");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_HOME);
- va.push_back(key);
- GLOBAL_DEF("input/ui_home", va);
+ events.push_back(key);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_home", action);
input_presets.push_back("input/ui_home");
- va = Array();
+ action = Dictionary();
+ action["deadzone"] = Variant(0.5f);
+ events = Array();
key.instance();
key->set_scancode(KEY_END);
- va.push_back(key);
- GLOBAL_DEF("input/ui_end", va);
+ events.push_back(key);
+ action["events"] = events;
+ GLOBAL_DEF("input/ui_end", action);
input_presets.push_back("input/ui_end");
//GLOBAL_DEF("display/window/handheld/orientation", "landscape");
@@ -1091,6 +1162,7 @@ ProjectSettings::ProjectSettings() {
custom_prop_info["rendering/quality/intended_usage/framebuffer_allocation"] = PropertyInfo(Variant::INT, "rendering/quality/intended_usage/framebuffer_allocation", PROPERTY_HINT_ENUM, "2D,2D Without Sampling,3D,3D Without Effects");
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
+ custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1");
//assigning here, because using GLOBAL_GET on every block for compressing can be slow
Compression::zstd_long_distance_matching = GLOBAL_DEF("compression/formats/zstd/long_distance_matching", false);