Use .godot as file extension for project files.

Now project files don't have to be named "godot.cfg" anymore, they can have any name so as long as it ends with *.godot.
Also godot will automatically start the editor now if launched with a project file as an argument.
This allows for double-clicking of projects to open them :)

Code-wise this should be complete, but there's still work to do:

- Make a nice icon for godot projects.
- Work on installers/packaging -> register the extension and icon with godot.
- Update the 2.1 to 3.0 exporter.

Tested on linux and windows so far.
This commit is contained in:
Andreas Haas 2017-04-16 10:17:24 +02:00
parent e46af1e236
commit c06a2db63a
No known key found for this signature in database
GPG key ID: B5FFAE1B65FBD2E1
7 changed files with 148 additions and 45 deletions

View file

@ -53,6 +53,11 @@ String GlobalConfig::get_resource_path() const {
return resource_path;
};
String GlobalConfig::get_project_file_name() const {
return project_file_name;
}
String GlobalConfig::localize_path(const String &p_path) const {
if (resource_path == "")
@ -236,13 +241,43 @@ bool GlobalConfig::_load_resource_pack(const String &p_pack) {
return true;
}
static String _find_project_file(DirAccess *p_diraccess, bool p_res = false) {
p_diraccess->list_dir_begin();
String ret = "";
while (true) {
bool isdir;
String file = p_diraccess->get_next(&isdir);
if (file == "")
break;
if (!isdir) {
if (file.get_extension() == "godot") {
if (p_res) {
ret = "res://" + file;
} else {
ret = p_diraccess->get_current_dir() + "/" + file;
}
}
}
}
p_diraccess->list_dir_end();
return ret;
}
static String _find_project_file() {
DirAccess *dir = DirAccess::create(DirAccess::ACCESS_RESOURCES);
String ret = _find_project_file(dir, true);
memdelete(dir);
return ret;
}
Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) {
//If looking for files in network, just use network!
if (FileAccessNetworkClient::get_singleton()) {
if (_load_settings("res://godot.cfg") == OK || _load_settings_binary("res://godot.cfb") == OK) {
String gdproj = _find_project_file();
if (_load_settings(gdproj) == OK || _load_settings_binary("res://godot.cfb") == OK) {
_load_settings("res://override.cfg");
}
@ -258,8 +293,8 @@ Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) {
bool ok = _load_resource_pack(p_main_pack);
ERR_FAIL_COND_V(!ok, ERR_CANT_OPEN);
if (_load_settings("res://godot.cfg") == OK || _load_settings_binary("res://godot.cfb") == OK) {
String gdproj = _find_project_file();
if (_load_settings(gdproj) == OK || _load_settings_binary("res://godot.cfb") == OK) {
//load override from location of the main pack
_load_settings(p_main_pack.get_base_dir().plus_file("override.cfg"));
}
@ -272,7 +307,8 @@ Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) {
if (_load_resource_pack(exec_path.get_basename() + ".pck")) {
if (_load_settings("res://godot.cfg") == OK || _load_settings_binary("res://godot.cfb") == OK) {
String gdproj = _find_project_file();
if (_load_settings(gdproj) == OK || _load_settings_binary("res://godot.cfb") == OK) {
//load override from location of executable
_load_settings(exec_path.get_base_dir().plus_file("override.cfg"));
}
@ -292,15 +328,15 @@ Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) {
// data.pck and data.zip are deprecated and no longer supported, apologies.
// make sure this is loaded from the resource path
if (_load_settings("res://godot.cfg") == OK || _load_settings_binary("res://godot.cfb") == OK) {
String gdproj = _find_project_file();
if (_load_settings(gdproj) == OK || _load_settings_binary("res://godot.cfb") == OK) {
_load_settings("res://override.cfg");
}
return OK;
}
//Nothing was found, try to find a godot.cfg somewhere!
//Nothing was found, try to find a *.godot somewhere!
DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!d, ERR_CANT_CREATE);
@ -313,8 +349,8 @@ Error GlobalConfig::setup(const String &p_path, const String &p_main_pack) {
while (true) {
//try to load settings in ascending through dirs shape!
if (_load_settings(current_dir + "/godot.cfg") == OK || _load_settings_binary(current_dir + "/godot.cfb") == OK) {
String gdproj = _find_project_file(d);
if (_load_settings(gdproj) == OK || _load_settings_binary(current_dir + "/godot.cfb") == OK) {
_load_settings(current_dir + "/override.cfg");
candidate = current_dir;
@ -428,6 +464,7 @@ Error GlobalConfig::_load_settings(const String p_path) {
err = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, NULL, true);
if (err == ERR_FILE_EOF) {
memdelete(f);
project_file_name = p_path.get_file();
return OK;
} else if (err != OK) {
ERR_PRINTS("GlobalConfig::load - " + p_path + ":" + itos(lines) + " error: " + error_text);
@ -449,6 +486,7 @@ Error GlobalConfig::_load_settings(const String p_path) {
}
}
project_file_name = p_path.get_file();
memdelete(f);
return OK;
@ -474,7 +512,12 @@ void GlobalConfig::clear(const String &p_name) {
Error GlobalConfig::save() {
return save_custom(get_resource_path() + "/godot.cfg");
if (project_file_name.empty()) {
String name = ((String)get("application/name")).replace(" ", "_");
return save_custom(get_resource_path() + "/" + name + ".godot");
} else {
return save_custom(get_resource_path() + "/" + project_file_name);
}
}
Error GlobalConfig::_save_settings_binary(const String &p_file, const Map<String, List<String> > &props, const CustomMap &p_custom) {
@ -483,7 +526,7 @@ Error GlobalConfig::_save_settings_binary(const String &p_file, const Map<String
FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
if (err != OK) {
ERR_EXPLAIN("Coudln't save godot.cfb at " + p_file);
ERR_EXPLAIN("Couldn't save godot.cfb at " + p_file);
ERR_FAIL_COND_V(err, err)
}
@ -548,7 +591,7 @@ Error GlobalConfig::_save_settings_text(const String &p_file, const Map<String,
FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
if (err) {
ERR_EXPLAIN("Coudln't save godot.cfg - " + p_file);
ERR_EXPLAIN("Couldn't save project file - " + p_file);
ERR_FAIL_COND_V(err, err)
}
@ -828,6 +871,7 @@ void GlobalConfig::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear", "name"), &GlobalConfig::clear);
ClassDB::bind_method(D_METHOD("localize_path", "path"), &GlobalConfig::localize_path);
ClassDB::bind_method(D_METHOD("globalize_path", "path"), &GlobalConfig::globalize_path);
ClassDB::bind_method(D_METHOD("get_project_file_name"), &GlobalConfig::get_project_file_name);
ClassDB::bind_method(D_METHOD("save"), &GlobalConfig::save);
ClassDB::bind_method(D_METHOD("has_singleton", "name"), &GlobalConfig::has_singleton);
ClassDB::bind_method(D_METHOD("get_singleton", "name"), &GlobalConfig::get_singleton_object);

View file

@ -111,6 +111,8 @@ protected:
void _add_property_info_bind(const Dictionary &p_info);
String project_file_name;
protected:
static void _bind_methods();
@ -124,6 +126,7 @@ public:
Variant property_get_revert(const String &p_name);
String get_resource_path() const;
String get_project_file_name() const;
static GlobalConfig *get_singleton();

View file

@ -16414,7 +16414,7 @@
Contains global variables accessible from everywhere.
</brief_description>
<description>
Contains global variables accessible from everywhere. Use the normal [Object] API, such as "Globals.get(variable)", "Globals.set(variable,value)" or "Globals.has(variable)" to access them. Variables stored in godot.cfg are also loaded into globals, making this object very useful for reading custom game configuration options.
Contains global variables accessible from everywhere. Use the normal [Object] API, such as "Globals.get(variable)", "Globals.set(variable,value)" or "Globals.has(variable)" to access them. Variables stored in the project file (*.godot) are also loaded into globals, making this object very useful for reading custom game configuration options.
</description>
<methods>
<method name="add_property_info">

View file

@ -487,6 +487,22 @@ bool EditorFileSystem::_check_missing_imported_files(const String &p_path) {
return true;
}
static bool _find_project(const String &p_path) {
DirAccess *dir_access = DirAccess::create_for_path(p_path);
bool ret = false;
while (true) {
bool is_dir;
String file = dir_access->get_next(&is_dir);
if (file == "")
break;
if (file.ends_with(".godot")) {
ret = true;
}
}
memdelete(dir_access);
return ret;
}
void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess *da, const ScanProgress &p_progress) {
List<String> dirs;
@ -509,8 +525,9 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
if (f.begins_with(".")) //ignore hidden and . / ..
continue;
if (FileAccess::exists(cd.plus_file(f).plus_file("godot.cfg"))) // skip if another project inside this
if (_find_project(cd.plus_file(f))) {
continue;
}
dirs.push_back(f);
@ -676,34 +693,35 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
while (true) {
bool isdir;
String f = da->get_next(&isdir);
if (f == "")
String file = da->get_next(&isdir);
if (file == "")
break;
if (isdir) {
if (f.begins_with(".")) //ignore hidden and . / ..
if (file.begins_with(".")) //ignore hidden and . / ..
continue;
int idx = p_dir->find_dir_index(f);
int idx = p_dir->find_dir_index(file);
if (idx == -1) {
if (FileAccess::exists(cd.plus_file(f).plus_file("godot.cfg"))) // skip if another project inside this
if (_find_project(cd.plus_file(file))) {
continue;
}
EditorFileSystemDirectory *efd = memnew(EditorFileSystemDirectory);
efd->parent = p_dir;
efd->name = f;
efd->name = file;
DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
d->change_dir(cd.plus_file(f));
d->change_dir(cd.plus_file(file));
_scan_new_dir(efd, d, p_progress.get_sub(1, 1));
memdelete(d);
ItemAction ia;
ia.action = ItemAction::ACTION_DIR_ADD;
ia.dir = p_dir;
ia.file = f;
ia.file = file;
ia.new_dir = efd;
scan_actions.push_back(ia);
} else {
@ -711,16 +729,16 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
}
} else {
String ext = f.get_extension().to_lower();
String ext = file.get_extension().to_lower();
if (!valid_extensions.has(ext))
continue; //invalid
int idx = p_dir->find_file_index(f);
int idx = p_dir->find_file_index(file);
if (idx == -1) {
//never seen this file, add actition to add it
EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
fi->file = f;
fi->file = file;
String path = cd.plus_file(fi->file);
fi->modified_time = FileAccess::get_modified_time(path);
@ -731,7 +749,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
ItemAction ia;
ia.action = ItemAction::ACTION_FILE_ADD;
ia.dir = p_dir;
ia.file = f;
ia.file = file;
ia.new_file = fi;
scan_actions.push_back(ia);
}
@ -739,14 +757,14 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
if (import_extensions.has(ext)) {
//if it can be imported, and it was added, it needs to be reimported
print_line("REIMPORT: file was not found before, reimport");
print_line("at dir: " + p_dir->get_path() + " file: " + f);
print_line("at dir: " + p_dir->get_path() + " file: " + file);
for (int i = 0; i < p_dir->files.size(); i++) {
print_line(itos(i) + ": " + p_dir->files[i]->file);
}
ItemAction ia;
ia.action = ItemAction::ACTION_FILE_REIMPORT;
ia.dir = p_dir;
ia.file = f;
ia.file = file;
scan_actions.push_back(ia);
}

View file

@ -50,6 +50,19 @@
#include "scene/gui/tool_button.h"
#include "version.h"
static String _find_project_file(DirAccess *p_da) {
p_da->list_dir_begin();
while (true) {
String f = p_da->get_next();
if (f == "")
break;
if (f.get_extension() == "godot")
return p_da->get_current_dir() + "/" + f;
}
p_da->list_dir_end();
return "";
}
class NewProjectDialog : public ConfirmationDialog {
GDCLASS(NewProjectDialog, ConfirmationDialog);
@ -92,18 +105,18 @@ private:
if (mode != MODE_IMPORT) {
if (d->file_exists("godot.cfg")) {
if (_find_project_file(d) != "") {
error->set_text(TTR("Invalid project path, godot.cfg must not exist."));
error->set_text(TTR("Invalid project path, *.godot must not exist."));
memdelete(d);
return "";
}
} else {
if (valid_path != "" && !d->file_exists("godot.cfg")) {
if (valid_path != "" && _find_project_file(d) == "") {
error->set_text(TTR("Invalid project path, godot.cfg must exist."));
error->set_text(TTR("Invalid project path, *.godot must exist."));
memdelete(d);
return "";
}
@ -136,7 +149,7 @@ private:
String p = p_path;
if (mode == MODE_IMPORT) {
if (p.ends_with("godot.cfg")) {
if (p.get_extension() == "godot") {
p = p.get_base_dir();
}
@ -162,7 +175,7 @@ private:
fdialog->set_mode(FileDialog::MODE_OPEN_FILE);
fdialog->clear_filters();
fdialog->add_filter("godot.cfg ; " _MKSTR(VERSION_NAME) " Project");
fdialog->add_filter("*.godot ; " _MKSTR(VERSION_NAME) " Project");
} else {
fdialog->set_mode(FileDialog::MODE_OPEN_DIR);
}
@ -186,9 +199,9 @@ private:
} else {
if (mode == MODE_NEW) {
FileAccess *f = FileAccess::open(dir.plus_file("/godot.cfg"), FileAccess::WRITE);
FileAccess *f = FileAccess::open(dir.plus_file("/" + project_name->get_text().replace(" ", "_") + ".godot"), FileAccess::WRITE);
if (!f) {
error->set_text(TTR("Couldn't create godot.cfg in project path."));
error->set_text(TTR("Couldn't create *.godot project file in project path."));
} else {
f->store_line("; Engine configuration file.");
@ -741,10 +754,17 @@ void ProjectManager::_load_recent_projects() {
continue;
String project = _name.get_slice("/", 1);
String conf = path.plus_file("godot.cfg");
DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (dir_access->change_dir(path) != OK) {
EditorSettings::get_singleton()->erase(_name);
continue;
}
String conf = _find_project_file(dir_access);
memdelete(dir_access);
bool favorite = (_name.begins_with("favorite_projects/")) ? true : false;
uint64_t last_modified = 0;
if (FileAccess::exists(conf)) {
last_modified = FileAccess::get_modified_time(conf);
@ -1006,7 +1026,7 @@ void ProjectManager::_scan_dir(DirAccess *da, float pos, float total, List<Strin
while (n != String()) {
if (da->current_is_dir() && !n.begins_with(".")) {
subdirs.push_front(n);
} else if (n == "godot.cfg") {
} else if (n.get_extension() == "godot") {
r_projects->push_back(da->get_current_dir());
}
n = da->get_next();
@ -1117,7 +1137,7 @@ void ProjectManager::_files_dropped(PoolStringArray p_files, int p_screen) {
dir->list_dir_begin();
String file = dir->get_next();
while (confirm && file != String()) {
if (!dir->current_is_dir() && file.ends_with("godot.cfg")) {
if (!dir->current_is_dir() && file.get_extension() == "godot") {
confirm = false;
}
file = dir->get_next();

View file

@ -1168,7 +1168,8 @@ void ProjectSettings::_bind_methods() {
ProjectSettings::ProjectSettings(EditorData *p_data) {
singleton = this;
set_title(TTR("Project Settings (godot.cfg)"));
String project_file = "(" + GlobalConfig::get_singleton()->get_project_file_name() + ")";
set_title(TTR("Project Settings " + project_file));
set_resizable(true);
undo_redo = &p_data->get_undo_redo();
data = p_data;

View file

@ -129,7 +129,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(VERSION_FULL_NAME " (c) 2008-2017 Juan Linietsky, Ariel Manzur.\n");
OS::get_singleton()->print("Usage: %s [options] [scene]\n", p_binary);
OS::get_singleton()->print("Options:\n");
OS::get_singleton()->print("\t-path [dir] : Path to a game, containing godot.cfg\n");
OS::get_singleton()->print("\t-path [dir] : Path to a game, containing *.godot\n");
#ifdef TOOLS_ENABLED
OS::get_singleton()->print("\t-e,-editor : Bring up the editor instead of running the scene.\n");
#endif
@ -447,6 +447,23 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
} else {
goto error;
}
} else if (I->get().ends_with(".godot")) {
String path;
String file = I->get();
int sep = MAX(file.find_last("/"), file.find_last("\\"));
if (sep == -1)
path = ".";
else {
path = file.substr(0, sep);
}
if (OS::get_singleton()->set_cwd(path) == OK) {
} else {
game_path = path;
}
#ifdef TOOLS_ENABLED
editor = true;
#endif
} else if (I->get() == "-bp") { // /breakpoints
if (I->next()) {
@ -673,7 +690,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
else
input_map->load_from_globals(); //keys for game
if (video_driver == "") // specified in godot.cfg
if (video_driver == "") // specified in *.godot
video_driver = GLOBAL_DEF("display/driver/name", Variant((const char *)OS::get_singleton()->get_video_driver_name(0)));
if (!force_res && use_custom_res && globals->has("display/window/width"))
@ -725,7 +742,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
/* Determine Video Driver */
if (audio_driver == "") { // specified in godot.cfg
if (audio_driver == "") { // specified in *.godot
audio_driver = GLOBAL_DEF("audio/driver", OS::get_singleton()->get_audio_driver_name(0));
}