From ea13ff860de2227ad343b8a2d9a2e37150473d09 Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 1 Sep 2021 01:17:33 +0200 Subject: [PATCH 01/17] implement individual mesh transform for meshlibrary items (cherry picked from commit 70108fd8509a09230933872c3042a7c7ef2545b8) --- doc/classes/MeshLibrary.xml | 15 +++++ editor/editor_node.cpp | 6 +- editor/editor_node.h | 1 + editor/plugins/mesh_library_editor_plugin.cpp | 62 +++++++++++++------ editor/plugins/mesh_library_editor_plugin.h | 14 +++-- modules/gridmap/grid_map.cpp | 2 +- modules/gridmap/grid_map_editor_plugin.cpp | 6 ++ scene/resources/mesh_library.cpp | 19 ++++++ scene/resources/mesh_library.h | 3 + 9 files changed, 101 insertions(+), 27 deletions(-) diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml index 342432d7498..06f6551eda7 100644 --- a/doc/classes/MeshLibrary.xml +++ b/doc/classes/MeshLibrary.xml @@ -45,6 +45,13 @@ Returns the item's mesh. + + + + + Returns the transform applied to the item's mesh. + + @@ -102,6 +109,14 @@ Sets the item's mesh. + + + + + + Sets the transform to apply to the item's mesh. + + diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 4b59d047fb9..7788e6f448f 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1727,7 +1727,7 @@ void EditorNode::_dialog_action(String p_file) { ml = Ref(memnew(MeshLibrary)); } - MeshLibraryEditor::update_library_file(editor_data.get_edited_scene_root(), ml, true); + MeshLibraryEditor::update_library_file(editor_data.get_edited_scene_root(), ml, true, file_export_lib_apply_xforms->is_pressed()); Error err = ResourceSaver::save(p_file, ml); if (err) { @@ -6751,6 +6751,10 @@ EditorNode::EditorNode() { file_export_lib_merge->set_text(TTR("Merge With Existing")); file_export_lib_merge->set_pressed(true); file_export_lib->get_vbox()->add_child(file_export_lib_merge); + file_export_lib_apply_xforms = memnew(CheckBox); + file_export_lib_apply_xforms->set_text(TTR("Apply MeshInstance Transforms")); + file_export_lib_apply_xforms->set_pressed(false); + file_export_lib->get_vbox()->add_child(file_export_lib_apply_xforms); gui_base->add_child(file_export_lib); file_script = memnew(EditorFileDialog); diff --git a/editor/editor_node.h b/editor/editor_node.h index 70809015ee2..7ac9a16b07a 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -335,6 +335,7 @@ private: EditorFileDialog *file_script; EditorFileDialog *file_android_build_source; CheckBox *file_export_lib_merge; + CheckBox *file_export_lib_apply_xforms; String current_path; MenuButton *update_spinner; diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 9caa72d80a1..661f13d3c90 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -47,23 +47,25 @@ void MeshLibraryEditor::edit(const Ref &p_mesh_library) { } } -void MeshLibraryEditor::_menu_confirm() { +void MeshLibraryEditor::_menu_remove_confirm() { switch (option) { case MENU_OPTION_REMOVE_ITEM: { mesh_library->remove_item(to_erase); } break; - case MENU_OPTION_UPDATE_FROM_SCENE: { - String existing = mesh_library->get_meta("_editor_source_scene"); - ERR_FAIL_COND(existing == ""); - _import_scene_cbk(existing); - - } break; default: { }; } } -void MeshLibraryEditor::_import_scene(Node *p_scene, Ref p_library, bool p_merge) { +void MeshLibraryEditor::_menu_update_confirm(bool p_apply_xforms) { + cd_update->hide(); + apply_xforms = p_apply_xforms; + String existing = mesh_library->get_meta("_editor_source_scene"); + ERR_FAIL_COND(existing == ""); + _import_scene_cbk(existing); +} + +void MeshLibraryEditor::_import_scene(Node *p_scene, Ref p_library, bool p_merge, bool p_apply_xforms) { if (!p_merge) { p_library->clear(); } @@ -108,6 +110,13 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref p_library, } p_library->set_item_mesh(id, mesh); + + if (p_apply_xforms) { + p_library->set_item_mesh_transform(id, mi->get_transform()); + } else { + p_library->set_item_mesh_transform(id, Transform()); + } + mesh_instances[id] = mi; Vector collisions; @@ -197,15 +206,16 @@ void MeshLibraryEditor::_import_scene_cbk(const String &p_str) { ERR_FAIL_COND_MSG(!scene, "Cannot create an instance from PackedScene '" + p_str + "'."); - _import_scene(scene, mesh_library, option == MENU_OPTION_UPDATE_FROM_SCENE); + _import_scene(scene, mesh_library, option == MENU_OPTION_UPDATE_FROM_SCENE, apply_xforms); memdelete(scene); mesh_library->set_meta("_editor_source_scene", p_str); + menu->get_popup()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), false); } -Error MeshLibraryEditor::update_library_file(Node *p_base_scene, Ref ml, bool p_merge) { - _import_scene(p_base_scene, ml, p_merge); +Error MeshLibraryEditor::update_library_file(Node *p_base_scene, Ref ml, bool p_merge, bool p_apply_xforms) { + _import_scene(p_base_scene, ml, p_merge, p_apply_xforms); return OK; } @@ -219,23 +229,29 @@ void MeshLibraryEditor::_menu_cbk(int p_option) { String p = editor->get_inspector()->get_selected_path(); if (p.begins_with("/MeshLibrary/item") && p.get_slice_count("/") >= 3) { to_erase = p.get_slice("/", 3).to_int(); - cd->set_text(vformat(TTR("Remove item %d?"), to_erase)); - cd->popup_centered(Size2(300, 60)); + cd_remove->set_text(vformat(TTR("Remove item %d?"), to_erase)); + cd_remove->popup_centered(Size2(300, 60)); } } break; case MENU_OPTION_IMPORT_FROM_SCENE: { + apply_xforms = false; + file->popup_centered_ratio(); + } break; + case MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS: { + apply_xforms = true; file->popup_centered_ratio(); } break; case MENU_OPTION_UPDATE_FROM_SCENE: { - cd->set_text(vformat(TTR("Update from existing scene?:\n%s"), String(mesh_library->get_meta("_editor_source_scene")))); - cd->popup_centered(Size2(500, 60)); + cd_update->set_text(vformat(TTR("Update from existing scene?:\n%s"), String(mesh_library->get_meta("_editor_source_scene")))); + cd_update->popup_centered(Size2(500, 60)); } break; } } void MeshLibraryEditor::_bind_methods() { ClassDB::bind_method("_menu_cbk", &MeshLibraryEditor::_menu_cbk); - ClassDB::bind_method("_menu_confirm", &MeshLibraryEditor::_menu_confirm); + ClassDB::bind_method("_menu_remove_confirm", &MeshLibraryEditor::_menu_remove_confirm); + ClassDB::bind_method("_menu_update_confirm", &MeshLibraryEditor::_menu_update_confirm); ClassDB::bind_method("_import_scene_cbk", &MeshLibraryEditor::_import_scene_cbk); } @@ -261,16 +277,22 @@ MeshLibraryEditor::MeshLibraryEditor(EditorNode *p_editor) { menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM); menu->get_popup()->add_item(TTR("Remove Selected Item"), MENU_OPTION_REMOVE_ITEM); menu->get_popup()->add_separator(); - menu->get_popup()->add_item(TTR("Import from Scene"), MENU_OPTION_IMPORT_FROM_SCENE); + menu->get_popup()->add_item(TTR("Import from Scene (Ignore Transforms)"), MENU_OPTION_IMPORT_FROM_SCENE); + menu->get_popup()->add_item(TTR("Import from Scene (Apply Transforms)"), MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS); menu->get_popup()->add_item(TTR("Update from Scene"), MENU_OPTION_UPDATE_FROM_SCENE); menu->get_popup()->set_item_disabled(menu->get_popup()->get_item_index(MENU_OPTION_UPDATE_FROM_SCENE), true); menu->get_popup()->connect("id_pressed", this, "_menu_cbk"); menu->hide(); editor = p_editor; - cd = memnew(ConfirmationDialog); - add_child(cd); - cd->get_ok()->connect("pressed", this, "_menu_confirm"); + cd_remove = memnew(ConfirmationDialog); + add_child(cd_remove); + cd_remove->get_ok()->connect("pressed", this, "_menu_remove_confirm"); + cd_update = memnew(ConfirmationDialog); + add_child(cd_update); + cd_update->get_ok()->set_text("Apply without Transforms"); + cd_update->get_ok()->connect("pressed", this, "_menu_update_confirm", varray(false)); + cd_update->add_button("Apply with Transforms")->connect("pressed", this, "_menu_update_confirm", varray(true)); } void MeshLibraryEditorPlugin::edit(Object *p_node) { diff --git a/editor/plugins/mesh_library_editor_plugin.h b/editor/plugins/mesh_library_editor_plugin.h index fbcd13575ca..17b8ecd82ca 100644 --- a/editor/plugins/mesh_library_editor_plugin.h +++ b/editor/plugins/mesh_library_editor_plugin.h @@ -41,8 +41,10 @@ class MeshLibraryEditor : public Control { EditorNode *editor; MenuButton *menu; - ConfirmationDialog *cd; + ConfirmationDialog *cd_remove; + ConfirmationDialog *cd_update; EditorFileDialog *file; + bool apply_xforms; int to_erase; enum { @@ -50,15 +52,17 @@ class MeshLibraryEditor : public Control { MENU_OPTION_ADD_ITEM, MENU_OPTION_REMOVE_ITEM, MENU_OPTION_UPDATE_FROM_SCENE, - MENU_OPTION_IMPORT_FROM_SCENE + MENU_OPTION_IMPORT_FROM_SCENE, + MENU_OPTION_IMPORT_FROM_SCENE_APPLY_XFORMS }; int option; void _import_scene_cbk(const String &p_str); void _menu_cbk(int p_option); - void _menu_confirm(); + void _menu_remove_confirm(); + void _menu_update_confirm(bool p_apply_xforms); - static void _import_scene(Node *p_scene, Ref p_library, bool p_merge); + static void _import_scene(Node *p_scene, Ref p_library, bool p_merge, bool p_apply_xforms); protected: static void _bind_methods(); @@ -67,7 +71,7 @@ public: MenuButton *get_menu_button() const { return menu; } void edit(const Ref &p_mesh_library); - static Error update_library_file(Node *p_base_scene, Ref ml, bool p_merge = true); + static Error update_library_file(Node *p_base_scene, Ref ml, bool p_merge = true, bool p_apply_xforms = false); MeshLibraryEditor(EditorNode *p_editor); }; diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index b173e743eef..027906a5b87 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -460,7 +460,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { } Pair p; - p.first = xform; + p.first = xform * mesh_library->get_item_mesh_transform(c.item); p.second = E->get(); multimesh_items[c.item].push_back(p); } diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 8a97d8156a6..8a4f0788655 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -261,6 +261,12 @@ void GridMapEditor::_update_cursor_transform() { cursor_transform.basis *= node->get_cell_scale(); cursor_transform = node->get_global_transform() * cursor_transform; + if (selected_palette >= 0) { + if (node && !node->get_mesh_library().is_null()) { + cursor_transform *= node->get_mesh_library()->get_item_mesh_transform(selected_palette); + } + } + if (cursor_instance.is_valid()) { VisualServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform); VisualServer::get_singleton()->instance_set_visible(cursor_instance, cursor_visible); diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index 6ab15a095c6..41144892f30 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -43,6 +43,8 @@ bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) { set_item_name(idx, p_value); } else if (what == "mesh") { set_item_mesh(idx, p_value); + } else if (what == "mesh_transform") { + set_item_mesh_transform(idx, p_value); } else if (what == "shape") { Vector shapes; ShapeData sd; @@ -77,6 +79,8 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_item_name(idx); } else if (what == "mesh") { r_ret = get_item_mesh(idx); + } else if (what == "mesh_transform") { + r_ret = get_item_mesh_transform(idx); } else if (what == "shapes") { r_ret = _get_item_shapes(idx); } else if (what == "navmesh") { @@ -127,6 +131,14 @@ void MeshLibrary::set_item_mesh(int p_item, const Ref &p_mesh) { _change_notify(); } +void MeshLibrary::set_item_mesh_transform(int p_item, const Transform &p_transform) { + ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); + item_map[p_item].mesh_transform = p_transform; + notify_change_to_owners(); + emit_changed(); + _change_notify(); +} + void MeshLibrary::set_item_shapes(int p_item, const Vector &p_shapes) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].shapes = p_shapes; @@ -170,6 +182,11 @@ Ref MeshLibrary::get_item_mesh(int p_item) const { return item_map[p_item].mesh; } +Transform MeshLibrary::get_item_mesh_transform(int p_item) const { + ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); + return item_map[p_item].mesh_transform; +} + Vector MeshLibrary::get_item_shapes(int p_item) const { ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Vector(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); return item_map[p_item].shapes; @@ -267,12 +284,14 @@ void MeshLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("create_item", "id"), &MeshLibrary::create_item); ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name); ClassDB::bind_method(D_METHOD("set_item_mesh", "id", "mesh"), &MeshLibrary::set_item_mesh); + ClassDB::bind_method(D_METHOD("set_item_mesh_transform", "id", "mesh_transform"), &MeshLibrary::set_item_mesh_transform); ClassDB::bind_method(D_METHOD("set_item_navmesh", "id", "navmesh"), &MeshLibrary::set_item_navmesh); ClassDB::bind_method(D_METHOD("set_item_navmesh_transform", "id", "navmesh"), &MeshLibrary::set_item_navmesh_transform); ClassDB::bind_method(D_METHOD("set_item_shapes", "id", "shapes"), &MeshLibrary::_set_item_shapes); ClassDB::bind_method(D_METHOD("set_item_preview", "id", "texture"), &MeshLibrary::set_item_preview); ClassDB::bind_method(D_METHOD("get_item_name", "id"), &MeshLibrary::get_item_name); ClassDB::bind_method(D_METHOD("get_item_mesh", "id"), &MeshLibrary::get_item_mesh); + ClassDB::bind_method(D_METHOD("get_item_mesh_transform", "id"), &MeshLibrary::get_item_mesh_transform); ClassDB::bind_method(D_METHOD("get_item_navmesh", "id"), &MeshLibrary::get_item_navmesh); ClassDB::bind_method(D_METHOD("get_item_navmesh_transform", "id"), &MeshLibrary::get_item_navmesh_transform); ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes); diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h index ddfbb3bbd14..7f8f6346e5d 100644 --- a/scene/resources/mesh_library.h +++ b/scene/resources/mesh_library.h @@ -52,6 +52,7 @@ public: Vector shapes; Ref preview; Transform navmesh_transform; + Transform mesh_transform; Ref navmesh; }; @@ -71,12 +72,14 @@ public: void create_item(int p_item); void set_item_name(int p_item, const String &p_name); void set_item_mesh(int p_item, const Ref &p_mesh); + void set_item_mesh_transform(int p_item, const Transform &p_transform); void set_item_navmesh(int p_item, const Ref &p_navmesh); void set_item_navmesh_transform(int p_item, const Transform &p_transform); void set_item_shapes(int p_item, const Vector &p_shapes); void set_item_preview(int p_item, const Ref &p_preview); String get_item_name(int p_item) const; Ref get_item_mesh(int p_item) const; + Transform get_item_mesh_transform(int p_item) const; Ref get_item_navmesh(int p_item) const; Transform get_item_navmesh_transform(int p_item) const; Vector get_item_shapes(int p_item) const; From 128208d1d0d40c644e10b9b63ca16f1cd8d77c37 Mon Sep 17 00:00:00 2001 From: Marcus Brummer Date: Sat, 21 Aug 2021 17:15:46 +0200 Subject: [PATCH 02/17] Check if vibration duration is > 0 on Android (cherry picked from commit 47f338fc128b0dfb4711689d2ab0c52c01b80514) --- platform/android/java/lib/src/org/godotengine/godot/Godot.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 5418f00bb7a..ab10d46fbb7 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -419,7 +419,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC @SuppressLint("MissingPermission") @Keep private void vibrate(int durationMs) { - if (requestPermission("VIBRATE")) { + if (durationMs > 0 && requestPermission("VIBRATE")) { Vibrator v = (Vibrator)getContext().getSystemService(Context.VIBRATOR_SERVICE); if (v != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { From 7f0094ca9f7c97404f8520a0b391f0993080af4a Mon Sep 17 00:00:00 2001 From: LoipesMas <46327403+LoipesMas@users.noreply.github.com> Date: Tue, 17 Aug 2021 20:05:38 +0200 Subject: [PATCH 03/17] Add note about batching to Line2D's anti-aliasing (cherry picked from commit b047430702206c9c1f467cc13f0263ddb4096524) --- doc/classes/Line2D.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml index b7c362a85b9..8c132e762a7 100644 --- a/doc/classes/Line2D.xml +++ b/doc/classes/Line2D.xml @@ -59,6 +59,7 @@ If [code]true[/code], the line's border will be anti-aliased. + [b]Note:[/b] Line2D is not accelerated by batching when being anti-aliased. Controls the style of the line's first point. Use [enum LineCapMode] constants. From 930a1ea746520838a1de98034479116b37f0a5e8 Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Tue, 24 Aug 2021 22:07:42 +0800 Subject: [PATCH 04/17] Make RichTextLabel honour default cursor shape property (cherry picked from commit d12cceadd211154cff09564e116ff04c1f276713) --- scene/gui/rich_text_label.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index ca3b2b9e876..8ee96d55f8f 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1090,7 +1090,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const { if (!underline_meta) { - return CURSOR_ARROW; + return get_default_cursor_shape(); } if (selection.click) { @@ -1098,10 +1098,11 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const } if (main->first_invalid_line < main->lines.size()) { - return CURSOR_ARROW; //invalid + return get_default_cursor_shape(); //invalid } int line = 0; + Item *item = nullptr; bool outside; ((RichTextLabel *)(this))->_find_click(main, p_pos, &item, &line, &outside); @@ -1110,7 +1111,7 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const return CURSOR_POINTING_HAND; } - return CURSOR_ARROW; + return get_default_cursor_shape(); } void RichTextLabel::_gui_input(Ref p_event) { From c4d0074aae43db94b6a53e10ea926f2b7e476b19 Mon Sep 17 00:00:00 2001 From: Duarte David Date: Sun, 22 Aug 2021 21:04:14 +0100 Subject: [PATCH 05/17] Fixes the normals of SphereMesh when the sphere/hemisphere is oblong (cherry picked from commit f4ac08a1826a8062f5206192d183d13a1c01c557) --- scene/resources/primitive_meshes.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index f4e58a21d9e..1d6f3e55ce4 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -1456,6 +1456,8 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const { int i, j, prevrow, thisrow, point; float x, y, z; + float scale = height * (is_hemisphere ? 1.0 : 0.5); + // set our bounding box PoolVector points; @@ -1479,7 +1481,7 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const { v /= (rings + 1); w = sin(Math_PI * v); - y = height * (is_hemisphere ? 1.0 : 0.5) * cos(Math_PI * v); + y = scale * cos(Math_PI * v); for (i = 0; i <= radial_segments; i++) { float u = i; @@ -1494,7 +1496,8 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const { } else { Vector3 p = Vector3(x * radius * w, y, z * radius * w); points.push_back(p); - normals.push_back(p.normalized()); + Vector3 normal = Vector3(x * radius * w * scale, y / scale, z * radius * w * scale); + normals.push_back(normal.normalized()); }; ADD_TANGENT(z, 0.0, -x, 1.0) uvs.push_back(Vector2(u, v)); From d1a4cb2beac8117c6ebee4e61d8ea0267d69f625 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Wed, 25 Aug 2021 17:05:16 +0200 Subject: [PATCH 06/17] Print colored diffs when there are formatting failures in CI This makes diffs more readable in CI logs. (cherry picked from commit 38424714b1d3c7e35fb0cb2de548338885a98c14) --- misc/scripts/black_format.sh | 2 +- misc/scripts/clang_format.sh | 2 +- misc/scripts/file_format.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/misc/scripts/black_format.sh b/misc/scripts/black_format.sh index f93e8cbc2a7..2ad9a238326 100755 --- a/misc/scripts/black_format.sh +++ b/misc/scripts/black_format.sh @@ -15,7 +15,7 @@ PY_FILES=$(find \( -path "./.git" \ \) -print) black -l 120 $PY_FILES -git diff > patch.patch +git diff --color > patch.patch # If no patch has been generated all is OK, clean up, and exit. if [ ! -s patch.patch ] ; then diff --git a/misc/scripts/clang_format.sh b/misc/scripts/clang_format.sh index 63c66d41c32..bcd63aa73ba 100755 --- a/misc/scripts/clang_format.sh +++ b/misc/scripts/clang_format.sh @@ -40,7 +40,7 @@ while IFS= read -rd '' f; do done done -git diff > patch.patch +git diff --color > patch.patch # If no patch has been generated all is OK, clean up, and exit. if [ ! -s patch.patch ] ; then diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh index 5f4d69a2854..be84daa7f4d 100755 --- a/misc/scripts/file_format.sh +++ b/misc/scripts/file_format.sh @@ -44,7 +44,7 @@ while IFS= read -rd '' f; do perl -i -pe 's/\x20== true//g' "$f" done -git diff > patch.patch +git diff --color > patch.patch # If no patch has been generated all is OK, clean up, and exit. if [ ! -s patch.patch ] ; then From e2b71de38b21a4293ca2d43494c0516021b79eb7 Mon Sep 17 00:00:00 2001 From: Paul Joannon Date: Sun, 12 Sep 2021 19:53:34 +0200 Subject: [PATCH 07/17] Improve C# method listing - implement CSharpInstance::get_method_list - loop through parent classes in CSharpInstance::get_method_list and CSharpScript::get_script_method_list (#46408) (cherry picked from commit 19f25b68475b63b8b5e781dd94da0212e5aacd61) --- modules/mono/csharp_script.cpp | 39 ++++++++++++++++++++++++++++++---- modules/mono/csharp_script.h | 2 +- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 10411f196c7..016d07aec56 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1630,6 +1630,28 @@ Variant::Type CSharpInstance::get_property_type(const StringName &p_name, bool * return Variant::NIL; } +void CSharpInstance::get_method_list(List *p_list) const { + if (!script->is_valid() || !script->script_class) + return; + + GD_MONO_SCOPE_THREAD_ATTACH; + + // TODO: We're filtering out constructors but there may be other methods unsuitable for explicit calls. + GDMonoClass *top = script->script_class; + + while (top && top != script->native) { + const Vector &methods = top->get_all_methods(); + for (int i = 0; i < methods.size(); ++i) { + MethodInfo minfo = methods[i]->get_method_info(); + if (minfo.name != CACHED_STRING_NAME(dotctor)) { + p_list->push_back(minfo); + } + } + + top = top->get_parent_class(); + } +} + bool CSharpInstance::has_method(const StringName &p_method) const { if (!script.is_valid()) return false; @@ -3034,10 +3056,19 @@ void CSharpScript::get_script_method_list(List *p_list) const { GD_MONO_SCOPE_THREAD_ATTACH; - // TODO: Filter out things unsuitable for explicit calls, like constructors. - const Vector &methods = script_class->get_all_methods(); - for (int i = 0; i < methods.size(); ++i) { - p_list->push_back(methods[i]->get_method_info()); + // TODO: We're filtering out constructors but there may be other methods unsuitable for explicit calls. + GDMonoClass *top = script_class; + + while (top && top != native) { + const Vector &methods = top->get_all_methods(); + for (int i = 0; i < methods.size(); ++i) { + MethodInfo minfo = methods[i]->get_method_info(); + if (minfo.name != CACHED_STRING_NAME(dotctor)) { + p_list->push_back(methods[i]->get_method_info()); + } + } + + top = top->get_parent_class(); } } diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index b19390a7c28..68eeb642161 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -255,7 +255,7 @@ public: virtual void get_property_list(List *p_properties) const; virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid) const; - /* TODO */ virtual void get_method_list(List *p_list) const {} + virtual void get_method_list(List *p_list) const; virtual bool has_method(const StringName &p_method) const; virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error); virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount); From 4d94aba0ede773f52cb327638d611b12dde5f54c Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Mon, 12 Apr 2021 16:59:23 +0200 Subject: [PATCH 08/17] Improve crash handler message display - State the Godot version and full hash in the backtrace. - Add decoration around the crash backtrace, both to make it stand out from other messages and help the user figure out what they should copy. (cherry picked from commit 8556dd1bef3e74e9cb8f0c7deb68c95ece1b8e11) --- platform/osx/crash_handler_osx.mm | 10 ++++++++++ platform/windows/crash_handler_windows.cpp | 10 ++++++++++ platform/x11/crash_handler_x11.cpp | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm index 416d4c93fc9..ded3db8b4fc 100644 --- a/platform/osx/crash_handler_osx.mm +++ b/platform/osx/crash_handler_osx.mm @@ -32,6 +32,8 @@ #include "core/os/os.h" #include "core/project_settings.h" +#include "core/version.h" +#include "core/version_hash.gen.h" #include "main/main.h" #include @@ -85,11 +87,18 @@ static void handle_crash(int sig) { } // Dump the backtrace to stderr with a message to the user + fprintf(stderr, "\n================================================================\n"); fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig); if (OS::get_singleton()->get_main_loop()) OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); + // Print the engine version just before, so that people are reminded to include the version in backtrace reports. + if (String(VERSION_HASH).length() != 0) { + fprintf(stderr, "Engine version: " VERSION_FULL_NAME " (" VERSION_HASH ")\n"); + } else { + fprintf(stderr, "Engine version: " VERSION_FULL_NAME "\n"); + } fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str()); char **strings = backtrace_symbols(bt_buffer, size); if (strings) { @@ -148,6 +157,7 @@ static void handle_crash(int sig) { free(strings); } fprintf(stderr, "-- END OF BACKTRACE --\n"); + fprintf(stderr, "================================================================\n"); // Abort to pass the error to the OS abort(); diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp index 3741aaab9a4..92541e231e6 100644 --- a/platform/windows/crash_handler_windows.cpp +++ b/platform/windows/crash_handler_windows.cpp @@ -32,6 +32,8 @@ #include "core/os/os.h" #include "core/project_settings.h" +#include "core/version.h" +#include "core/version_hash.gen.h" #include "main/main.h" #ifdef CRASH_HANDLER_EXCEPTION @@ -127,6 +129,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { return EXCEPTION_CONTINUE_SEARCH; } + fprintf(stderr, "\n================================================================\n"); fprintf(stderr, "%s: Program crashed\n", __FUNCTION__); if (OS::get_singleton()->get_main_loop()) @@ -175,6 +178,12 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { msg = proj_settings->get("debug/settings/crash_handler/message"); } + // Print the engine version just before, so that people are reminded to include the version in backtrace reports. + if (String(VERSION_HASH).length() != 0) { + fprintf(stderr, "Engine version: " VERSION_FULL_NAME " (" VERSION_HASH ")\n"); + } else { + fprintf(stderr, "Engine version: " VERSION_FULL_NAME "\n"); + } fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str()); int n = 0; @@ -200,6 +209,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) { } while (frame.AddrReturn.Offset != 0 && n < 256); fprintf(stderr, "-- END OF BACKTRACE --\n"); + fprintf(stderr, "================================================================\n"); SymCleanup(process); diff --git a/platform/x11/crash_handler_x11.cpp b/platform/x11/crash_handler_x11.cpp index 2bdc11d2c3c..d38e527b1fa 100644 --- a/platform/x11/crash_handler_x11.cpp +++ b/platform/x11/crash_handler_x11.cpp @@ -32,6 +32,8 @@ #include "core/os/os.h" #include "core/project_settings.h" +#include "core/version.h" +#include "core/version_hash.gen.h" #include "main/main.h" #ifdef DEBUG_ENABLED @@ -61,12 +63,19 @@ static void handle_crash(int sig) { } // Dump the backtrace to stderr with a message to the user + fprintf(stderr, "\n================================================================\n"); fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig); if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); } + // Print the engine version just before, so that people are reminded to include the version in backtrace reports. + if (String(VERSION_HASH).length() != 0) { + fprintf(stderr, "Engine version: " VERSION_FULL_NAME " (" VERSION_HASH ")\n"); + } else { + fprintf(stderr, "Engine version: " VERSION_FULL_NAME "\n"); + } fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str()); char **strings = backtrace_symbols(bt_buffer, size); if (strings) { @@ -115,6 +124,7 @@ static void handle_crash(int sig) { free(strings); } fprintf(stderr, "-- END OF BACKTRACE --\n"); + fprintf(stderr, "================================================================\n"); // Abort to pass the error to the OS abort(); From 9aee1a399242fb44b65674e06a83aa97ab4db290 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Sun, 22 Aug 2021 02:21:06 +0200 Subject: [PATCH 09/17] Document `Image.generate_mipmaps()` always running on the main thread (cherry picked from commit 30a88f464ba6e0dc08b7cc84029df0e50e1a75b6) --- doc/classes/Image.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index e670cf91a34..60cc13fb628 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -163,6 +163,7 @@ Generates mipmaps for the image. Mipmaps are precalculated lower-resolution copies of the image that are automatically used if the image needs to be scaled down when rendered. They help improve image quality and performance when rendering. This method returns an error if the image is compressed, in a custom format, or if the image's width/height is [code]0[/code]. + [b]Note:[/b] Mipmap generation is done on the CPU, is single-threaded and is [i]always[/i] done on the main thread. This means generating mipmaps will result in noticeable stuttering during gameplay, even if [method generate_mipmaps] is called from a [Thread]. From 6a7ca4329795323beb2a8944d61cbe816e6da275 Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Wed, 25 Aug 2021 03:24:57 +0200 Subject: [PATCH 10/17] Expose `String.SimplifyPath` in C# (cherry picked from commit 126b1ea1493f603684a361f92865d4c80bca0ed4) --- .../GodotSharp/GodotSharp/Core/StringExtensions.cs | 11 +++++++++++ modules/mono/glue/string_glue.cpp | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs index 34da29bdf50..dcb51267be4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs @@ -1126,6 +1126,17 @@ namespace Godot return 2.0f * inter / sum; } + /// + /// Returns a simplified canonical path. + /// + public static string SimplifyPath(this string instance) + { + return godot_icall_String_simplify_path(instance); + } + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static string godot_icall_String_simplify_path(string str); + /// /// Split the string by a divisor string, return an array of the substrings. /// Example "One,Two,Three" will return ["One","Two","Three"] if split by ",". diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp index 08b04d45b55..15addb3be3a 100644 --- a/modules/mono/glue/string_glue.cpp +++ b/modules/mono/glue/string_glue.cpp @@ -67,6 +67,11 @@ MonoString *godot_icall_String_sha256_text(MonoString *p_str) { return GDMonoMarshal::mono_string_from_godot(ret); } +MonoString *godot_icall_String_simplify_path(MonoString *p_str) { + String ret = GDMonoMarshal::mono_string_to_godot(p_str).simplify_path(); + return GDMonoMarshal::mono_string_from_godot(ret); +} + void godot_register_string_icalls() { GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_buffer", godot_icall_String_md5_buffer); GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_text", godot_icall_String_md5_text); @@ -74,6 +79,7 @@ void godot_register_string_icalls() { GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfindn", godot_icall_String_rfindn); GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", godot_icall_String_sha256_buffer); GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", godot_icall_String_sha256_text); + GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_simplify_path", godot_icall_String_simplify_path); } #endif // MONO_GLUE_ENABLED From b0cb253a515e5576119d78b6439adeaf2d4b0514 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gilles=20Roudi=C3=A8re?= Date: Thu, 26 Aug 2021 11:54:56 +0200 Subject: [PATCH 11/17] Fix LocalVector crash on insert. (cherry picked from commit de0765b94a9e62a0b9a5f35dbf262c14b1655815) --- core/local_vector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/local_vector.h b/core/local_vector.h index f42456ac059..8a571c8a346 100644 --- a/core/local_vector.h +++ b/core/local_vector.h @@ -169,7 +169,7 @@ public: push_back(p_val); } else { resize(count + 1); - for (U i = count; i > p_pos; i--) { + for (U i = count - 1; i > p_pos; i--) { data[i] = data[i - 1]; } data[p_pos] = p_val; From 4e68f089e0be3604d5d83a6cdc62b15202c68fdb Mon Sep 17 00:00:00 2001 From: Lewis Pollard Date: Sun, 15 Nov 2020 19:10:19 +0000 Subject: [PATCH 12/17] Fix is_playing() method in AnimatedSprite3D (cherry picked from commit 2450173495b6766cb1a2015b83d4cc9f17b17af5) --- scene/3d/sprite_3d.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 8c59aab869c..bf4df19fdd5 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -1131,7 +1131,7 @@ void AnimatedSprite3D::stop() { } bool AnimatedSprite3D::is_playing() const { - return is_processing(); + return playing; } void AnimatedSprite3D::_reset_timeout() { From b36b81cbdd9b07936b7f0ebf278e882f970badf9 Mon Sep 17 00:00:00 2001 From: Yuri Roubinsky Date: Wed, 11 Aug 2021 17:43:05 +0300 Subject: [PATCH 13/17] Better port handling connection for `GraphEdit` (cherry picked from commit 61904d56eac35b81f55e0ed73ee3320e21ea7241) --- doc/classes/GraphEdit.xml | 2 +- scene/gui/graph_edit.cpp | 43 ++++++++++++++----- scene/gui/graph_edit.h | 2 +- .../resources/default_theme/default_theme.cpp | 3 +- 4 files changed, 36 insertions(+), 14 deletions(-) diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index 4606151a7d7..a4e457a1519 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -285,7 +285,7 @@ The icon for the zoom in button. - + The horizontal range within which a port can be grabbed (on both sides). diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 8a18870589d..774f6672088 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -520,6 +520,7 @@ void GraphEdit::_notification(int p_what) { bool GraphEdit::_filter_input(const Point2 &p_point) { Ref port = get_icon("port", "GraphNode"); + Vector2i port_size = Vector2i(port->get_width(), port->get_height()); for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to(get_child(i)); @@ -529,14 +530,14 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); - if (is_in_hot_zone(pos / zoom, p_point / zoom)) { + if (is_in_hot_zone(pos / zoom, p_point / zoom, port_size, false)) { return true; } } for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); - if (is_in_hot_zone(pos / zoom, p_point / zoom)) { + if (is_in_hot_zone(pos / zoom, p_point / zoom, port_size, true)) { return true; } } @@ -548,8 +549,10 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { void GraphEdit::_top_layer_input(const Ref &p_ev) { Ref mb = p_ev; if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { - connecting_valid = false; Ref port = get_icon("port", "GraphNode"); + Vector2i port_size = Vector2i(port->get_width(), port->get_height()); + + connecting_valid = false; click_pos = mb->get_position() / zoom; for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to(get_child(i)); @@ -559,7 +562,7 @@ void GraphEdit::_top_layer_input(const Ref &p_ev) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); - if (is_in_hot_zone(pos / zoom, click_pos)) { + if (is_in_hot_zone(pos / zoom, click_pos, port_size, false)) { if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) { //check disconnect for (List::Element *E = connections.front(); E; E = E->next()) { @@ -601,7 +604,7 @@ void GraphEdit::_top_layer_input(const Ref &p_ev) { for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); - if (is_in_hot_zone(pos / zoom, click_pos)) { + if (is_in_hot_zone(pos / zoom, click_pos, port_size, true)) { if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) { //check disconnect for (List::Element *E = connections.front(); E; E = E->next()) { @@ -650,10 +653,12 @@ void GraphEdit::_top_layer_input(const Ref &p_ev) { connecting_target = false; top_layer->update(); minimap->update(); - connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0 * zoom; + connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0; if (connecting_valid) { Ref port = get_icon("port", "GraphNode"); + Vector2i port_size = Vector2i(port->get_width(), port->get_height()); + Vector2 mpos = mm->get_position() / zoom; for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to(get_child(i)); @@ -665,7 +670,7 @@ void GraphEdit::_top_layer_input(const Ref &p_ev) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); int type = gn->get_connection_output_type(j); - if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos)) { + if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos, port_size, false)) { connecting_target = true; connecting_to = pos; connecting_target_to = gn->get_name(); @@ -677,7 +682,7 @@ void GraphEdit::_top_layer_input(const Ref &p_ev) { for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); int type = gn->get_connection_input_type(j); - if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos)) { + if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos, port_size, true)) { connecting_target = true; connecting_to = pos; connecting_target_to = gn->get_name(); @@ -748,9 +753,25 @@ bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &pos) } } -bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos) { - if (!Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2).has_point(p_mouse_pos)) { - return false; +bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left) { + if (p_left) { + if (!Rect2( + pos.x - p_port_size.x / 2 - port_grab_distance_horizontal, + pos.y - p_port_size.y / 2 - port_grab_distance_vertical / 2, + p_port_size.x + port_grab_distance_horizontal, + p_port_size.y + port_grab_distance_vertical) + .has_point(p_mouse_pos)) { + return false; + } + } else { + if (!Rect2( + pos.x - p_port_size.x / 2, + pos.y - p_port_size.y / 2 - port_grab_distance_vertical / 2, + p_port_size.x + port_grab_distance_horizontal, + p_port_size.y + port_grab_distance_vertical) + .has_point(p_mouse_pos)) { + return false; + } } for (int i = 0; i < get_child_count(); i++) { diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index a0f973749cf..46f53a98491 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -181,7 +181,7 @@ private: GraphEditMinimap *minimap; void _top_layer_input(const Ref &p_ev); - bool is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos); + bool is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left); void _top_layer_draw(); void _connections_layer_draw(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index be81b0e53d8..e84982e1a26 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -888,7 +888,8 @@ void fill_default_theme(Ref &theme, const Ref &default_font, const theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale); // Visual Node Ports - theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 48 * scale); + + theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 24 * scale); theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale); theme->set_stylebox("bg", "GraphEditMinimap", make_flat_stylebox(Color(0.24, 0.24, 0.24), 0, 0, 0, 0)); From 389e67aa987869c67af7f2bab88c11191d3661c3 Mon Sep 17 00:00:00 2001 From: PouleyKetchoupp Date: Wed, 16 Jun 2021 10:54:02 -0700 Subject: [PATCH 14/17] Fix loading packed scene with editable children at runtime At runtime, packed scenes with nodes marked as editable instance where saved with node type tags, which prevented the scene to be then loaded as an instance, causing duplicated nodes in the tree. This change ensures nodes marked as editable instances and their owned children are properly set as instances. That doesn't make a difference in the editor, since such nodes where already set as instances based on their instance state, but it helps at runtime where instance states are disabled. Co-authored-by: latorril (cherry picked from commit fab88a810ccd32ed5a573050171d12c73f69a668) --- scene/resources/packed_scene.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 070b5e61cca..dfc9c9fb37d 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -377,10 +377,17 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map return OK; } - // save the child instanced scenes that are chosen as editable, so they can be restored + bool is_editable_instance = false; + + // save the child instantiated scenes that are chosen as editable, so they can be restored // upon load back if (p_node != p_owner && p_node->get_filename() != String() && p_owner->is_editable_instance(p_node)) { editable_instances.push_back(p_owner->get_path_to(p_node)); + // Node is the root of an editable instance. + is_editable_instance = true; + } else if (p_node->get_owner() && p_node->get_owner() != p_owner && p_owner->is_editable_instance(p_node->get_owner())) { + // Node is part of an editable instance. + is_editable_instance = true; } NodeData nd; @@ -610,7 +617,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map // Save the right type. If this node was created by an instance // then flag that the node should not be created but reused - if (pack_state_stack.empty()) { + if (pack_state_stack.empty() && !is_editable_instance) { //this node is not part of an instancing process, so save the type nd.type = _nm_get_string(p_node->get_class(), name_map); } else { From e46d54ebec8b3999fab4962047d3203363b8d04a Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Sat, 28 Aug 2021 13:00:10 +0800 Subject: [PATCH 15/17] Quote and escape ConfigFile keys when necessary (cherry picked from commit 597d489a20d3755dae4b92ac7667e058d68b3d83) --- core/io/config_file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp index d3b53b996b3..b6da2dadc1d 100644 --- a/core/io/config_file.cpp +++ b/core/io/config_file.cpp @@ -184,7 +184,7 @@ Error ConfigFile::_internal_save(FileAccess *file) { for (OrderedHashMap::Element F = E.get().front(); F; F = F.next()) { String vstr; VariantWriter::write_to_string(F.get(), vstr); - file->store_string(F.key() + "=" + vstr + "\n"); + file->store_string(F.key().property_name_encode() + "=" + vstr + "\n"); } } From 018f28bead3d641f71de9534bbe27988cbeda38b Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Tue, 14 Sep 2021 17:46:39 +0800 Subject: [PATCH 16/17] Make sure IK target is inside tree before using its transform (cherry picked from commit 88e3ba83f0d80a88771afcb9ee5597bcfcf1a2d0) --- scene/animation/skeleton_ik.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp index 7bb08a68976..324c2d0f8c5 100644 --- a/scene/animation/skeleton_ik.cpp +++ b/scene/animation/skeleton_ik.cpp @@ -549,7 +549,7 @@ Transform SkeletonIK::_get_target_transform() { target_node_override = Object::cast_to(get_node(target_node_path_override)); } - if (target_node_override) { + if (target_node_override && target_node_override->is_inside_tree()) { return target_node_override->get_global_transform(); } else { return target; From 25bd0c3f72fd39daafb17e34764b08a715db763e Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Sun, 11 Jul 2021 17:43:52 +0800 Subject: [PATCH 17/17] Try other resolved IPs if one fails to connect (cherry picked from commit fd52e18d199f5055e1f743f762e4790f2a7d3261) --- core/io/http_client.cpp | 26 +++++++++++++++++++++++--- core/io/http_client.h | 1 + modules/websocket/wsl_client.cpp | 28 ++++++++++++++++++++++------ modules/websocket/wsl_client.h | 2 ++ 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 581362b51a0..e30b59a6fdb 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -52,6 +52,8 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, conn_port = p_port; conn_host = p_host; + ip_candidates.clear(); + ssl = p_ssl; ssl_verify_host = p_verify_host; @@ -306,6 +308,7 @@ void HTTPClient::close() { resolving = IP::RESOLVER_INVALID_ID; } + ip_candidates.clear(); response_headers.clear(); response_str.clear(); body_size = -1; @@ -328,10 +331,17 @@ Error HTTPClient::poll() { return OK; // Still resolving case IP::RESOLVER_STATUS_DONE: { - IP_Address host = IP::get_singleton()->get_resolve_item_address(resolving); - Error err = tcp_connection->connect_to_host(host, conn_port); + ip_candidates = IP::get_singleton()->get_resolve_item_addresses(resolving); IP::get_singleton()->erase_resolve_item(resolving); resolving = IP::RESOLVER_INVALID_ID; + + Error err = ERR_BUG; // Should be at least one entry. + while (ip_candidates.size() > 0) { + err = tcp_connection->connect_to_host(ip_candidates.front(), conn_port); + if (err == OK) { + break; + } + } if (err) { status = STATUS_CANT_CONNECT; return err; @@ -385,6 +395,7 @@ Error HTTPClient::poll() { if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) { // Handshake has been successful handshaking = false; + ip_candidates.clear(); status = STATUS_CONNECTED; return OK; } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) { @@ -395,15 +406,24 @@ Error HTTPClient::poll() { } // ... we will need to poll more for handshake to finish } else { + ip_candidates.clear(); status = STATUS_CONNECTED; } return OK; } break; case StreamPeerTCP::STATUS_ERROR: case StreamPeerTCP::STATUS_NONE: { + Error err = ERR_CANT_CONNECT; + while (ip_candidates.size() > 0) { + tcp_connection->disconnect_from_host(); + err = tcp_connection->connect_to_host(ip_candidates.pop_front(), conn_port); + if (err == OK) { + return OK; + } + } close(); status = STATUS_CANT_CONNECT; - return ERR_CANT_CONNECT; + return err; } break; } } break; diff --git a/core/io/http_client.h b/core/io/http_client.h index 9a14d72bd61..47ad576f5d7 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -159,6 +159,7 @@ private: #ifndef JAVASCRIPT_ENABLED Status status; IP::ResolverID resolving; + Array ip_candidates; int conn_port; String conn_host; bool ssl; diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp index 3125d5ab7f9..415f49c29cf 100644 --- a/modules/websocket/wsl_client.cpp +++ b/modules/websocket/wsl_client.cpp @@ -161,22 +161,28 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, ERR_FAIL_COND_V(p_path.empty(), ERR_INVALID_PARAMETER); _peer = Ref(memnew(WSLPeer)); - IP_Address addr; - if (!p_host.is_valid_ip_address()) { - addr = IP::get_singleton()->resolve_hostname(p_host); + if (p_host.is_valid_ip_address()) { + ip_candidates.clear(); + ip_candidates.push_back(IP_Address(p_host)); } else { - addr = p_host; + ip_candidates = IP::get_singleton()->resolve_hostname_addresses(p_host); } - ERR_FAIL_COND_V(!addr.is_valid(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(ip_candidates.empty(), ERR_INVALID_PARAMETER); String port = ""; if ((p_port != 80 && !p_ssl) || (p_port != 443 && p_ssl)) { port = ":" + itos(p_port); } - Error err = _tcp->connect_to_host(addr, p_port); + Error err = ERR_BUG; // Should be at least one entry. + while (ip_candidates.size() > 0) { + err = _tcp->connect_to_host(ip_candidates.pop_front(), p_port); + if (err == OK) { + break; + } + } if (err != OK) { _tcp->disconnect_from_host(); _on_error(); @@ -185,6 +191,7 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, _connection = _tcp; _use_ssl = p_ssl; _host = p_host; + _port = p_port; // Strip edges from protocols. _protocols.resize(p_protocols.size()); String *pw = _protocols.ptrw(); @@ -244,6 +251,7 @@ void WSLClient::poll() { _on_error(); break; case StreamPeerTCP::STATUS_CONNECTED: { + ip_candidates.clear(); Ref ssl; if (_use_ssl) { if (_connection == _tcp) { @@ -274,6 +282,12 @@ void WSLClient::poll() { _do_handshake(); } break; case StreamPeerTCP::STATUS_ERROR: + while (ip_candidates.size() > 0) { + _tcp->disconnect_from_host(); + if (_tcp->connect_to_host(ip_candidates.pop_front(), _port) == OK) { + return; + } + } disconnect_from_host(); _on_error(); break; @@ -315,6 +329,8 @@ void WSLClient::disconnect_from_host(int p_code, String p_reason) { memset(_resp_buf, 0, sizeof(_resp_buf)); _resp_pos = 0; + + ip_candidates.clear(); } IP_Address WSLClient::get_connected_host() const { diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h index d453c880a49..93fe290b756 100644 --- a/modules/websocket/wsl_client.h +++ b/modules/websocket/wsl_client.h @@ -63,6 +63,8 @@ private: String _key; String _host; + int _port; + Array ip_candidates; Vector _protocols; bool _use_ssl;