diff options
32 files changed, 477 insertions, 422 deletions
@@ -1,25 +1,29 @@ -[](https://godotengine.org) +# Godot Engine -## Godot Engine +<p align="center"> + <a href="https://godotengine.org"> + <img src="logo.svg" width="400" alt="Godot Engine logo"> + </a> +</p> -Homepage: https://godotengine.org +## 2D and 3D cross-platform game engine -#### 2D and 3D cross-platform game engine +**[Godot Engine](https://godotengine.org) is a feature-packed, cross-platform +game engine to create 2D and 3D games from a unified interface.** It provides a +comprehensive set of common tools, so that users can focus on making games +without having to reinvent the wheel. Games can be exported in one click to a +number of platforms, including the major desktop platforms (Linux, macOS, +Windows), mobile platforms (Android, iOS), as well as Web-based platforms +(HTML5) and +[consoles](https://docs.godotengine.org/en/latest/tutorials/platform/consoles.html). -Godot Engine is a feature-packed, cross-platform game engine to create 2D and -3D games from a unified interface. It provides a comprehensive set of common -tools, so that users can focus on making games without having to reinvent the -wheel. Games can be exported in one click to a number of platforms, including -the major desktop platforms (Linux, Mac OSX, Windows) as well as mobile -(Android, iOS) and web-based (HTML5) platforms. - -#### Free, open source and community-driven +## Free, open source and community-driven Godot is completely free and open source under the very permissive MIT license. No strings attached, no royalties, nothing. The users' games are theirs, down to the last line of engine code. Godot's development is fully independent and community-driven, empowering users to help shape their engine to match their -expectations. It is supported by the Software Freedom Conservancy +expectations. It is supported by the [Software Freedom Conservancy](https://sfconservancy.org/) not-for-profit. Before being open sourced in February 2014, Godot had been developed by Juan @@ -28,43 +32,45 @@ years as an in-house engine, used to publish several work-for-hire titles.  -### Getting the engine +## Getting the engine -#### Binary downloads +### Binary downloads Official binaries for the Godot editor and the export templates can be found [on the homepage](https://godotengine.org/download). -#### Compiling from source +### Compiling from source [See the official docs](https://docs.godotengine.org/en/latest/development/compiling/) for compilation instructions for every supported platform. -### Community and contributing +## Community and contributing Godot is not only an engine but an ever-growing community of users and engine developers. The main community channels are listed [on the homepage](https://godotengine.org/community). -To get in touch with the developers, the best way is to join the -[#godotengine IRC channel](https://webchat.freenode.net/?channels=godotengine) +To get in touch with the engine developers, the best way is to join the +[#godotengine-devel IRC channel](https://webchat.freenode.net/?channels=godotengine-devel) on Freenode. To get started contributing to the project, see the [contributing guide](CONTRIBUTING.md). -### Documentation and demos +## Documentation and demos The official documentation is hosted on [ReadTheDocs](https://docs.godotengine.org). It is maintained by the Godot community in its own [GitHub repository](https://github.com/godotengine/godot-docs). The [class reference](https://docs.godotengine.org/en/latest/classes/) -is also accessible from within the engine. +is also accessible from the Godot editor. The official demos are maintained in their own [GitHub repository](https://github.com/godotengine/godot-demo-projects) as well. -There are also a number of other learning resources provided by the community, -such as text and video tutorials, demos, etc. Consult the [community channels](https://godotengine.org/community) -for more info. +There are also a number of other +[learning resources](https://docs.godotengine.org/en/latest/community/tutorials.html) +provided by the community, such as text and video tutorials, demos, etc. +Consult the [community channels](https://godotengine.org/community) +for more information. [](https://github.com/godotengine/godot/actions) [](https://www.codetriage.com/godotengine/godot) diff --git a/core/project_settings.cpp b/core/project_settings.cpp index e08a44d0c1..960a0ec1b0 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -659,6 +659,12 @@ void ProjectSettings::set_builtin_order(const String &p_name) { } } +bool ProjectSettings::is_builtin_setting(const String &p_name) const { + // Return true because a false negative is worse than a false positive. + ERR_FAIL_COND_V_MSG(!props.has(p_name), true, "Request for nonexistent project setting: " + p_name + "."); + return props[p_name].order < NO_BUILTIN_ORDER_BASE; +} + void ProjectSettings::clear(const String &p_name) { ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + "."); props.erase(p_name); diff --git a/core/project_settings.h b/core/project_settings.h index 659ee402b3..686f6f3873 100644 --- a/core/project_settings.h +++ b/core/project_settings.h @@ -142,6 +142,7 @@ public: int get_order(const String &p_name) const; void set_order(const String &p_name, int p_order); void set_builtin_order(const String &p_name); + bool is_builtin_setting(const String &p_name) const; Error setup(const String &p_path, const String &p_main_pack, bool p_upwards = false); diff --git a/core/variant_call.cpp b/core/variant_call.cpp index b96fd0c103..91af127d32 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -2350,9 +2350,9 @@ void register_variant_methods() { _VariantCall::add_variant_constant(Variant::VECTOR3, "FORWARD", Vector3(0, 0, -1)); _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1)); - _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_X", Vector3::AXIS_X); - _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3::AXIS_Y); - _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3::AXIS_Z); + _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_X", Vector3i::AXIS_X); + _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3i::AXIS_Y); + _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3i::AXIS_Z); _VariantCall::add_variant_constant(Variant::VECTOR3I, "ZERO", Vector3i(0, 0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR3I, "ONE", Vector3i(1, 1, 1)); @@ -2366,8 +2366,8 @@ void register_variant_methods() { _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X); _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y); - _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2::AXIS_X); - _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_Y", Vector2::AXIS_Y); + _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2i::AXIS_X); + _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_Y", Vector2i::AXIS_Y); _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR2, "ONE", Vector2(1, 1)); diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index b7240655af..d4abac15c0 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -430,6 +430,9 @@ <member name="v_scroll_speed" type="float" setter="set_v_scroll_speed" getter="get_v_scroll_speed" default="80.0"> Vertical scroll sensitivity. </member> + <member name="virtual_keyboard_enabled" type="bool" setter="set_virtual_keyboard_enabled" getter="is_virtual_keyboard_enabled" default="true"> + If [code]true[/code], the native virtual keyboard is shown when focused on platforms that support it. + </member> <member name="wrap_enabled" type="bool" setter="set_wrap_enabled" getter="is_wrap_enabled" default="false"> If [code]true[/code], enables text wrapping when it goes beyond the edge of what is visible. </member> diff --git a/editor/doc_data.cpp b/editor/doc_data.cpp index 75b16b4510..791b49319a 100644 --- a/editor/doc_data.cpp +++ b/editor/doc_data.cpp @@ -316,8 +316,7 @@ void DocData::generate(bool p_basic_types) { if (name == "ProjectSettings") { // Special case for project settings, so that settings are not taken from the current project's settings - if (E->get().name == "script" || - ProjectSettings::get_singleton()->get_order(E->get().name) >= ProjectSettings::NO_BUILTIN_ORDER_BASE) { + if (E->get().name == "script" || !ProjectSettings::get_singleton()->is_builtin_setting(E->get().name)) { continue; } if (E->get().usage & PROPERTY_USAGE_EDITOR) { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index a93763810b..8d54bc8021 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -85,7 +85,8 @@ static Ref<StyleBoxLine> make_line_stylebox(Color p_color, int p_thickness = 1, return style; } -Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float p_scale = EDSCALE, bool p_force_filter = false) { +#ifdef MODULE_SVG_ENABLED +static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float p_scale = EDSCALE, bool p_force_filter = false) { Ref<ImageTexture> icon = memnew(ImageTexture); Ref<Image> img = memnew(Image); @@ -99,6 +100,7 @@ Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float return icon; } +#endif #ifndef ADD_CONVERT_COLOR #define ADD_CONVERT_COLOR(dictionary, old_color, new_color) dictionary[Color::html(old_color)] = Color::html(new_color) diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index a68742a985..35311b32eb 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -475,10 +475,12 @@ private: set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR); } else { f->store_line("[gd_resource type=\"Environment\" load_steps=2 format=2]"); + f->store_line(""); f->store_line("[sub_resource type=\"Sky\" id=1]"); + f->store_line(""); f->store_line("[resource]"); f->store_line("background_mode = 2"); - f->store_line("background_sky = SubResource( 1 )"); + f->store_line("sky = SubResource( 1 )"); memdelete(f); } } diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 0257e31ee7..9be1a7c2fe 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -30,8 +30,6 @@ #include "project_settings_editor.h" -#include "core/global_constants.h" -#include "core/os/keyboard.h" #include "core/project_settings.h" #include "editor/editor_export.h" #include "editor/editor_node.h" @@ -48,175 +46,157 @@ void ProjectSettingsEditor::popup_project_settings() { popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8); } - globals_editor->update_category_list(); + _add_feature_overrides(); + inspector->update_category_list(); + localization_editor->update_translations(); autoload_settings->update_autoload(); plugin_settings->update_plugins(); - set_process_unhandled_input(true); } -void ProjectSettingsEditor::_unhandled_input(const Ref<InputEvent> &p_event) { - const Ref<InputEventKey> k = p_event; - - if (k.is_valid() && k->is_pressed()) { - if (k->get_keycode_with_modifiers() == (KEY_MASK_CMD | KEY_F)) { - if (search_button->is_pressed()) { - search_box->grab_focus(); - search_box->select_all(); - } else { - // This toggles the search bar display while giving the button its "pressed" appearance - search_button->set_pressed(true); - } - - set_input_as_handled(); - } - } +void ProjectSettingsEditor::queue_save() { + timer->start(); } -void ProjectSettingsEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_VISIBILITY_CHANGED: { - if (!is_visible()) { - EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "project_settings", Rect2(get_position(), get_size())); - set_process_unhandled_input(false); - } - } break; - case NOTIFICATION_ENTER_TREE: { - globals_editor->edit(ProjectSettings::get_singleton()); - - search_button->set_icon(get_theme_icon("Search", "EditorIcons")); - search_box->set_right_icon(get_theme_icon("Search", "EditorIcons")); - search_box->set_clear_button_enabled(true); - - restart_close_button->set_icon(get_theme_icon("Close", "EditorIcons")); - restart_container->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); - restart_icon->set_texture(get_theme_icon("StatusWarning", "EditorIcons")); - restart_label->add_theme_color_override("font_color", get_theme_color("warning_color", "Editor")); - - } break; - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - search_button->set_icon(get_theme_icon("Search", "EditorIcons")); - search_box->set_right_icon(get_theme_icon("Search", "EditorIcons")); - search_box->set_clear_button_enabled(true); - } break; - } +void ProjectSettingsEditor::set_plugins_page() { + tab_container->set_current_tab(plugin_settings->get_index()); } void ProjectSettingsEditor::update_plugins() { plugin_settings->update_plugins(); } -void ProjectSettingsEditor::_item_selected(const String &p_path) { - const String &selected_path = p_path; - if (selected_path == String()) { - return; +void ProjectSettingsEditor::_setting_edited(const String &p_name) { + queue_save(); +} + +void ProjectSettingsEditor::_advanced_pressed() { + if (advanced->is_pressed()) { + _update_advanced_bar(); + advanced_bar->show(); + } else { + advanced_bar->hide(); } - category->set_text(globals_editor->get_current_section()); - property->set_text(selected_path); - popup_copy_to_feature->set_disabled(false); } -void ProjectSettingsEditor::_item_adds(String) { - _item_add(); +void ProjectSettingsEditor::_setting_selected(const String &p_path) { + if (p_path == String()) { + return; + } + + category_box->set_text(inspector->get_current_section()); + property_box->set_text(p_path); + + if (advanced_bar->is_visible()) { + _update_advanced_bar(); // set_text doesn't trigger text_changed + } } -void ProjectSettingsEditor::_item_add() { +void ProjectSettingsEditor::_add_setting() { + String setting = _get_setting_name(); + // Initialize the property with the default value for the given type. // The type list starts at 1 (as we exclude Nil), so add 1 to the selected value. Callable::CallError ce; const Variant value = Variant::construct(Variant::Type(type->get_selected() + 1), nullptr, 0, ce); - String catname = category->get_text().strip_edges(); - String propname = property->get_text().strip_edges(); + undo_redo->create_action(TTR("Add Project Setting")); + undo_redo->add_do_property(ps, setting, value); + undo_redo->add_undo_property(ps, setting, ps->has_setting(setting) ? ps->get(setting) : Variant()); - if (propname.empty()) { - return; - } + undo_redo->add_do_method(inspector, "update_category_list"); + undo_redo->add_undo_method(inspector, "update_category_list"); + undo_redo->add_do_method(this, "queue_save"); + undo_redo->add_undo_method(this, "queue_save"); + undo_redo->commit_action(); - if (catname.empty()) { - catname = "global"; - } + inspector->set_current_section(setting.get_slice("/", 1)); +} - String name = catname + "/" + propname; +void ProjectSettingsEditor::_delete_setting() { + String setting = _get_setting_name(); + Variant value = ps->get(setting); + int order = ps->get_order(setting); - undo_redo->create_action(TTR("Add Global Property")); + undo_redo->create_action(TTR("Delete Item")); - undo_redo->add_do_property(ProjectSettings::get_singleton(), name, value); + undo_redo->add_do_method(ps, "clear", setting); + undo_redo->add_undo_method(ps, "set", setting, value); + undo_redo->add_undo_method(ps, "set_order", setting, order); - if (ProjectSettings::get_singleton()->has_setting(name)) { - undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, ProjectSettings::get_singleton()->get(name)); - } else { - undo_redo->add_undo_property(ProjectSettings::get_singleton(), name, Variant()); - } + undo_redo->add_do_method(inspector, "update_category_list"); + undo_redo->add_undo_method(inspector, "update_category_list"); + undo_redo->add_do_method(this, "queue_save"); + undo_redo->add_undo_method(this, "queue_save"); - undo_redo->add_do_method(globals_editor, "update_category_list"); - undo_redo->add_undo_method(globals_editor, "update_category_list"); - undo_redo->add_do_method(this, "_settings_changed"); - undo_redo->add_undo_method(this, "_settings_changed"); undo_redo->commit_action(); - globals_editor->set_current_section(catname); - - _settings_changed(); + property_box->clear(); } -void ProjectSettingsEditor::_item_del() { - String path = globals_editor->get_inspector()->get_selected_path(); - if (path == String()) { - EditorNode::get_singleton()->show_warning(TTR("Select a setting item first!")); - return; - } +void ProjectSettingsEditor::_text_field_changed(const String &p_text) { + _update_advanced_bar(); +} - String property = globals_editor->get_current_section().plus_file(path); +void ProjectSettingsEditor::_feature_selected(int p_index) { + _update_advanced_bar(); +} - if (!ProjectSettings::get_singleton()->has_setting(property)) { - EditorNode::get_singleton()->show_warning(vformat(TTR("No property '%s' exists."), property)); - return; - } +void ProjectSettingsEditor::_update_advanced_bar() { + const String property_text = property_box->get_text().strip_edges(); - if (ProjectSettings::get_singleton()->get_order(property) < ProjectSettings::NO_BUILTIN_ORDER_BASE) { - EditorNode::get_singleton()->show_warning(vformat(TTR("Setting '%s' is internal, and it can't be deleted."), property)); - return; - } - - undo_redo->create_action(TTR("Delete Item")); + String error_msg = ""; + bool disable_add = true; + bool disable_del = true; - Variant value = ProjectSettings::get_singleton()->get(property); - int order = ProjectSettings::get_singleton()->get_order(property); + if (!property_box->get_text().empty()) { + const String setting = _get_setting_name(); + bool setting_exists = ps->has_setting(setting); + if (setting_exists) { + error_msg = TTR(" - Cannot add already existing setting."); - undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", property); - undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property, value); - undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set_order", property, order); + disable_del = ps->is_builtin_setting(setting); + if (disable_del) { + String msg = TTR(" - Cannot delete built-in setting."); + error_msg += (error_msg == "") ? msg : "\n" + msg; + } + } else { + bool bad_category = false; // Allow empty string. + Vector<String> cats = category_box->get_text().strip_edges().split("/"); + for (int i = 0; i < cats.size(); i++) { + if (!cats[i].is_valid_identifier()) { + bad_category = true; + error_msg = TTR(" - Invalid category name."); + break; + } + } - undo_redo->add_do_method(globals_editor, "update_category_list"); - undo_redo->add_undo_method(globals_editor, "update_category_list"); + disable_add = !bad_category; - undo_redo->add_do_method(this, "_settings_changed"); - undo_redo->add_undo_method(this, "_settings_changed"); + if (!property_text.is_valid_identifier()) { + disable_add = true; + String msg = TTR(" - Invalid property name."); + error_msg += (error_msg == "") ? msg : "\n" + msg; + } + } + } - undo_redo->commit_action(); -} + add_button->set_disabled(disable_add); + del_button->set_disabled(disable_del); -void ProjectSettingsEditor::_save() { - Error err = ProjectSettings::get_singleton()->save(); - message->set_text(err != OK ? TTR("Error saving settings.") : TTR("Settings saved OK.")); - message->popup_centered(Size2(300, 100) * EDSCALE); + error_label->set_text(error_msg); + error_label->set_visible(error_msg != ""); } -void ProjectSettingsEditor::_settings_prop_edited(const String &p_name) { - // Method needed to discard the mandatory argument of the property_edited signal - _settings_changed(); -} +String ProjectSettingsEditor::_get_setting_name() const { + const String cat = category_box->get_text(); + const String name = (cat.empty() ? "global" : cat.strip_edges()).plus_file(property_box->get_text().strip_edges()); + const String feature = feature_override->get_item_text(feature_override->get_selected()); -void ProjectSettingsEditor::_settings_changed() { - timer->start(); + return (feature == "") ? name : (name + "." + feature); } -void ProjectSettingsEditor::queue_save() { - _settings_changed(); -} - -void ProjectSettingsEditor::_copy_to_platform_about_to_show() { +void ProjectSettingsEditor::_add_feature_overrides() { Set<String> presets; presets.insert("bptc"); @@ -230,25 +210,26 @@ void ProjectSettingsEditor::_copy_to_platform_about_to_show() { presets.insert("standalone"); presets.insert("32"); presets.insert("64"); - // Not available as an export platform yet, so it needs to be added manually - presets.insert("Server"); + presets.insert("Server"); // Not available as an export platform yet, so it needs to be added manually - for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) { + EditorExport *ee = EditorExport::get_singleton(); + + for (int i = 0; i < ee->get_export_platform_count(); i++) { List<String> p; - EditorExport::get_singleton()->get_export_platform(i)->get_platform_features(&p); + ee->get_export_platform(i)->get_platform_features(&p); for (List<String>::Element *E = p.front(); E; E = E->next()) { presets.insert(E->get()); } } - for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { + for (int i = 0; i < ee->get_export_preset_count(); i++) { List<String> p; - EditorExport::get_singleton()->get_export_preset(i)->get_platform()->get_preset_features(EditorExport::get_singleton()->get_export_preset(i), &p); + ee->get_export_preset(i)->get_platform()->get_preset_features(ee->get_export_preset(i), &p); for (List<String>::Element *E = p.front(); E; E = E->next()) { presets.insert(E->get()); } - String custom = EditorExport::get_singleton()->get_export_preset(i)->get_custom_features(); + String custom = ee->get_export_preset(i)->get_custom_features(); Vector<String> custom_list = custom.split(","); for (int j = 0; j < custom_list.size(); j++) { String f = custom_list[j].strip_edges(); @@ -258,70 +239,14 @@ void ProjectSettingsEditor::_copy_to_platform_about_to_show() { } } - popup_copy_to_feature->get_popup()->clear(); - int id = 0; + feature_override->clear(); + feature_override->add_item("", 0); // So it is always on top. + int id = 1; for (Set<String>::Element *E = presets.front(); E; E = E->next()) { - popup_copy_to_feature->get_popup()->add_item(E->get(), id++); + feature_override->add_item(E->get(), id++); } } -void ProjectSettingsEditor::_copy_to_platform(int p_which) { - String path = globals_editor->get_inspector()->get_selected_path(); - if (path == String()) { - EditorNode::get_singleton()->show_warning(TTR("Select a setting item first!")); - return; - } - - String property = globals_editor->get_current_section().plus_file(path); - - undo_redo->create_action(TTR("Override for Feature")); - - Variant value = ProjectSettings::get_singleton()->get(property); - if (property.find(".") != -1) { //overwriting overwrite, keep overwrite - undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", property); - undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property, value); - } - - String feature = popup_copy_to_feature->get_popup()->get_item_text(p_which); - String new_path = property + "." + feature; - - undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", new_path, value); - if (ProjectSettings::get_singleton()->has_setting(new_path)) { - undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", new_path, ProjectSettings::get_singleton()->get(new_path)); - } - - undo_redo->add_do_method(globals_editor, "update_category_list"); - undo_redo->add_undo_method(globals_editor, "update_category_list"); - - undo_redo->add_do_method(this, "_settings_changed"); - undo_redo->add_undo_method(this, "_settings_changed"); - - undo_redo->commit_action(); -} - -void ProjectSettingsEditor::_toggle_search_bar(bool p_pressed) { - globals_editor->get_inspector()->set_use_filter(p_pressed); - - if (p_pressed) { - search_bar->show(); - add_prop_bar->hide(); - search_box->grab_focus(); - search_box->select_all(); - } else { - search_box->clear(); - search_bar->hide(); - add_prop_bar->show(); - } -} - -void ProjectSettingsEditor::set_plugins_page() { - tab_container->set_current_tab(plugin_settings->get_index()); -} - -TabContainer *ProjectSettingsEditor::get_tabs() { - return tab_container; -} - void ProjectSettingsEditor::_editor_restart() { EditorNode::get_singleton()->save_all_scenes(); EditorNode::get_singleton()->restart_editor(); @@ -335,17 +260,48 @@ void ProjectSettingsEditor::_editor_restart_close() { restart_container->hide(); } -void ProjectSettingsEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("_unhandled_input"), &ProjectSettingsEditor::_unhandled_input); - ClassDB::bind_method(D_METHOD("_save"), &ProjectSettingsEditor::_save); +void ProjectSettingsEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_VISIBILITY_CHANGED: { + if (!is_visible()) { + EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "project_settings", Rect2(get_position(), get_size())); + if (advanced->is_pressed()) { + advanced->set_pressed(false); + advanced_bar->hide(); + } + } + } break; + case NOTIFICATION_ENTER_TREE: { + inspector->edit(ps); + + error_label->add_theme_color_override("font_color", error_label->get_theme_color("error_color", "Editor")); + add_button->set_icon(get_theme_icon("Add", "EditorIcons")); + del_button->set_icon(get_theme_icon("Remove", "EditorIcons")); + + search_box->set_right_icon(get_theme_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); + + restart_close_button->set_icon(get_theme_icon("Close", "EditorIcons")); + restart_container->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); + restart_icon->set_texture(get_theme_icon("StatusWarning", "EditorIcons")); + restart_label->add_theme_color_override("font_color", get_theme_color("warning_color", "Editor")); + } break; + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + search_box->set_right_icon(get_theme_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); + } break; + } +} - ClassDB::bind_method(D_METHOD("get_tabs"), &ProjectSettingsEditor::get_tabs); +void ProjectSettingsEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("queue_save"), &ProjectSettingsEditor::queue_save); } ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { singleton = this; set_title(TTR("Project Settings (project.godot)")); + ps = ProjectSettings::get_singleton(); undo_redo = &p_data->get_undo_redo(); data = p_data; @@ -354,103 +310,110 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { tab_container->set_use_hidden_tabs_for_min_size(true); add_child(tab_container); - VBoxContainer *props_base = memnew(VBoxContainer); - props_base->set_name(TTR("General")); - props_base->set_alignment(BoxContainer::ALIGN_BEGIN); - props_base->set_v_size_flags(Control::SIZE_EXPAND_FILL); - tab_container->add_child(props_base); - - HBoxContainer *hbc = memnew(HBoxContainer); - hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); - props_base->add_child(hbc); - - search_button = memnew(Button); - search_button->set_text(TTR("Search")); - search_button->set_toggle_mode(true); - search_button->set_pressed(false); - search_button->connect("toggled", callable_mp(this, &ProjectSettingsEditor::_toggle_search_bar)); - hbc->add_child(search_button); - - hbc->add_child(memnew(VSeparator)); - - add_prop_bar = memnew(HBoxContainer); - add_prop_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL); - hbc->add_child(add_prop_bar); - - Label *l = memnew(Label); - l->set_text(TTR("Category:")); - add_prop_bar->add_child(l); - - category = memnew(LineEdit); - category->set_h_size_flags(Control::SIZE_EXPAND_FILL); - category->connect("text_entered", callable_mp(this, &ProjectSettingsEditor::_item_adds)); - add_prop_bar->add_child(category); - - l = memnew(Label); - l->set_text(TTR("Property:")); - add_prop_bar->add_child(l); - - property = memnew(LineEdit); - property->set_h_size_flags(Control::SIZE_EXPAND_FILL); - property->connect("text_entered", callable_mp(this, &ProjectSettingsEditor::_item_adds)); - add_prop_bar->add_child(property); - - l = memnew(Label); - l->set_text(TTR("Type:")); - add_prop_bar->add_child(l); - - type = memnew(OptionButton); - type->set_h_size_flags(Control::SIZE_EXPAND_FILL); - add_prop_bar->add_child(type); - - // Start at 1 to avoid adding "Nil" as an option - for (int i = 1; i < Variant::VARIANT_MAX; i++) { - type->add_item(Variant::get_type_name(Variant::Type(i))); + VBoxContainer *general_editor = memnew(VBoxContainer); + general_editor->set_name(TTR("General")); + general_editor->set_alignment(BoxContainer::ALIGN_BEGIN); + general_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); + tab_container->add_child(general_editor); + + VBoxContainer *header = memnew(VBoxContainer); + header->set_h_size_flags(Control::SIZE_EXPAND_FILL); + general_editor->add_child(header); + + { + // Search bar. + search_bar = memnew(HBoxContainer); + search_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL); + header->add_child(search_bar); + + search_box = memnew(LineEdit); + search_box->set_custom_minimum_size(Size2(300, 0)); + search_bar->add_child(search_box); + + search_bar->add_spacer(); + + advanced = memnew(CheckButton); + advanced->set_text(TTR("Advanced")); + advanced->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_advanced_pressed)); + search_bar->add_child(advanced); } - Button *add = memnew(Button); - add->set_text(TTR("Add")); - add->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_item_add)); - add_prop_bar->add_child(add); + { + // Advanced bar. + advanced_bar = memnew(VBoxContainer); + advanced_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL); + advanced_bar->hide(); + header->add_child(advanced_bar); + + HBoxContainer *hbc = memnew(HBoxContainer); + hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); + advanced_bar->add_margin_child(TTR("Add or remove custom project settings."), hbc, true); + + category_box = memnew(LineEdit); + category_box->set_custom_minimum_size(Size2(140, 0) * EDSCALE); + category_box->connect("text_changed", callable_mp(this, &ProjectSettingsEditor::_text_field_changed)); + category_box->set_placeholder(TTR("Category")); + hbc->add_child(category_box); + + Label *l = memnew(Label); + l->set_text("/"); + hbc->add_child(l); + + property_box = memnew(LineEdit); + property_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); + property_box->set_placeholder(TTR("Property")); + property_box->connect("text_changed", callable_mp(this, &ProjectSettingsEditor::_text_field_changed)); + hbc->add_child(property_box); + + l = memnew(Label); + l->set_text(TTR("Type:")); + hbc->add_child(l); + + type = memnew(OptionButton); + type->set_custom_minimum_size(Size2(70, 0) * EDSCALE); + hbc->add_child(type); + + // Start at 1 to avoid adding "Nil" as an option + for (int i = 1; i < Variant::VARIANT_MAX; i++) { + type->add_item(Variant::get_type_name(Variant::Type(i))); + } - search_bar = memnew(HBoxContainer); - search_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL); - search_bar->hide(); - hbc->add_child(search_bar); + l = memnew(Label); + l->set_text(TTR("Feature Override:")); + hbc->add_child(l); - search_box = memnew(LineEdit); - search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); - search_bar->add_child(search_box); + feature_override = memnew(OptionButton); + feature_override->set_custom_minimum_size(Size2(70, 0) * EDSCALE); + feature_override->connect("item_selected", callable_mp(this, &ProjectSettingsEditor::_feature_selected)); + hbc->add_child(feature_override); - globals_editor = memnew(SectionedInspector); - globals_editor->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo()); - globals_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); - globals_editor->register_search_box(search_box); - globals_editor->get_inspector()->connect("property_selected", callable_mp(this, &ProjectSettingsEditor::_item_selected)); - globals_editor->get_inspector()->connect("property_edited", callable_mp(this, &ProjectSettingsEditor::_settings_prop_edited)); - globals_editor->get_inspector()->connect("restart_requested", callable_mp(this, &ProjectSettingsEditor::_editor_restart_request)); - props_base->add_child(globals_editor); + hbc->add_spacer(); - Button *del = memnew(Button); - del->set_text(TTR("Delete")); - del->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_item_del)); - hbc->add_child(del); + add_button = memnew(Button); + add_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_add_setting)); + hbc->add_child(add_button); - add_prop_bar->add_child(memnew(VSeparator)); + del_button = memnew(Button); + del_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_delete_setting)); + hbc->add_child(del_button); - popup_copy_to_feature = memnew(MenuButton); - popup_copy_to_feature->set_text(TTR("Override For...")); - popup_copy_to_feature->set_disabled(true); - add_prop_bar->add_child(popup_copy_to_feature); + error_label = memnew(Label); + advanced_bar->add_child(error_label); + } - popup_copy_to_feature->get_popup()->connect("id_pressed", callable_mp(this, &ProjectSettingsEditor::_copy_to_platform)); - popup_copy_to_feature->get_popup()->connect("about_to_popup", callable_mp(this, &ProjectSettingsEditor::_copy_to_platform_about_to_show)); + header->add_child(memnew(HSeparator)); - get_ok()->set_text(TTR("Close")); - set_hide_on_ok(true); + inspector = memnew(SectionedInspector); + inspector->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo()); + inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL); + inspector->register_search_box(search_box); + inspector->get_inspector()->connect("property_selected", callable_mp(this, &ProjectSettingsEditor::_setting_selected)); + inspector->get_inspector()->connect("property_edited", callable_mp(this, &ProjectSettingsEditor::_setting_edited)); + inspector->get_inspector()->connect("restart_requested", callable_mp(this, &ProjectSettingsEditor::_editor_restart_request)); + general_editor->add_child(inspector); restart_container = memnew(PanelContainer); - props_base->add_child(restart_container); + general_editor->add_child(restart_container); HBoxContainer *restart_hb = memnew(HBoxContainer); restart_container->hide(); @@ -475,27 +438,24 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { restart_close_button->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_editor_restart_close)); restart_hb->add_child(restart_close_button); - message = memnew(AcceptDialog); - add_child(message); - inputmap_editor = memnew(InputMapEditor); inputmap_editor->set_name(TTR("Input Map")); - inputmap_editor->connect("inputmap_changed", callable_mp(this, &ProjectSettingsEditor::_settings_changed)); + inputmap_editor->connect("inputmap_changed", callable_mp(this, &ProjectSettingsEditor::queue_save)); tab_container->add_child(inputmap_editor); localization_editor = memnew(LocalizationEditor); localization_editor->set_name(TTR("Localization")); - localization_editor->connect("localization_changed", callable_mp(this, &ProjectSettingsEditor::_settings_changed)); + localization_editor->connect("localization_changed", callable_mp(this, &ProjectSettingsEditor::queue_save)); tab_container->add_child(localization_editor); autoload_settings = memnew(EditorAutoloadSettings); autoload_settings->set_name(TTR("AutoLoad")); - autoload_settings->connect("autoload_changed", callable_mp(this, &ProjectSettingsEditor::_settings_changed)); + autoload_settings->connect("autoload_changed", callable_mp(this, &ProjectSettingsEditor::queue_save)); tab_container->add_child(autoload_settings); shaders_global_variables_editor = memnew(ShaderGlobalsEditor); shaders_global_variables_editor->set_name(TTR("Shader Globals")); - shaders_global_variables_editor->connect("globals_changed", callable_mp(this, &ProjectSettingsEditor::_settings_changed)); + shaders_global_variables_editor->connect("globals_changed", callable_mp(this, &ProjectSettingsEditor::queue_save)); tab_container->add_child(shaders_global_variables_editor); plugin_settings = memnew(EditorPluginSettings); @@ -504,7 +464,10 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { timer = memnew(Timer); timer->set_wait_time(1.5); - timer->connect("timeout", callable_mp(ProjectSettings::get_singleton(), &ProjectSettings::save)); + timer->connect("timeout", callable_mp(ps, &ProjectSettings::save)); timer->set_one_shot(true); add_child(timer); + + get_ok()->set_text(TTR("Close")); + set_hide_on_ok(true); } diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index c99c2fe9a2..0d7e19b242 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -35,12 +35,11 @@ #include "editor/editor_data.h" #include "editor/editor_plugin_settings.h" #include "editor/editor_sectioned_inspector.h" +#include "editor/input_map_editor.h" +#include "editor/localization_editor.h" +#include "editor/shader_globals_editor.h" #include "editor_autoload_settings.h" -#include "input_map_editor.h" -#include "localization_editor.h" -#include "scene/gui/dialogs.h" #include "scene/gui/tab_container.h" -#include "shader_globals_editor.h" class ProjectSettingsEditor : public AcceptDialog { GDCLASS(ProjectSettingsEditor, AcceptDialog); @@ -53,28 +52,31 @@ class ProjectSettingsEditor : public AcceptDialog { INPUT_MOUSE_BUTTON }; - TabContainer *tab_container; - AcceptDialog *message; + static ProjectSettingsEditor *singleton; + ProjectSettings *ps; Timer *timer; - HBoxContainer *search_bar; - Button *search_button; - LineEdit *search_box; - HBoxContainer *add_prop_bar; - LineEdit *category; - LineEdit *property; - OptionButton *type; - - SectionedInspector *globals_editor; - - MenuButton *popup_copy_to_feature; - + TabContainer *tab_container; + SectionedInspector *inspector; InputMapEditor *inputmap_editor; LocalizationEditor *localization_editor; EditorAutoloadSettings *autoload_settings; ShaderGlobalsEditor *shaders_global_variables_editor; EditorPluginSettings *plugin_settings; + HBoxContainer *search_bar; + LineEdit *search_box; + CheckButton *advanced; + + VBoxContainer *advanced_bar; + LineEdit *category_box; + LineEdit *property_box; + Button *add_button; + Button *del_button; + OptionButton *type; + OptionButton *feature_override; + Label *error_label; + Label *restart_label; TextureRect *restart_icon; PanelContainer *restart_container; @@ -83,30 +85,25 @@ class ProjectSettingsEditor : public AcceptDialog { EditorData *data; UndoRedo *undo_redo; - void _item_selected(const String &); - void _item_adds(String); - void _item_add(); - void _item_del(); - void _save(); - - void _settings_prop_edited(const String &p_name); - void _settings_changed(); + void _advanced_pressed(); + void _update_advanced_bar(); + void _text_field_changed(const String &p_text); + void _feature_selected(int p_index); - void _copy_to_platform(int p_which); - void _copy_to_platform_about_to_show(); - - void _toggle_search_bar(bool p_pressed); - - ProjectSettingsEditor(); - - static ProjectSettingsEditor *singleton; + String _get_setting_name() const; + void _setting_edited(const String &p_name); + void _setting_selected(const String &p_path); + void _add_setting(); + void _delete_setting(); void _editor_restart_request(); void _editor_restart(); void _editor_restart_close(); + void _add_feature_overrides(); + ProjectSettingsEditor(); + protected: - void _unhandled_input(const Ref<InputEvent> &p_event); void _notification(int p_what); static void _bind_methods(); @@ -117,8 +114,7 @@ public: void update_plugins(); EditorAutoloadSettings *get_autoload_settings() { return autoload_settings; } - - TabContainer *get_tabs(); + TabContainer *get_tabs() { return tab_container; } void queue_save(); diff --git a/main/main.cpp b/main/main.cpp index 5f791159f9..c5500a1f66 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -372,7 +372,7 @@ void Main::print_help(const char *p_binary) { int Main::test_entrypoint(int argc, char *argv[], bool &tests_need_run) { #ifdef TESTS_ENABLED for (int x = 0; x < argc; x++) { - if (strncmp(argv[x], "--test", 6) == 0) { + if ((strncmp(argv[x], "--test", 6) == 0) && (strlen(argv[x]) == 6)) { tests_need_run = true; OS::get_singleton()->initialize(); StringName::setup(); diff --git a/misc/dist/linux/x-godot-project.xml b/misc/dist/linux/x-godot-project.xml index 0572e4e54e..9f28bab2ae 100644 --- a/misc/dist/linux/x-godot-project.xml +++ b/misc/dist/linux/x-godot-project.xml @@ -1,8 +1,8 @@ <?xml version="1.0"?> - <mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'> - <mime-type type="application/x-godot-project"> - <comment>Godot Engine project</comment> - <icon name="godot" /> - <glob pattern="*.godot" weight="100" /> +<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> + <mime-type type="application/x-godot-project"> + <comment>Godot Engine project</comment> + <icon name="godot" /> + <glob pattern="*.godot" weight="100" /> </mime-type> </mime-info> diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 5c1144b875..32c3240a35 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -897,8 +897,7 @@ void RigidBodyBullet::on_exit_area(AreaBullet *p_area) { } void RigidBodyBullet::reload_space_override_modificator() { - // Make sure that kinematic bodies have their total gravity calculated - if (!is_active() && PhysicsServer3D::BODY_MODE_KINEMATIC != mode) { + if (mode == PhysicsServer3D::BODY_MODE_STATIC) { return; } diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 2b60f8df36..d0515e7c97 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -177,6 +177,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf bt_xform_to.getOrigin() += bt_motion; if ((bt_xform_to.getOrigin() - bt_xform_from.getOrigin()).fuzzyZero()) { + shape->destroy_bt_shape(btShape); return false; } diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 82a47f594b..8f2ebc7232 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -506,6 +506,12 @@ void CSGShape3D::_notification(int p_what) { _make_dirty(); } + if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { + if (use_collision && is_root_shape() && root_collision_instance.is_valid()) { + PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); + } + } + if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { if (parent) { parent->_make_dirty(); @@ -641,7 +647,7 @@ CSGShape3D::~CSGShape3D() { ////////////////////////////////// CSGBrush *CSGCombiner3D::_build_brush() { - return nullptr; //does not build anything + return memnew(CSGBrush); //does not build anything } CSGCombiner3D::CSGCombiner3D() { diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index aba3e07134..ae1f2893f1 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -82,6 +82,10 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) const String &str = text_edit->get_line(p_line); const int line_length = str.length(); Color prev_color; + + if (in_region != -1 && str.length() == 0) { + color_region_cache[p_line] = in_region; + } for (int j = 0; j < str.length(); j++) { Dictionary highlighter_info; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 597a79a40c..1e72216ad2 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -71,6 +71,10 @@ static StringName get_real_class_name(const StringName &p_source) { return p_source; } +void GDScriptAnalyzer::cleanup() { + underscore_map.clear(); +} + static GDScriptParser::DataType make_callable_type(const MethodInfo &p_info) { GDScriptParser::DataType type; type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; @@ -494,7 +498,7 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas if (member.variable->initializer != nullptr) { if (!is_type_compatible(datatype, member.variable->initializer->get_datatype(), true)) { - push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); + push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", member.variable->initializer->get_datatype().to_string(), datatype.to_string()), member.variable->initializer); } else if (datatype.builtin_type == Variant::INT && member.variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { #ifdef DEBUG_ENABLED parser->push_warning(member.variable->initializer, GDScriptWarning::NARROWING_CONVERSION); @@ -989,7 +993,7 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable if (p_variable->initializer != nullptr) { if (!is_type_compatible(type, p_variable->initializer->get_datatype(), true)) { - push_error(vformat(R"(Value of type "%s" cannot be assigned to variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer); + push_error(vformat(R"(Value of type "%s" cannot be assigned to a variable of type "%s".)", p_variable->initializer->get_datatype().to_string(), type.to_string()), p_variable->initializer); #ifdef DEBUG_ENABLED } else if (type.builtin_type == Variant::INT && p_variable->initializer->get_datatype().builtin_type == Variant::FLOAT) { parser->push_warning(p_variable->initializer, GDScriptWarning::NARROWING_CONVERSION); @@ -1369,11 +1373,61 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig push_error("Cannot assign a new value to a constant.", p_assignment->assignee); } - if (!is_type_compatible(p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), true)) { - if (p_assignment->assignee->get_datatype().is_hard_type()) { - push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value); + Variant::Operator vop = Variant::Operator::OP_EQUAL; + switch (p_assignment->operation) { + case GDScriptParser::AssignmentNode::OP_NONE: + vop = Variant::Operator::OP_EQUAL; + break; + case GDScriptParser::AssignmentNode::OP_ADDITION: + vop = Variant::Operator::OP_ADD; + break; + case GDScriptParser::AssignmentNode::OP_SUBTRACTION: + vop = Variant::Operator::OP_SUBTRACT; + break; + case GDScriptParser::AssignmentNode::OP_MULTIPLICATION: + vop = Variant::Operator::OP_MULTIPLY; + break; + case GDScriptParser::AssignmentNode::OP_DIVISION: + vop = Variant::Operator::OP_DIVIDE; + break; + case GDScriptParser::AssignmentNode::OP_MODULO: + vop = Variant::Operator::OP_MODULE; + break; + case GDScriptParser::AssignmentNode::OP_BIT_SHIFT_LEFT: + vop = Variant::Operator::OP_SHIFT_LEFT; + break; + case GDScriptParser::AssignmentNode::OP_BIT_SHIFT_RIGHT: + vop = Variant::Operator::OP_SHIFT_RIGHT; + break; + case GDScriptParser::AssignmentNode::OP_BIT_AND: + vop = Variant::Operator::OP_BIT_AND; + break; + case GDScriptParser::AssignmentNode::OP_BIT_OR: + vop = Variant::Operator::OP_BIT_OR; + break; + case GDScriptParser::AssignmentNode::OP_BIT_XOR: + vop = Variant::Operator::OP_BIT_XOR; + break; + } + + if (!p_assignment->assignee->get_datatype().is_variant() && !p_assignment->assigned_value->get_datatype().is_variant()) { + bool compatible = true; + GDScriptParser::DataType op_type = p_assignment->assigned_value->get_datatype(); + if (vop != Variant::OP_EQUAL) { + op_type = get_operation_type(vop, p_assignment->assignee->get_datatype(), p_assignment->assigned_value->get_datatype(), compatible); + } + + if (compatible) { + compatible = is_type_compatible(p_assignment->assignee->get_datatype(), op_type, true); + if (!compatible) { + if (p_assignment->assignee->get_datatype().is_hard_type()) { + push_error(vformat(R"(Cannot assign a value of type "%s" to a target of type "%s".)", p_assignment->assigned_value->get_datatype().to_string(), p_assignment->assignee->get_datatype().to_string()), p_assignment->assigned_value); + } else { + // TODO: Warning in this case. + } + } } else { - // TODO: Warning in this case. + push_error(vformat(R"(Invalid operands "%s" and "%s" for assignment operator.)", p_assignment->assignee->get_datatype().to_string(), p_assignment->assigned_value->get_datatype().to_string()), p_assignment); } } @@ -1488,7 +1542,19 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o if (p_binary_op->left_operand->is_constant && p_binary_op->right_operand->is_constant) { p_binary_op->is_constant = true; if (p_binary_op->variant_op < Variant::OP_MAX) { - p_binary_op->reduced_value = Variant::evaluate(p_binary_op->variant_op, p_binary_op->left_operand->reduced_value, p_binary_op->right_operand->reduced_value); + bool valid = false; + Variant::evaluate(p_binary_op->variant_op, p_binary_op->left_operand->reduced_value, p_binary_op->right_operand->reduced_value, p_binary_op->reduced_value, valid); + if (!valid) { + if (p_binary_op->reduced_value.get_type() == Variant::STRING) { + push_error(vformat(R"(%s in operator %s.)", p_binary_op->reduced_value, Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); + } else { + push_error(vformat(R"(Invalid operands to operator %s, %s and %s.".)", + Variant::get_operator_name(p_binary_op->variant_op), + Variant::get_type_name(p_binary_op->left_operand->reduced_value.get_type()), + Variant::get_type_name(p_binary_op->right_operand->reduced_value.get_type())), + p_binary_op); + } + } } else { if (p_binary_op->operation == GDScriptParser::BinaryOpNode::OP_TYPE_TEST) { GDScriptParser::DataType test_type = right_type; diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index 85183d3272..06d3530cb6 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -113,6 +113,8 @@ public: Error analyze(); GDScriptAnalyzer(GDScriptParser *p_parser); + + static void cleanup(); }; #endif // GDSCRIPT_ANALYZER_H diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index af07457750..1f3e1c1e40 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -94,6 +94,10 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) { return Variant::VARIANT_MAX; } +void GDScriptParser::cleanup() { + builtin_types.clear(); +} + GDScriptFunctions::Function GDScriptParser::get_builtin_function(const StringName &p_name) { for (int i = 0; i < GDScriptFunctions::FUNC_MAX; i++) { if (p_name == GDScriptFunctions::get_func_name(GDScriptFunctions::Function(i))) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index a741ae0cc7..c9ab3d4e12 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1335,6 +1335,7 @@ public: void print_tree(const GDScriptParser &p_parser); }; #endif // DEBUG_ENABLED + static void cleanup(); }; #endif // GDSCRIPT_PARSER_H diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 23c7f97b5a..c554cbac05 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -35,6 +35,7 @@ #include "core/os/dir_access.h" #include "core/os/file_access.h" #include "gdscript.h" +#include "gdscript_analyzer.h" #include "gdscript_cache.h" #include "gdscript_tokenizer.h" @@ -148,4 +149,7 @@ void unregister_gdscript_types() { EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); gdscript_translation_parser_plugin.unref(); #endif // TOOLS_ENABLED + + GDScriptParser::cleanup(); + GDScriptAnalyzer::cleanup(); } diff --git a/platform/android/logo.png b/platform/android/logo.png Binary files differindex df445f6a9c..f44d360a25 100644 --- a/platform/android/logo.png +++ b/platform/android/logo.png diff --git a/platform/iphone/godot_view_renderer.mm b/platform/iphone/godot_view_renderer.mm index 1fc822b457..045fb451f0 100644 --- a/platform/iphone/godot_view_renderer.mm +++ b/platform/iphone/godot_view_renderer.mm @@ -44,7 +44,6 @@ @interface GodotViewRenderer () -@property(assign, nonatomic) BOOL hasFinishedLocaleSetup; @property(assign, nonatomic) BOOL hasFinishedProjectDataSetup; @property(assign, nonatomic) BOOL hasStartedMain; @property(assign, nonatomic) BOOL hasFinishedSetup; @@ -58,9 +57,8 @@ return NO; } - if (!self.hasFinishedLocaleSetup) { - [self setupLocaleAndUUID]; - return YES; + if (!OS::get_singleton()) { + exit(0); } if (!self.hasFinishedProjectDataSetup) { @@ -79,33 +77,6 @@ return NO; } -- (void)setupLocaleAndUUID { - self.hasFinishedLocaleSetup = YES; - - if (!OS::get_singleton()) { - exit(0); - } - - NSString *locale_code = [[NSLocale currentLocale] localeIdentifier]; - OSIPhone::get_singleton()->set_locale(String::utf8([locale_code UTF8String])); - - NSString *uuid; - if ([[UIDevice currentDevice] respondsToSelector:@selector(identifierForVendor)]) { - uuid = [UIDevice currentDevice].identifierForVendor.UUIDString; - } else { - // before iOS 6, so just generate an identifier and store it - uuid = [[NSUserDefaults standardUserDefaults] objectForKey:@"identiferForVendor"]; - if (!uuid) { - CFUUIDRef cfuuid = CFUUIDCreate(NULL); - uuid = [(NSString *)CFUUIDCreateString(NULL, cfuuid) autorelease]; - CFRelease(cfuuid); - [[NSUserDefaults standardUserDefaults] setObject:uuid forKey:@"identifierForVendor"]; - } - } - - OSIPhone::get_singleton()->set_unique_id(String::utf8([uuid UTF8String])); -} - - (void)setupProjectData { self.hasFinishedProjectDataSetup = YES; diff --git a/platform/iphone/logo.png b/platform/iphone/logo.png Binary files differindex 405b6f93ca..966d8aa70a 100644 --- a/platform/iphone/logo.png +++ b/platform/iphone/logo.png diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index f3bde46717..c6f95869ee 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -84,8 +84,6 @@ private: virtual void finalize() override; String user_data_dir; - String unique_id; - String locale_code; bool is_focused = false; @@ -118,10 +116,8 @@ public: void set_user_data_dir(String p_dir); virtual String get_user_data_dir() const override; - void set_locale(String p_locale); virtual String get_locale() const override; - void set_unique_id(String p_id); virtual String get_unique_id() const override; virtual void vibrate_handheld(int p_duration_ms = 500) override; diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm index f0bbbd39ca..a7366ffdec 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/iphone/os_iphone.mm @@ -305,20 +305,20 @@ String OSIPhone::get_user_data_dir() const { return user_data_dir; } -void OSIPhone::set_locale(String p_locale) { - locale_code = p_locale; -} - String OSIPhone::get_locale() const { - return locale_code; -} + NSString *preferedLanguage = [NSLocale preferredLanguages].firstObject; + + if (preferedLanguage) { + return String::utf8([preferedLanguage UTF8String]).replace("-", "_"); + } -void OSIPhone::set_unique_id(String p_id) { - unique_id = p_id; + NSString *localeIdentifier = [[NSLocale currentLocale] localeIdentifier]; + return String::utf8([localeIdentifier UTF8String]).replace("-", "_"); } String OSIPhone::get_unique_id() const { - return unique_id; + NSString *uuid = [UIDevice currentDevice].identifierForVendor.UUIDString; + return String::utf8([uuid UTF8String]); } void OSIPhone::vibrate_handheld(int p_duration_ms) { diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index ae45e0734d..0cf02ef69b 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -95,8 +95,8 @@ protected: virtual void get_export_options(List<ExportOption> *r_options) override; public: - virtual String get_name() const override { return "Mac OSX"; } - virtual String get_os_name() const override { return "OSX"; } + virtual String get_name() const override { return "macOS"; } + virtual String get_os_name() const override { return "macOS"; } virtual Ref<Texture2D> get_logo() const override { return logo; } virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override { diff --git a/platform/osx/logo.png b/platform/osx/logo.png Binary files differindex 834bbf3ba6..b5a660b165 100644 --- a/platform/osx/logo.png +++ b/platform/osx/logo.png diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index b974dc2897..e17085cafc 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1631,7 +1631,7 @@ void TextEdit::_notification(int p_what) { DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id()); } - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) { + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true); } } break; @@ -1647,7 +1647,7 @@ void TextEdit::_notification(int p_what) { ime_text = ""; ime_selection = Point2(); - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) { + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { DisplayServer::get_singleton()->virtual_keyboard_hide(); } } break; @@ -6693,6 +6693,10 @@ void TextEdit::set_shortcut_keys_enabled(bool p_enabled) { _generate_context_menu(); } +void TextEdit::set_virtual_keyboard_enabled(bool p_enable) { + virtual_keyboard_enabled = p_enable; +} + void TextEdit::set_selecting_enabled(bool p_enabled) { selecting_enabled = p_enabled; @@ -6711,6 +6715,10 @@ bool TextEdit::is_shortcut_keys_enabled() const { return shortcut_keys_enabled; } +bool TextEdit::is_virtual_keyboard_enabled() const { + return virtual_keyboard_enabled; +} + PopupMenu *TextEdit::get_menu() const { return menu; } @@ -6763,6 +6771,8 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &TextEdit::is_context_menu_enabled); ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enable"), &TextEdit::set_shortcut_keys_enabled); ClassDB::bind_method(D_METHOD("is_shortcut_keys_enabled"), &TextEdit::is_shortcut_keys_enabled); + ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled", "enable"), &TextEdit::set_virtual_keyboard_enabled); + ClassDB::bind_method(D_METHOD("is_virtual_keyboard_enabled"), &TextEdit::is_virtual_keyboard_enabled); ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &TextEdit::set_selecting_enabled); ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &TextEdit::is_selecting_enabled); @@ -6854,6 +6864,7 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed"); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 5a6ed99845..a6bc9963cc 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -386,6 +386,8 @@ private: bool context_menu_enabled; bool shortcut_keys_enabled; + bool virtual_keyboard_enabled = true; + int executing_line; void _generate_context_menu(); @@ -749,6 +751,9 @@ public: void set_shortcut_keys_enabled(bool p_enabled); bool is_shortcut_keys_enabled() const; + void set_virtual_keyboard_enabled(bool p_enable); + bool is_virtual_keyboard_enabled() const; + PopupMenu *get_menu() const; String get_text_for_completion(); diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 2449b3bd35..adefb53862 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -880,7 +880,10 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p if (n->get_script_instance()) { n->get_script_instance()->call(p_method, (const Variant **)v, 1, err); } - n->call(p_method, (const Variant **)v, 1, err); + MethodBind *method = ClassDB::get_method(n->get_class_name(), p_method); + if (method) { + method->call(n, (const Variant **)v, 1, err); + } } call_lock--; diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp index 9c8f9334a9..4479b822c0 100644 --- a/scene/resources/syntax_highlighter.cpp +++ b/scene/resources/syntax_highlighter.cpp @@ -158,6 +158,10 @@ Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) { const String &str = text_edit->get_line(p_line); const int line_length = str.length(); Color prev_color; + + if (in_region != -1 && str.length() == 0) { + color_region_cache[p_line] = in_region; + } for (int j = 0; j < line_length; j++) { Dictionary highlighter_info; |