Add a network mode setting to bring the editor offline

This PR also adds default font styles for RichTextLabels
in the editor, and improves the introduction dialog
when you don't have any local projects available.

The offline mode is implemented in the asset library
plugin, alongside some code improvements.
This commit is contained in:
Yuri Sizov 2024-01-30 17:35:46 +01:00
parent bac037b1e0
commit 4d97c33503
8 changed files with 165 additions and 67 deletions

View file

@ -724,6 +724,9 @@
Specify the multiplier to apply to the scale for the editor gizmo handles to improve usability on touchscreen devices. Specify the multiplier to apply to the scale for the editor gizmo handles to improve usability on touchscreen devices.
[b]Note:[/b] Defaults to [code]1[/code] on non-touchscreen devices. [b]Note:[/b] Defaults to [code]1[/code] on non-touchscreen devices.
</member> </member>
<member name="network/connection/network_mode" type="int" setter="" getter="">
Determines whether online features are enabled in the editor, such as the Asset Library. Setting this property to "Offline" is recommended to limit editor's internet activity, especially if privacy is a concern.
</member>
<member name="network/debug/remote_host" type="String" setter="" getter=""> <member name="network/debug/remote_host" type="String" setter="" getter="">
The address to listen to when starting the remote debugger. This can be set to [code]0.0.0.0[/code] to allow external clients to connect to the remote debugger (instead of restricting the remote debugger to connections from [code]localhost[/code]). The address to listen to when starting the remote debugger. This can be set to [code]0.0.0.0[/code] to allow external clients to connect to the remote debugger (instead of restricting the remote debugger to connections from [code]localhost[/code]).
</member> </member>

View file

@ -766,15 +766,22 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
/* Network */ /* Network */
// Debug // General
_initial_set("network/debug/remote_host", "127.0.0.1"); // Hints provided in setup_network EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "network/connection/network_mode", 0, "Offline,Online");
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/debug/remote_port", 6007, "1,65535,1") // HTTP Proxy
_initial_set("network/http_proxy/host", "");
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/http_proxy/port", 8080, "1,65535,1")
// SSL // SSL
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "network/tls/editor_tls_certificates", _SYSTEM_CERTS_PATH, "*.crt,*.pem", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "network/tls/editor_tls_certificates", _SYSTEM_CERTS_PATH, "*.crt,*.pem", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
// Debugger/profiler // Debug
_initial_set("network/debug/remote_host", "127.0.0.1"); // Hints provided in setup_network
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/debug/remote_port", 6007, "1,65535,1")
/* Debugger/profiler */
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/auto_switch_to_remote_scene_tree", false, "") EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/auto_switch_to_remote_scene_tree", false, "")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_history_size", 3600, "60,10000,1") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_history_size", 3600, "60,10000,1")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_max_functions", 64, "16,512,1") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_max_functions", 64, "16,512,1")
@ -782,10 +789,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "debugger/remote_inspect_refresh_interval", 0.2, "0.02,10,0.01,or_greater") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "debugger/remote_inspect_refresh_interval", 0.2, "0.02,10,0.01,or_greater")
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/profile_native_calls", false, "") EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/profile_native_calls", false, "")
// HTTP Proxy
_initial_set("network/http_proxy/host", "");
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/http_proxy/port", 8080, "1,65535,1")
/* Extra config */ /* Extra config */
// TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects. // TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects.

View file

@ -57,6 +57,11 @@ public:
Vector<String> install_files; Vector<String> install_files;
}; };
enum NetworkMode {
NETWORK_OFFLINE,
NETWORK_ONLINE,
};
private: private:
struct VariantContainer { struct VariantContainer {
int order = 0; int order = 0;

View file

@ -643,6 +643,15 @@ void EditorAssetLibrary::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
_update_repository_options(); _update_repository_options();
setup_http_request(request); setup_http_request(request);
const bool loading_blocked_new = ((int)EDITOR_GET("network/connection/network_mode") == EditorSettings::NETWORK_OFFLINE);
if (loading_blocked_new != loading_blocked) {
loading_blocked = loading_blocked_new;
if (!loading_blocked && is_visible()) {
_request_current_config(); // Reload config now that the network is available.
}
}
} break; } break;
} }
} }
@ -929,9 +938,7 @@ void EditorAssetLibrary::_request_image(ObjectID p_for, String p_image_url, Imag
} }
void EditorAssetLibrary::_repository_changed(int p_repository_id) { void EditorAssetLibrary::_repository_changed(int p_repository_id) {
library_error->hide(); _set_library_message(TTR("Loading..."));
library_info->set_text(TTR("Loading..."));
library_info->show();
asset_top_page->hide(); asset_top_page->hide();
asset_bottom_page->hide(); asset_bottom_page->hide();
@ -1104,10 +1111,14 @@ void EditorAssetLibrary::_api_request(const String &p_request, RequestType p_req
if (requesting != REQUESTING_NONE) { if (requesting != REQUESTING_NONE) {
request->cancel_request(); request->cancel_request();
} }
error_hb->hide();
if (loading_blocked) {
_set_library_message_with_action(TTR("The Asset Library requires an online connection and involves sending data over the internet."), TTR("Go Online"), callable_mp(this, &EditorAssetLibrary::_force_online_mode));
return;
}
requesting = p_request_type; requesting = p_request_type;
error_hb->hide();
request->request(host + "/" + p_request + p_arguments); request->request(host + "/" + p_request + p_arguments);
} }
@ -1156,8 +1167,7 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
if (error_abort) { if (error_abort) {
if (requesting == REQUESTING_CONFIG) { if (requesting == REQUESTING_CONFIG) {
library_info->hide(); _set_library_message_with_action(TTR("Failed to get repository configuration."), TTR("Retry"), callable_mp(this, &EditorAssetLibrary::_request_current_config));
library_error->show();
} }
error_hb->show(); error_hb->show();
return; return;
@ -1265,18 +1275,17 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
} }
if (!filter->get_text().is_empty()) { if (!filter->get_text().is_empty()) {
library_info->set_text( _set_library_message(
vformat(TTR("No results for \"%s\" for support level(s): %s."), filter->get_text(), support_list)); vformat(TTR("No results for \"%s\" for support level(s): %s."), filter->get_text(), support_list));
} else { } else {
// No results, even though the user didn't search for anything specific. // No results, even though the user didn't search for anything specific.
// This is typically because the version number changed recently // This is typically because the version number changed recently
// and no assets compatible with the new version have been published yet. // and no assets compatible with the new version have been published yet.
library_info->set_text( _set_library_message(
vformat(TTR("No results compatible with %s %s for support level(s): %s.\nCheck the enabled support levels using the 'Support' button in the top-right corner."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH), support_list)); vformat(TTR("No results compatible with %s %s for support level(s): %s.\nCheck the enabled support levels using the 'Support' button in the top-right corner."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH), support_list));
} }
library_info->show();
} else { } else {
library_info->hide(); library_message_box->hide();
} }
for (int i = 0; i < result.size(); i++) { for (int i = 0; i < result.size(); i++) {
@ -1432,6 +1441,39 @@ void EditorAssetLibrary::_update_asset_items_columns() {
asset_items_column_width = (get_size().x / new_columns) - (100 * EDSCALE); asset_items_column_width = (get_size().x / new_columns) - (100 * EDSCALE);
} }
void EditorAssetLibrary::_set_library_message(const String &p_message) {
library_message->set_text(p_message);
if (library_message_action.is_valid()) {
library_message_button->disconnect("pressed", library_message_action);
library_message_action = Callable();
}
library_message_button->hide();
library_message_box->show();
}
void EditorAssetLibrary::_set_library_message_with_action(const String &p_message, const String &p_action_text, const Callable &p_action) {
library_message->set_text(p_message);
library_message_button->set_text(p_action_text);
if (library_message_action.is_valid()) {
library_message_button->disconnect("pressed", library_message_action);
library_message_action = Callable();
}
library_message_action = p_action;
library_message_button->connect("pressed", library_message_action);
library_message_button->show();
library_message_box->show();
}
void EditorAssetLibrary::_force_online_mode() {
EditorSettings::get_singleton()->set_setting("network/connection/network_mode", EditorSettings::NETWORK_ONLINE);
EditorSettings::get_singleton()->notify_changes();
EditorSettings::get_singleton()->save();
}
void EditorAssetLibrary::disable_community_support() { void EditorAssetLibrary::disable_community_support() {
support->get_popup()->set_item_checked(SUPPORT_COMMUNITY, false); support->get_popup()->set_item_checked(SUPPORT_COMMUNITY, false);
} }
@ -1443,7 +1485,7 @@ void EditorAssetLibrary::_bind_methods() {
EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
requesting = REQUESTING_NONE; requesting = REQUESTING_NONE;
templates_only = p_templates_only; templates_only = p_templates_only;
initial_loading = true; loading_blocked = ((int)EDITOR_GET("network/connection/network_mode") == EditorSettings::NETWORK_OFFLINE);
VBoxContainer *library_main = memnew(VBoxContainer); VBoxContainer *library_main = memnew(VBoxContainer);
add_child(library_main); add_child(library_main);
@ -1567,22 +1609,17 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
library_vb_border->add_child(library_vb); library_vb_border->add_child(library_vb);
library_info = memnew(Label); library_message_box = memnew(VBoxContainer);
library_info->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); library_message_box->hide();
library_vb->add_child(library_info); library_vb->add_child(library_message_box);
library_error = memnew(VBoxContainer); library_message = memnew(Label);
library_error->hide(); library_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
library_vb->add_child(library_error); library_message_box->add_child(library_message);
library_error_label = memnew(Label(TTR("Failed to get repository configuration."))); library_message_button = memnew(Button);
library_error_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); library_message_button->set_h_size_flags(SIZE_SHRINK_CENTER);
library_error->add_child(library_error_label); library_message_box->add_child(library_message_button);
library_error_retry = memnew(Button(TTR("Retry")));
library_error_retry->set_h_size_flags(SIZE_SHRINK_CENTER);
library_error_retry->connect("pressed", callable_mp(this, &EditorAssetLibrary::_request_current_config));
library_error->add_child(library_error_retry);
asset_top_page = memnew(HBoxContainer); asset_top_page = memnew(HBoxContainer);
library_vb->add_child(asset_top_page); library_vb->add_child(asset_top_page);

View file

@ -191,10 +191,14 @@ class EditorAssetLibrary : public PanelContainer {
PanelContainer *library_scroll_bg = nullptr; PanelContainer *library_scroll_bg = nullptr;
ScrollContainer *library_scroll = nullptr; ScrollContainer *library_scroll = nullptr;
VBoxContainer *library_vb = nullptr; VBoxContainer *library_vb = nullptr;
Label *library_info = nullptr; VBoxContainer *library_message_box = nullptr;
VBoxContainer *library_error = nullptr; Label *library_message = nullptr;
Label *library_error_label = nullptr; Button *library_message_button = nullptr;
Button *library_error_retry = nullptr; Callable library_message_action;
void _set_library_message(const String &p_message);
void _set_library_message_with_action(const String &p_message, const String &p_action_text, const Callable &p_action);
LineEdit *filter = nullptr; LineEdit *filter = nullptr;
Timer *filter_debounce_timer = nullptr; Timer *filter_debounce_timer = nullptr;
OptionButton *categories = nullptr; OptionButton *categories = nullptr;
@ -213,8 +217,11 @@ class EditorAssetLibrary : public PanelContainer {
HTTPRequest *request = nullptr; HTTPRequest *request = nullptr;
bool templates_only; bool templates_only = false;
bool initial_loading; bool initial_loading = true;
bool loading_blocked = false;
void _force_online_mode();
enum Support { enum Support {
SUPPORT_OFFICIAL, SUPPORT_OFFICIAL,

View file

@ -59,6 +59,7 @@
#include "scene/gui/margin_container.h" #include "scene/gui/margin_container.h"
#include "scene/gui/option_button.h" #include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h" #include "scene/gui/panel_container.h"
#include "scene/gui/rich_text_label.h"
#include "scene/gui/separator.h" #include "scene/gui/separator.h"
#include "scene/gui/texture_rect.h" #include "scene/gui/texture_rect.h"
#include "scene/main/window.h" #include "scene/main/window.h"
@ -137,21 +138,15 @@ void ProjectManager::_notification(int p_what) {
} break; } break;
case NOTIFICATION_READY: { case NOTIFICATION_READY: {
int default_sorting = (int)EDITOR_GET("project_manager/sorting_order"); const int default_sorting = (int)EDITOR_GET("project_manager/sorting_order");
filter_option->select(default_sorting); filter_option->select(default_sorting);
_project_list->set_order_option(default_sorting); _project_list->set_order_option(default_sorting);
#ifndef ANDROID_ENABLED _select_main_view(MAIN_VIEW_PROJECTS);
if (_project_list->get_project_count() >= 1) {
// Focus on the search box immediately to allow the user
// to search without having to reach for their mouse
search_box->grab_focus();
}
#endif
// Suggest browsing asset library to get templates/demos. // Suggest browsing asset library to get templates/demos.
if (asset_library && open_templates && _project_list->get_project_count() == 0) { if (asset_library && _project_list->get_project_count() == 0) {
open_templates->popup_centered(); _suggest_asset_library();
} }
} break; } break;
@ -303,10 +298,54 @@ void ProjectManager::_select_main_view(int p_id) {
} }
void ProjectManager::_show_about() { void ProjectManager::_show_about() {
about->popup_centered(Size2(780, 500) * EDSCALE); about_dialog->popup_centered(Size2(780, 500) * EDSCALE);
} }
void ProjectManager::_open_asset_library() { void ProjectManager::_suggest_asset_library() {
if (!suggest_asset_library_dialog) {
suggest_asset_library_dialog = memnew(ConfirmationDialog);
suggest_asset_library_dialog->set_title(TTR("Getting Started with Godot"));
add_child(suggest_asset_library_dialog);
suggest_asset_library_dialog->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library_confirmed));
VBoxContainer *suggest_vbox = memnew(VBoxContainer);
suggest_asset_library_dialog->add_child(suggest_vbox);
suggest_asset_library_label = memnew(RichTextLabel);
suggest_asset_library_label->set_use_bbcode(true);
suggest_asset_library_label->set_fit_content(true);
suggest_asset_library_label->set_h_size_flags(SIZE_EXPAND_FILL);
suggest_asset_library_label->add_theme_style_override("normal", memnew(StyleBoxEmpty));
suggest_vbox->add_child(suggest_asset_library_label);
}
const int network_mode = EDITOR_GET("network/connection/network_mode");
if (network_mode == EditorSettings::NETWORK_OFFLINE) {
const String line1 = TTR("You don't have any projects yet.");
const String line2 = TTR("Get started with one of the official project templates from the Asset Library!");
const String line3 = TTR("Note: The Asset Library requires an online connection and involves sending data over the internet.");
suggest_asset_library_label->set_text(vformat("%s\n\n[b]%s[/b]\n\n[i]%s[/i]", line1, line2, line3));
suggest_asset_library_dialog->set_ok_button_text(TTR("Go Online and Open Asset Library"));
} else {
const String line1 = TTR("You don't have any projects yet.");
const String line2 = TTR("Get started with one of the official project templates from the Asset Library!");
suggest_asset_library_label->set_text(vformat("%s\n\n[b]%s[/b]", line1, line2));
suggest_asset_library_dialog->set_ok_button_text(TTR("Open Asset Library"));
}
suggest_asset_library_dialog->popup_centered(Size2(540, 100) * EDSCALE);
}
void ProjectManager::_open_asset_library_confirmed() {
const int network_mode = EDITOR_GET("network/connection/network_mode");
if (network_mode == EditorSettings::NETWORK_OFFLINE) {
EditorSettings::get_singleton()->set_setting("network/connection/network_mode", EditorSettings::NETWORK_ONLINE);
EditorSettings::get_singleton()->notify_changes();
EditorSettings::get_singleton()->save();
}
asset_library->disable_community_support(); asset_library->disable_community_support();
_select_main_view(MAIN_VIEW_ASSETLIB); _select_main_view(MAIN_VIEW_ASSETLIB);
} }
@ -1339,16 +1378,8 @@ ProjectManager::ProjectManager() {
dialog_error = memnew(AcceptDialog); dialog_error = memnew(AcceptDialog);
add_child(dialog_error); add_child(dialog_error);
if (asset_library) { about_dialog = memnew(EditorAbout);
open_templates = memnew(ConfirmationDialog); add_child(about_dialog);
open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?"));
open_templates->set_ok_button_text(TTR("Open Asset Library"));
open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library));
add_child(open_templates);
}
about = memnew(EditorAbout);
add_child(about);
} }
// Tag management. // Tag management.
@ -1453,7 +1484,6 @@ ProjectManager::ProjectManager() {
} }
_update_size_limits(); _update_size_limits();
_select_main_view(MAIN_VIEW_PROJECTS);
} }
ProjectManager::~ProjectManager() { ProjectManager::~ProjectManager() {

View file

@ -46,6 +46,7 @@ class OptionButton;
class PanelContainer; class PanelContainer;
class ProjectDialog; class ProjectDialog;
class ProjectList; class ProjectList;
class RichTextLabel;
class TabContainer; class TabContainer;
class VBoxContainer; class VBoxContainer;
@ -96,11 +97,13 @@ class ProjectManager : public Control {
VBoxContainer *local_projects_vb = nullptr; VBoxContainer *local_projects_vb = nullptr;
EditorAssetLibrary *asset_library = nullptr; EditorAssetLibrary *asset_library = nullptr;
ConfirmationDialog *open_templates = nullptr; ConfirmationDialog *suggest_asset_library_dialog = nullptr;
EditorAbout *about = nullptr; RichTextLabel *suggest_asset_library_label = nullptr;
EditorAbout *about_dialog = nullptr;
void _show_about(); void _show_about();
void _open_asset_library(); void _suggest_asset_library();
void _open_asset_library_confirmed();
// Quick settings. // Quick settings.

View file

@ -370,6 +370,9 @@ void editor_register_fonts(const Ref<Theme> &p_theme) {
Ref<FontVariation> italic_fc = default_fc->duplicate(); Ref<FontVariation> italic_fc = default_fc->duplicate();
italic_fc->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0)); italic_fc->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
Ref<FontVariation> bold_italic_fc = bold_fc->duplicate();
bold_italic_fc->set_variation_transform(Transform2D(1.0, 0.2, 0.0, 1.0, 0.0, 0.0));
// Setup theme. // Setup theme.
p_theme->set_default_font(default_fc); // Default theme font config. p_theme->set_default_font(default_fc); // Default theme font config.
@ -394,6 +397,8 @@ void editor_register_fonts(const Ref<Theme> &p_theme) {
p_theme->set_font("font", "MainScreenButton", bold_fc); p_theme->set_font("font", "MainScreenButton", bold_fc);
p_theme->set_font_size("font_size", "MainScreenButton", default_font_size + 2 * EDSCALE); p_theme->set_font_size("font_size", "MainScreenButton", default_font_size + 2 * EDSCALE);
// Labels.
p_theme->set_font("font", "Label", default_fc); p_theme->set_font("font", "Label", default_fc);
p_theme->set_type_variation("HeaderSmall", "Label"); p_theme->set_type_variation("HeaderSmall", "Label");
@ -408,6 +413,11 @@ void editor_register_fonts(const Ref<Theme> &p_theme) {
p_theme->set_font("font", "HeaderLarge", bold_fc); p_theme->set_font("font", "HeaderLarge", bold_fc);
p_theme->set_font_size("font_size", "HeaderLarge", default_font_size + 3 * EDSCALE); p_theme->set_font_size("font_size", "HeaderLarge", default_font_size + 3 * EDSCALE);
p_theme->set_font("normal_font", "RichTextLabel", default_fc);
p_theme->set_font("bold_font", "RichTextLabel", bold_fc);
p_theme->set_font("italics_font", "RichTextLabel", italic_fc);
p_theme->set_font("bold_italics_font", "RichTextLabel", bold_italic_fc);
// Documentation fonts // Documentation fonts
p_theme->set_font_size("doc_size", EditorStringName(EditorFonts), int(EDITOR_GET("text_editor/help/help_font_size")) * EDSCALE); p_theme->set_font_size("doc_size", EditorStringName(EditorFonts), int(EDITOR_GET("text_editor/help/help_font_size")) * EDSCALE);
p_theme->set_font("doc", EditorStringName(EditorFonts), default_fc); p_theme->set_font("doc", EditorStringName(EditorFonts), default_fc);