diff options
author | RĂ©mi Verschelde <remi@verschelde.fr> | 2021-11-24 19:28:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-24 19:28:20 +0100 |
commit | e49b127b41a425fadc47d09d375624c5511f1f06 (patch) | |
tree | 11ce05a4559d6b75908339e296c01e01bb33b701 /editor | |
parent | 3e3300637e216b35a93b5ecc8364e383ac898e73 (diff) | |
parent | e81c689592bd493aa2ff67b8e9d2d9107572647a (diff) |
Merge pull request #31171 from aaronfranke/feature-system
Diffstat (limited to 'editor')
-rw-r--r-- | editor/project_manager.cpp | 214 |
1 files changed, 164 insertions, 50 deletions
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 4318f30add..0be1f6d85b 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -478,8 +478,20 @@ private: cd->grab_focus(); return; } + PackedStringArray project_features = ProjectSettings::get_required_features(); ProjectSettings::CustomMap initial_settings; - initial_settings["rendering/vulkan/rendering/back_end"] = rasterizer_button_group->get_pressed_button()->get_meta(SNAME("driver_name")); + // Be sure to change this code if/when renderers are changed. + int renderer_type = rasterizer_button_group->get_pressed_button()->get_meta(SNAME("driver_name")); + initial_settings["rendering/vulkan/rendering/back_end"] = renderer_type; + if (renderer_type == 0) { + project_features.push_back("Vulkan Clustered"); + } else if (renderer_type == 1) { + project_features.push_back("Vulkan Mobile"); + } else { + WARN_PRINT("Unknown renderer type. Please report this as a bug on GitHub."); + } + project_features.sort(); + initial_settings["application/config/features"] = project_features; initial_settings["application/config/name"] = project_name->get_text().strip_edges(); initial_settings["application/config/icon"] = "res://icon.png"; @@ -1019,6 +1031,7 @@ public: String path; String icon; String main_scene; + PackedStringArray unsupported_features; uint64_t last_edited = 0; bool favorite = false; bool grayed = false; @@ -1035,6 +1048,7 @@ public: const String &p_path, const String &p_icon, const String &p_main_scene, + const PackedStringArray &p_unsupported_features, uint64_t p_last_edited, bool p_favorite, bool p_grayed, @@ -1046,6 +1060,7 @@ public: path = p_path; icon = p_icon; main_scene = p_main_scene; + unsupported_features = p_unsupported_features; last_edited = p_last_edited; favorite = p_favorite; grayed = p_grayed; @@ -1097,8 +1112,7 @@ private: void remove_project(int p_index, bool p_update_settings); void update_icons_async(); void load_project_icon(int p_index); - - static void load_project_data(const String &p_property_key, Item &p_item, bool p_favorite); + static Item load_project_data(const String &p_property_key, bool p_favorite); String _search_term; FilterOption _order_option; @@ -1189,7 +1203,8 @@ void ProjectList::load_project_icon(int p_index) { item.control->icon_needs_reload = false; } -void ProjectList::load_project_data(const String &p_property_key, Item &p_item, bool p_favorite) { +// Load project data from p_property_key and return it in a ProjectList::Item. p_favorite is passed directly into the Item. +ProjectList::Item ProjectList::load_project_data(const String &p_property_key, bool p_favorite) { String path = EditorSettings::get_singleton()->get(p_property_key); String conf = path.plus_file("project.godot"); bool grayed = false; @@ -1209,13 +1224,56 @@ void ProjectList::load_project_data(const String &p_property_key, Item &p_item, } if (config_version > ProjectSettings::CONFIG_VERSION) { - // Comes from an incompatible (more recent) Godot version, grey it out + // Comes from an incompatible (more recent) Godot version, gray it out. grayed = true; } - String description = cf->get_value("application", "config/description", ""); - String icon = cf->get_value("application", "config/icon", ""); - String main_scene = cf->get_value("application", "run/main_scene", ""); + const String description = cf->get_value("application", "config/description", ""); + const String icon = cf->get_value("application", "config/icon", ""); + const String main_scene = cf->get_value("application", "run/main_scene", ""); + + PackedStringArray project_features = cf->get_value("application", "config/features", PackedStringArray()); + bool project_features_dirty = false; + // If there is no feature list currently present, force one to generate. + if (project_features.is_empty()) { + project_features = ProjectSettings::get_required_features(); + project_features_dirty = true; + } + // Check the rendering API. + const String rendering_api = cf->get_value("rendering", "quality/driver/driver_name", ""); + if (rendering_api != "") { + // Add the rendering API as a project feature if it doesn't already exist. + if (!project_features.has(rendering_api)) { + project_features.append(rendering_api); + project_features_dirty = true; + } + } + // Check for the existence of a csproj file. + if (FileAccess::exists(path.plus_file(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#"); + project_features_dirty = true; + } + } else { + // If there isn't a csproj file, remove the C# feature if it exists. + if (project_features.has("C#")) { + project_features.remove_at(project_features.find("C#")); + project_features_dirty = true; + } + } + if (project_features_dirty) { + project_features.sort(); + // Write the updated feature list, but only if the project config version is the same. + // Never write to project files with a different config version! + if (config_version == ProjectSettings::CONFIG_VERSION) { + ProjectSettings *ps = ProjectSettings::get_singleton(); + ps->load_custom(conf); + ps->set("application/config/features", project_features); + ps->save_custom(conf); + } + } + PackedStringArray unsupported_features = ProjectSettings::get_unsupported_features(project_features); uint64_t last_edited = 0; if (FileAccess::exists(conf)) { @@ -1237,9 +1295,9 @@ void ProjectList::load_project_data(const String &p_property_key, Item &p_item, print_line("Project is missing: " + conf); } - String project_key = p_property_key.get_slice("/", 1); + const String project_key = p_property_key.get_slice("/", 1); - p_item = Item(project_key, project_name, description, path, icon, main_scene, last_edited, p_favorite, grayed, missing, config_version); + return Item(project_key, project_name, description, path, icon, main_scene, unsupported_features, last_edited, p_favorite, grayed, missing, config_version); } void ProjectList::load_projects() { @@ -1282,8 +1340,7 @@ void ProjectList::load_projects() { String project_key = property_key.get_slice("/", 1); bool favorite = favorites.has("favorite_projects/" + project_key); - Item item; - load_project_data(property_key, item, favorite); + Item item = load_project_data(property_key, favorite); _projects.push_back(item); } @@ -1366,7 +1423,7 @@ void ProjectList::create_project_item_control(int p_index) { TextureButton *favorite = memnew(TextureButton); favorite->set_name("FavoriteButton"); favorite->set_normal_texture(favorite_icon); - // This makes the project's "hover" style display correctly when hovering the favorite icon + // This makes the project's "hover" style display correctly when hovering the favorite icon. favorite->set_mouse_filter(MOUSE_FILTER_PASS); favorite->connect("pressed", callable_mp(this, &ProjectList::_favorite_pressed), varray(hb)); favorite_box->add_child(favorite); @@ -1396,40 +1453,65 @@ void ProjectList::create_project_item_control(int p_index) { ec->set_custom_minimum_size(Size2(0, 1)); ec->set_mouse_filter(MOUSE_FILTER_PASS); vb->add_child(ec); - Label *title = memnew(Label(!item.missing ? item.project_name : TTR("Missing Project"))); - title->add_theme_font_override("font", get_theme_font(SNAME("title"), SNAME("EditorFonts"))); - title->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("title_size"), SNAME("EditorFonts"))); - title->add_theme_color_override("font_color", font_color); - title->set_clip_text(true); - vb->add_child(title); - - HBoxContainer *path_hb = memnew(HBoxContainer); - path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); - vb->add_child(path_hb); - - Button *show = memnew(Button); - // Display a folder icon if the project directory can be opened, or a "broken file" icon if it can't. - show->set_icon(get_theme_icon(!item.missing ? "Load" : "FileBroken", "EditorIcons")); - if (!item.grayed) { - // Don't make the icon less prominent if the parent is already grayed out. - show->set_modulate(Color(1, 1, 1, 0.5)); - } - path_hb->add_child(show); - - if (!item.missing) { - show->connect("pressed", callable_mp(this, &ProjectList::_show_project), varray(item.path)); - show->set_tooltip(TTR("Show in File Manager")); - } else { - show->set_tooltip(TTR("Error: Project is missing on the filesystem.")); - } - Label *fpath = memnew(Label(item.path)); - fpath->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE); - path_hb->add_child(fpath); - fpath->set_h_size_flags(Control::SIZE_EXPAND_FILL); - fpath->set_modulate(Color(1, 1, 1, 0.5)); - fpath->add_theme_color_override("font_color", font_color); - fpath->set_clip_text(true); + { // Top half, title and unsupported features labels. + HBoxContainer *title_hb = memnew(HBoxContainer); + vb->add_child(title_hb); + + Label *title = memnew(Label(!item.missing ? item.project_name : TTR("Missing Project"))); + title->set_h_size_flags(Control::SIZE_EXPAND_FILL); + title->add_theme_font_override("font", get_theme_font(SNAME("title"), SNAME("EditorFonts"))); + title->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("title_size"), SNAME("EditorFonts"))); + title->add_theme_color_override("font_color", font_color); + title->set_clip_text(true); + title_hb->add_child(title); + + String unsupported_features_str = Variant(item.unsupported_features).operator String().trim_prefix("[").trim_suffix("]"); + int length = unsupported_features_str.length(); + if (length > 0) { + Label *unsupported_label = memnew(Label(unsupported_features_str)); + unsupported_label->set_custom_minimum_size(Size2(length * 15, 10)); + unsupported_label->add_theme_font_override("font", get_theme_font(SNAME("title"), SNAME("EditorFonts"))); + unsupported_label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor"))); + unsupported_label->set_clip_text(true); + unsupported_label->set_align(Label::ALIGN_RIGHT); + title_hb->add_child(unsupported_label); + Control *spacer = memnew(Control()); + spacer->set_custom_minimum_size(Size2(10, 10)); + title_hb->add_child(spacer); + } + } + + { // Bottom half, containing the path and view folder button. + HBoxContainer *path_hb = memnew(HBoxContainer); + path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + vb->add_child(path_hb); + + Button *show = memnew(Button); + // Display a folder icon if the project directory can be opened, or a "broken file" icon if it can't. + show->set_icon(get_theme_icon(!item.missing ? "Load" : "FileBroken", "EditorIcons")); + show->set_flat(true); + if (!item.grayed) { + // Don't make the icon less prominent if the parent is already grayed out. + show->set_modulate(Color(1, 1, 1, 0.5)); + } + path_hb->add_child(show); + + if (!item.missing) { + show->connect("pressed", callable_mp(this, &ProjectList::_show_project), varray(item.path)); + show->set_tooltip(TTR("Show in File Manager")); + } else { + show->set_tooltip(TTR("Error: Project is missing on the filesystem.")); + } + + Label *fpath = memnew(Label(item.path)); + fpath->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE); + path_hb->add_child(fpath); + fpath->set_h_size_flags(Control::SIZE_EXPAND_FILL); + fpath->set_modulate(Color(1, 1, 1, 0.5)); + fpath->add_theme_color_override("font_color", font_color); + fpath->set_clip_text(true); + } _scroll_children->add_child(hb); item.control = hb; @@ -1634,8 +1716,7 @@ int ProjectList::refresh_project(const String &dir_path) { if (should_be_in_list) { // Recreate it with updated info - Item item; - load_project_data(property_key, item, is_favourite); + Item item = load_project_data(property_key, is_favourite); _projects.push_back(item); create_project_item_control(_projects.size() - 1); @@ -2114,8 +2195,12 @@ void ProjectManager::_open_selected_projects_ask() { } // Update the project settings or don't open - String conf = project.path.plus_file("project.godot"); - int config_version = project.version; + const String conf = project.path.plus_file("project.godot"); + const int config_version = project.version; + PackedStringArray unsupported_features = project.unsupported_features; + + Label *ask_update_label = ask_update_settings->get_label(); + ask_update_label->set_align(Label::ALIGN_LEFT); // Reset in case of previous center align. // Check if the config_version property was empty or 0 if (config_version == 0) { @@ -2135,6 +2220,35 @@ void ProjectManager::_open_selected_projects_ask() { dialog_error->popup_centered(); return; } + // Check if the project is using features not supported by this build of Godot. + if (!unsupported_features.is_empty()) { + String warning_message = ""; + for (int i = 0; i < unsupported_features.size(); i++) { + String feature = unsupported_features[i]; + if (feature == "Double Precision") { + warning_message += TTR("Warning: This project uses double precision floats, but this version of\nGodot uses single precision floats. Opening this project may cause data loss.\n\n"); + unsupported_features.remove_at(i); + i--; + } else if (feature == "C#") { + warning_message += TTR("Warning: This project uses C#, but this build of Godot does not have\nthe Mono module. If you proceed you will not be able to use any C# scripts.\n\n"); + unsupported_features.remove_at(i); + i--; + } else if (feature.substr(0, 3).is_numeric()) { + warning_message += vformat(TTR("Warning: This project was built in Godot %s.\nOpening will upgrade or downgrade the project to Godot %s.\n\n"), Variant(feature), Variant(VERSION_BRANCH)); + unsupported_features.remove_at(i); + i--; + } + } + if (!unsupported_features.is_empty()) { + String unsupported_features_str = Variant(unsupported_features).operator String().trim_prefix("[").trim_suffix("]"); + warning_message += vformat(TTR("Warning: This project uses the following features not supported by this build of Godot:\n\n%s\n\n"), unsupported_features_str); + } + warning_message += TTR("Open anyway? Project will be modified."); + ask_update_label->set_align(Label::ALIGN_CENTER); + ask_update_settings->set_text(warning_message); + ask_update_settings->popup_centered(); + return; + } // Open if the project is up-to-date _open_selected_projects(); |