From 97a787aa71add99af08a70a052faaacd3175c9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= Date: Tue, 21 Apr 2020 21:12:05 +0200 Subject: [PATCH 01/12] Fix compilation of jpgd.cpp on MSVC 2017 (cherry picked from commit 1e5a93a4166858bba708b12cd62961c6bf3512a4) --- thirdparty/README.md | 2 ++ thirdparty/jpeg-compressor/jpgd.cpp | 6 ++-- .../patches/fix-msvc2017-build.patch | 31 +++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 thirdparty/jpeg-compressor/patches/fix-msvc2017-build.patch diff --git a/thirdparty/README.md b/thirdparty/README.md index 6526f4d4eb5e..af11e59dc137 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -151,6 +151,8 @@ Files extracted from upstream source: - `jpgd*.{c,h}` +Patches in the `patches` directory should be re-applied after updates. + ## libogg diff --git a/thirdparty/jpeg-compressor/jpgd.cpp b/thirdparty/jpeg-compressor/jpgd.cpp index a0c494db6105..257d0b757473 100644 --- a/thirdparty/jpeg-compressor/jpgd.cpp +++ b/thirdparty/jpeg-compressor/jpgd.cpp @@ -2126,7 +2126,7 @@ namespace jpgd { int jpeg_decoder::decode_next_mcu_row() { - if (setjmp(m_jmp_state)) + if (::setjmp(m_jmp_state)) return JPGD_FAILED; const bool chroma_y_filtering = ((m_flags & cFlagBoxChromaFiltering) == 0) && ((m_scan_type == JPGD_YH2V2) || (m_scan_type == JPGD_YH1V2)); @@ -3042,7 +3042,7 @@ namespace jpgd { jpeg_decoder::jpeg_decoder(jpeg_decoder_stream* pStream, uint32_t flags) { - if (setjmp(m_jmp_state)) + if (::setjmp(m_jmp_state)) return; decode_init(pStream, flags); } @@ -3055,7 +3055,7 @@ namespace jpgd { if (m_error_code) return JPGD_FAILED; - if (setjmp(m_jmp_state)) + if (::setjmp(m_jmp_state)) return JPGD_FAILED; decode_start(); diff --git a/thirdparty/jpeg-compressor/patches/fix-msvc2017-build.patch b/thirdparty/jpeg-compressor/patches/fix-msvc2017-build.patch new file mode 100644 index 000000000000..7b338de08469 --- /dev/null +++ b/thirdparty/jpeg-compressor/patches/fix-msvc2017-build.patch @@ -0,0 +1,31 @@ +diff --git a/thirdparty/jpeg-compressor/jpgd.cpp b/thirdparty/jpeg-compressor/jpgd.cpp +index a0c494db61..257d0b7574 100644 +--- a/thirdparty/jpeg-compressor/jpgd.cpp ++++ b/thirdparty/jpeg-compressor/jpgd.cpp +@@ -2126,7 +2126,7 @@ namespace jpgd { + + int jpeg_decoder::decode_next_mcu_row() + { +- if (setjmp(m_jmp_state)) ++ if (::setjmp(m_jmp_state)) + return JPGD_FAILED; + + const bool chroma_y_filtering = ((m_flags & cFlagBoxChromaFiltering) == 0) && ((m_scan_type == JPGD_YH2V2) || (m_scan_type == JPGD_YH1V2)); +@@ -3042,7 +3042,7 @@ namespace jpgd { + + jpeg_decoder::jpeg_decoder(jpeg_decoder_stream* pStream, uint32_t flags) + { +- if (setjmp(m_jmp_state)) ++ if (::setjmp(m_jmp_state)) + return; + decode_init(pStream, flags); + } +@@ -3055,7 +3055,7 @@ namespace jpgd { + if (m_error_code) + return JPGD_FAILED; + +- if (setjmp(m_jmp_state)) ++ if (::setjmp(m_jmp_state)) + return JPGD_FAILED; + + decode_start(); From add8d1b9dff0d62dd54e6a1e629c687c5eb19517 Mon Sep 17 00:00:00 2001 From: jfons Date: Fri, 20 Mar 2020 12:41:07 +0100 Subject: [PATCH 02/12] Update Joint gizmos automatically (cherry picked from commit 3e77b6d49d47e837dbdf50664d2d71e451b7b615) --- editor/plugins/spatial_editor_plugin.h | 3 +-- editor/spatial_editor_gizmos.cpp | 19 +++++++++++++++++++ editor/spatial_editor_gizmos.h | 8 ++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index b84dc85f3fcc..a4089327a5c8 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -828,12 +828,11 @@ class EditorSpatialGizmoPlugin : public Resource { static const int HIDDEN = 1; static const int ON_TOP = 2; -private: +protected: int current_state; List current_gizmos; HashMap > > materials; -protected: static void _bind_methods(); virtual bool has_gizmo(Spatial *p_spatial); virtual Ref create_gizmo(Spatial *p_spatial); diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index c94b0eeab0f4..838aa4d2f7ba 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -4075,6 +4075,25 @@ JointSpatialGizmoPlugin::JointSpatialGizmoPlugin() { create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1))); create_material("joint_body_a_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1))); create_material("joint_body_b_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1))); + + update_timer = memnew(Timer); + update_timer->set_name("JointGizmoUpdateTimer"); + update_timer->set_wait_time(1.0 / 120.0); + update_timer->connect("timeout", this, "incremental_update_gizmos"); + update_timer->set_autostart(true); + EditorNode::get_singleton()->call_deferred("add_child", update_timer); +} + +void JointSpatialGizmoPlugin::_bind_methods() { + ClassDB::bind_method(D_METHOD("incremental_update_gizmos"), &JointSpatialGizmoPlugin::incremental_update_gizmos); +} + +void JointSpatialGizmoPlugin::incremental_update_gizmos() { + if (!current_gizmos.empty()) { + update_idx++; + update_idx = update_idx % current_gizmos.size(); + redraw(current_gizmos[update_idx]); + } } bool JointSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index 81b62981accc..c0084c13d599 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -390,6 +390,14 @@ class JointSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { GDCLASS(JointSpatialGizmoPlugin, EditorSpatialGizmoPlugin); + Timer *update_timer; + uint64_t update_idx = 0; + + void incremental_update_gizmos(); + +protected: + static void _bind_methods(); + public: bool has_gizmo(Spatial *p_spatial); String get_name() const; From 17ad99c2065875edc2289001b982d8ffbf0f952c Mon Sep 17 00:00:00 2001 From: Fredia Huya-Kouadio Date: Thu, 23 Apr 2020 00:21:39 -0700 Subject: [PATCH 03/12] Fix Android templates size regression The issue was caused by PR #36906 which changes prevented the generated shared libraries from being stripped. Since the change is only needed for development (debugging) purposes, it's commented out by default. (cherry picked from commit 2f38cfd9ab4dc0105097f8b109391af4510a2c60) --- platform/android/java/app/build.gradle | 4 +++- platform/android/java/lib/build.gradle | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index d57cb95de1f1..751ee45421e5 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -90,7 +90,9 @@ android { packagingOptions { exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' - doNotStrip '**/*.so' + + // Should be uncommented for development purpose within Android Studio + // doNotStrip '**/*.so' } // Both signing and zip-aligning will be done at export time diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle index 6bb438c249a0..19eee5a315b0 100644 --- a/platform/android/java/lib/build.gradle +++ b/platform/android/java/lib/build.gradle @@ -26,7 +26,9 @@ android { packagingOptions { exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' - doNotStrip '**/*.so' + + // Should be uncommented for development purpose within Android Studio + // doNotStrip '**/*.so' } sourceSets { From 243711e77f78e1e2538023c87e4e0a2c9866462b Mon Sep 17 00:00:00 2001 From: Stoofin <44447892+stoofin@users.noreply.github.com> Date: Thu, 9 Apr 2020 02:43:47 -0700 Subject: [PATCH 04/12] Pattern bind counts as assignment Fixes #34697 (cherry picked from commit 44281f233dd0f3cff13a0c14320de943ee4719ea) --- modules/gdscript/gdscript_parser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 71347d125b69..1622431f56c2 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -2683,6 +2683,7 @@ void GDScriptParser::_transform_match_statment(MatchNode *p_match_statement) { LocalVarNode *local_var = branch->body->variables[e->key()]; local_var->assign = e->value(); local_var->set_datatype(local_var->assign->get_datatype()); + local_var->assignments++; IdentifierNode *id2 = alloc_node(); id2->name = local_var->name; From 12c776dba30f79c0fa84e136e1015c115812cccd Mon Sep 17 00:00:00 2001 From: Thakee Nathees Date: Fri, 17 Apr 2020 12:13:57 +0530 Subject: [PATCH 05/12] line unsafe for indexing with known base type & unkown identifier (cherry picked from commit 0780ad2800aeeb26c02871d0a6242f68097c69b2) --- modules/gdscript/gdscript_parser.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 1622431f56c2..3565ce148a78 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -6569,6 +6569,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { node_type = _reduce_identifier_type(&base_type, member_id->name, op->line, true); #ifdef DEBUG_ENABLED if (!node_type.has_type) { + _mark_line_as_unsafe(op->line); _add_warning(GDScriptWarning::UNSAFE_PROPERTY_ACCESS, op->line, member_id->name.operator String(), base_type.to_string()); } #endif // DEBUG_ENABLED From 95f6bdfa783234d62404030e00650341ec689f29 Mon Sep 17 00:00:00 2001 From: Thakee Nathees Date: Mon, 20 Apr 2020 16:20:36 +0530 Subject: [PATCH 06/12] GDScript class name existance check enhanced (cherry picked from commit 62280c3d47bf4cda3775013b1676a2b651e18756) --- modules/gdscript/gdscript_parser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 3565ce148a78..e9c9c66d87a3 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -3674,6 +3674,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { _set_error("A constant named \"" + String(name) + "\" already exists in the outer class scope (at line" + itos(outer_class->constant_expressions[name].expression->line) + ")."); return; } + for (int i = 0; i < outer_class->variables.size(); i++) { + if (outer_class->variables[i].identifier == name) { + _set_error("A variable named \"" + String(name) + "\" already exists in the outer class scope (at line " + itos(outer_class->variables[i].line) + ")."); + return; + } + } outer_class = outer_class->owner; } From f670f6e351110c2588fcfbaf318c1ec10a957f56 Mon Sep 17 00:00:00 2001 From: volzhs Date: Wed, 22 Apr 2020 00:45:44 +0900 Subject: [PATCH 07/12] Emit signal when animation ends by seek (cherry picked from commit bf1cc116e15ec155c1dfff06bd02d2f1dfc21ee0) --- scene/animation/animation_player.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 2bc9336b1417..978089bbf524 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -950,13 +950,13 @@ void AnimationPlayer::_animation_process(float p_delta) { play(queued.front()->get()); String new_name = playback.assigned; queued.pop_front(); - if (end_notify) + if (end_notify || playback.seeked) emit_signal(SceneStringNames::get_singleton()->animation_changed, old, new_name); } else { //stop(); playing = false; _set_process(false); - if (end_notify) + if (end_notify || playback.seeked) emit_signal(SceneStringNames::get_singleton()->animation_finished, playback.assigned); } end_reached = false; From a5bbd13794b6b0f791857e3b76e7b5a100c7d179 Mon Sep 17 00:00:00 2001 From: dankan1890 Date: Wed, 22 Apr 2020 04:26:44 +0200 Subject: [PATCH 08/12] Fixed output prints " Signal 'node_removed' is already connected " when the editor settings window is closed. Close #38012 (cherry picked from commit ef08e64afb77834120596484309cfd0f4618d7c9) --- editor/plugins/tile_map_editor_plugin.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 3a1fc6c7d0cd..8736b88b71e7 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -57,17 +57,18 @@ void TileMapEditor::_notification(int p_what) { } break; + case NOTIFICATION_ENTER_TREE: { + + get_tree()->connect("node_removed", this, "_node_removed"); + FALLTHROUGH; + } + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { if (is_visible_in_tree()) { _update_palette(); } - FALLTHROUGH; - } - case NOTIFICATION_ENTER_TREE: { - - get_tree()->connect("node_removed", this, "_node_removed"); paint_button->set_icon(get_icon("Edit", "EditorIcons")); bucket_fill_button->set_icon(get_icon("Bucket", "EditorIcons")); picker_button->set_icon(get_icon("ColorPick", "EditorIcons")); From 08f41f474b35c717b3b9d2c1ad300fe3d1d0db65 Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Wed, 22 Apr 2020 14:39:42 +0200 Subject: [PATCH 09/12] C#: Save copy of sln and csproj before applying fixes (cherry picked from commit 93d7ec88360a467a3041c0aa08390daa1f75892b) --- .../GodotTools/GodotTools.Core/FileUtils.cs | 27 ++++++++ .../GodotTools.Core/GodotTools.Core.csproj | 1 + .../DotNetSolution.cs | 5 ++ .../GodotTools.ProjectEditor/ProjectUtils.cs | 65 +++++++------------ .../GodotTools/GodotTools/GodotSharpEditor.cs | 21 +++++- 5 files changed, 76 insertions(+), 43 deletions(-) create mode 100644 modules/mono/editor/GodotTools/GodotTools.Core/FileUtils.cs diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/FileUtils.cs b/modules/mono/editor/GodotTools/GodotTools.Core/FileUtils.cs new file mode 100644 index 000000000000..85760a3705e3 --- /dev/null +++ b/modules/mono/editor/GodotTools/GodotTools.Core/FileUtils.cs @@ -0,0 +1,27 @@ +using System.IO; + +namespace GodotTools.Core +{ + public static class FileUtils + { + public static void SaveBackupCopy(string filePath) + { + string backupPathBase = filePath + ".old"; + string backupPath = backupPathBase; + + const int maxAttempts = 5; + int attempt = 1; + + while (File.Exists(backupPath) && attempt <= maxAttempts) + { + backupPath = backupPathBase + "." + (attempt); + attempt++; + } + + if (attempt > maxAttempts + 1) + return; + + File.Copy(filePath, backupPath, overwrite: true); + } + } +} diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj index 2c35ef540aee..c9ea7d3a2cd5 100644 --- a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj @@ -31,6 +31,7 @@ + diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs index 9afd9adeb13a..6f318aab4a2d 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/DotNetSolution.cs @@ -153,7 +153,12 @@ public static void MigrateFromOldConfigNames(string slnPath) var result = regex.Replace(input,m => dict[m.Value]); if (result != input) + { + // Save a copy of the solution before replacing it + FileUtils.SaveBackupCopy(slnPath); + File.WriteAllText(slnPath, result); + } } } } diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs index 1776b46e6a86..a875e1c14f83 100644 --- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs +++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs @@ -9,8 +9,28 @@ namespace GodotTools.ProjectEditor { + public sealed class MSBuildProject + { + public ProjectRootElement Root { get; } + + public bool HasUnsavedChanges => Root.HasUnsavedChanges; + + public void Save() => Root.Save(); + + public MSBuildProject(ProjectRootElement root) + { + Root = root; + } + } + public static class ProjectUtils { + public static MSBuildProject Open(string path) + { + var root = ProjectRootElement.Open(path); + return root != null ? new MSBuildProject(root) : null; + } + public static void AddItemToProjectChecked(string projectPath, string itemType, string include) { var dir = Directory.GetParent(projectPath).FullName; @@ -43,7 +63,6 @@ public static void RenameItemInProjectChecked(string projectPath, string itemTyp public static void RemoveItemFromProjectChecked(string projectPath, string itemType, string include) { - var dir = Directory.GetParent(projectPath).FullName; var root = ProjectRootElement.Open(projectPath); Debug.Assert(root != null); @@ -59,8 +78,6 @@ public static void RenameItemsToNewFolderInProjectChecked(string projectPath, st var root = ProjectRootElement.Open(projectPath); Debug.Assert(root != null); - bool dirty = false; - var oldFolderNormalized = oldFolder.NormalizePath(); var newFolderNormalized = newFolder.NormalizePath(); string absOldFolderNormalized = Path.GetFullPath(oldFolderNormalized).NormalizePath(); @@ -71,10 +88,9 @@ public static void RenameItemsToNewFolderInProjectChecked(string projectPath, st string absPathNormalized = Path.GetFullPath(item.Include).NormalizePath(); string absNewIncludeNormalized = absNewFolderNormalized + absPathNormalized.Substring(absOldFolderNormalized.Length); item.Include = absNewIncludeNormalized.RelativeToPath(dir).Replace("/", "\\"); - dirty = true; } - if (dirty) + if (root.HasUnsavedChanges) root.Save(); } @@ -150,12 +166,9 @@ public static string[] GetIncludeFiles(string projectPath, string itemType) } /// Simple function to make sure the Api assembly references are configured correctly - public static void FixApiHintPath(string projectPath) + public static void FixApiHintPath(MSBuildProject project) { - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - bool dirty = false; + var root = project.Root; void AddPropertyIfNotPresent(string name, string condition, string value) { @@ -170,7 +183,6 @@ void AddPropertyIfNotPresent(string name, string condition, string value) } root.AddProperty(name, value).Condition = " " + condition + " "; - dirty = true; } AddPropertyIfNotPresent(name: "ApiConfiguration", @@ -212,7 +224,6 @@ void SetReferenceHintPath(string referenceName, string condition, string hintPat } referenceWithHintPath.AddMetadata("HintPath", hintPath); - dirty = true; return; } @@ -221,14 +232,12 @@ void SetReferenceHintPath(string referenceName, string condition, string hintPat { // Found a Reference item without a HintPath referenceWithoutHintPath.AddMetadata("HintPath", hintPath); - dirty = true; return; } } // Found no Reference item at all. Add it. root.AddItem("Reference", referenceName).Condition = " " + condition + " "; - dirty = true; } const string coreProjectName = "GodotSharp"; @@ -242,17 +251,11 @@ void SetReferenceHintPath(string referenceName, string condition, string hintPat SetReferenceHintPath(coreProjectName, coreCondition, coreHintPath); SetReferenceHintPath(editorProjectName, editorCondition, editorHintPath); - - if (dirty) - root.Save(); } - public static void MigrateFromOldConfigNames(string projectPath) + public static void MigrateFromOldConfigNames(MSBuildProject project) { - var root = ProjectRootElement.Open(projectPath); - Debug.Assert(root != null); - - bool dirty = false; + var root = project.Root; bool hasGodotProjectGeneratorVersion = false; bool foundOldConfiguration = false; @@ -267,7 +270,6 @@ public static void MigrateFromOldConfigNames(string projectPath) { configItem.Value = "Debug"; foundOldConfiguration = true; - dirty = true; } } @@ -275,7 +277,6 @@ public static void MigrateFromOldConfigNames(string projectPath) { root.PropertyGroups.First(g => g.Condition == string.Empty)? .AddProperty("GodotProjectGeneratorVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString()); - dirty = true; } if (!foundOldConfiguration) @@ -299,33 +300,21 @@ void MigrateConfigurationConditions(string oldConfiguration, string newConfigura void MigrateConditions(string oldCondition, string newCondition) { foreach (var propertyGroup in root.PropertyGroups.Where(g => g.Condition.Trim() == oldCondition)) - { propertyGroup.Condition = " " + newCondition + " "; - dirty = true; - } foreach (var propertyGroup in root.PropertyGroups) { foreach (var prop in propertyGroup.Properties.Where(p => p.Condition.Trim() == oldCondition)) - { prop.Condition = " " + newCondition + " "; - dirty = true; - } } foreach (var itemGroup in root.ItemGroups.Where(g => g.Condition.Trim() == oldCondition)) - { itemGroup.Condition = " " + newCondition + " "; - dirty = true; - } foreach (var itemGroup in root.ItemGroups) { foreach (var item in itemGroup.Items.Where(item => item.Condition.Trim() == oldCondition)) - { item.Condition = " " + newCondition + " "; - dirty = true; - } } } @@ -340,10 +329,6 @@ void MigrateConditions(string oldCondition, string newCondition) MigrateConfigurationConditions("Release", "ExportRelease"); MigrateConfigurationConditions("Tools", "Debug"); // Must be last } - - - if (dirty) - root.Save(); } } } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index b33dad1ca2ec..6aca7250a749 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -1,4 +1,5 @@ using Godot; +using GodotTools.Core; using GodotTools.Export; using GodotTools.Utils; using System; @@ -450,13 +451,27 @@ public override void EnablePlugin() { // Migrate solution from old configuration names to: Debug, ExportDebug and ExportRelease DotNetSolution.MigrateFromOldConfigNames(GodotSharpDirs.ProjectSlnPath); + + var msbuildProject = ProjectUtils.Open(GodotSharpDirs.ProjectCsProjPath) + ?? throw new Exception("Cannot open C# project"); + + // NOTE: The order in which changes are made to the project is important + // Migrate csproj from old configuration names to: Debug, ExportDebug and ExportRelease - ProjectUtils.MigrateFromOldConfigNames(GodotSharpDirs.ProjectCsProjPath); + ProjectUtils.MigrateFromOldConfigNames(msbuildProject); - // Apply the other fixes after configurations are migrated + // Apply the other fixes only after configurations have been migrated // Make sure the existing project has Api assembly references configured correctly - ProjectUtils.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath); + ProjectUtils.FixApiHintPath(msbuildProject); + + if (msbuildProject.HasUnsavedChanges) + { + // Save a copy of the project before replacing it + FileUtils.SaveBackupCopy(GodotSharpDirs.ProjectCsProjPath); + + msbuildProject.Save(); + } } catch (Exception e) { From 317d8decad2523f010ad0ab9d4a4d9dd9f9d4452 Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Wed, 22 Apr 2020 16:44:03 +0200 Subject: [PATCH 10/12] Mono/C#: Allow debugging exported games - Include PDB files in exported games. - Release export templates also allow debugging now. Right now the only way to enable debugging in exported games is with the environment variables, which may be cumbersome or not even possible on some platforms. (cherry picked from commit 71fc87e1013029cc379adb6d430a9adf5d25b6cf) --- .../GodotTools/Export/ExportPlugin.cs | 54 +++++++++++-------- modules/mono/editor/editor_internal_calls.cpp | 10 ++-- modules/mono/editor/godotsharp_export.cpp | 18 +++---- modules/mono/editor/godotsharp_export.h | 4 +- modules/mono/mono_gd/gd_mono.cpp | 12 ++--- 5 files changed, 54 insertions(+), 44 deletions(-) diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs index d782d4e61b24..2ceb4888a232 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs @@ -168,13 +168,13 @@ private void _ExportBeginImpl(string[] features, bool isDebug, string path, int // Add dependency assemblies - var dependencies = new Godot.Collections.Dictionary(); + var assemblies = new Godot.Collections.Dictionary(); string projectDllName = GodotSharpEditor.ProjectAssemblyName; string projectDllSrcDir = Path.Combine(GodotSharpDirs.ResTempAssembliesBaseDir, buildConfig); string projectDllSrcPath = Path.Combine(projectDllSrcDir, $"{projectDllName}.dll"); - dependencies[projectDllName] = projectDllSrcPath; + assemblies[projectDllName] = projectDllSrcPath; if (platform == OS.Platforms.Android) { @@ -184,15 +184,15 @@ private void _ExportBeginImpl(string[] features, bool isDebug, string path, int if (!File.Exists(monoAndroidAssemblyPath)) throw new FileNotFoundException("Assembly not found: 'Mono.Android'", monoAndroidAssemblyPath); - dependencies["Mono.Android"] = monoAndroidAssemblyPath; + assemblies["Mono.Android"] = monoAndroidAssemblyPath; } string bclDir = DeterminePlatformBclDir(platform); - var initialDependencies = dependencies.Duplicate(); - internal_GetExportedAssemblyDependencies(initialDependencies, buildConfig, bclDir, dependencies); + var initialAssemblies = assemblies.Duplicate(); + internal_GetExportedAssemblyDependencies(initialAssemblies, buildConfig, bclDir, assemblies); - AddI18NAssemblies(dependencies, bclDir); + AddI18NAssemblies(assemblies, bclDir); string outputDataDir = null; @@ -211,20 +211,32 @@ private void _ExportBeginImpl(string[] features, bool isDebug, string path, int Directory.CreateDirectory(outputDataGameAssembliesDir); } - foreach (var dependency in dependencies) + foreach (var assembly in assemblies) { - string dependSrcPath = dependency.Value; - - if (assembliesInsidePck) - { - string dependDstPath = Path.Combine(resAssembliesDir, dependSrcPath.GetFile()); - AddFile(dependSrcPath, dependDstPath); - } - else + void AddToAssembliesDir(string fileSrcPath) { - string dependDstPath = Path.Combine(outputDataDir, "Assemblies", dependSrcPath.GetFile()); - File.Copy(dependSrcPath, dependDstPath); + if (assembliesInsidePck) + { + string fileDstPath = Path.Combine(resAssembliesDir, fileSrcPath.GetFile()); + AddFile(fileSrcPath, fileDstPath); + } + else + { + Debug.Assert(outputDataDir != null); + string fileDstPath = Path.Combine(outputDataDir, "Assemblies", fileSrcPath.GetFile()); + File.Copy(fileSrcPath, fileDstPath); + } } + + string assemblySrcPath = assembly.Value; + + string assemblyPathWithoutExtension = Path.ChangeExtension(assemblySrcPath, null); + string pdbSrcPath = assemblyPathWithoutExtension + ".pdb"; + + AddToAssembliesDir(assemblySrcPath); + + if (File.Exists(pdbSrcPath)) + AddToAssembliesDir(pdbSrcPath); } // AOT compilation @@ -254,7 +266,7 @@ private void _ExportBeginImpl(string[] features, bool isDebug, string path, int ToolchainPath = aotToolchainPath }; - AotBuilder.CompileAssemblies(this, aotOpts, features, platform, isDebug, bclDir, outputDir, outputDataDir, dependencies); + AotBuilder.CompileAssemblies(this, aotOpts, features, platform, isDebug, bclDir, outputDir, outputDataDir, assemblies); } } @@ -366,7 +378,7 @@ private static string DeterminePlatformBclDir(string platform) if (PlatformRequiresCustomBcl(platform)) throw new FileNotFoundException($"Missing BCL (Base Class Library) for platform: {platform}"); - platformBclDir = typeof(object).Assembly.Location; // Use the one we're running on + platformBclDir = typeof(object).Assembly.Location.GetBaseDir(); // Use the one we're running on } } @@ -425,7 +437,7 @@ private static string DetermineDataDirNameForProject() } [MethodImpl(MethodImplOptions.InternalCall)] - private static extern void internal_GetExportedAssemblyDependencies(Godot.Collections.Dictionary initialDependencies, - string buildConfig, string customBclDir, Godot.Collections.Dictionary dependencies); + private static extern void internal_GetExportedAssemblyDependencies(Godot.Collections.Dictionary initialAssemblies, + string buildConfig, string customBclDir, Godot.Collections.Dictionary dependencyAssemblies); } } diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp index c8d20e80be79..cf78246f0d5c 100644 --- a/modules/mono/editor/editor_internal_calls.cpp +++ b/modules/mono/editor/editor_internal_calls.cpp @@ -231,14 +231,14 @@ int32_t godot_icall_ScriptClassParser_ParseFile(MonoString *p_filepath, MonoObje return err; } -uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(MonoObject *p_initial_dependencies, - MonoString *p_build_config, MonoString *p_custom_bcl_dir, MonoObject *r_dependencies) { - Dictionary initial_dependencies = GDMonoMarshal::mono_object_to_variant(p_initial_dependencies); +uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(MonoObject *p_initial_assemblies, + MonoString *p_build_config, MonoString *p_custom_bcl_dir, MonoObject *r_assembly_dependencies) { + Dictionary initial_dependencies = GDMonoMarshal::mono_object_to_variant(p_initial_assemblies); String build_config = GDMonoMarshal::mono_string_to_godot(p_build_config); String custom_bcl_dir = GDMonoMarshal::mono_string_to_godot(p_custom_bcl_dir); - Dictionary dependencies = GDMonoMarshal::mono_object_to_variant(r_dependencies); + Dictionary assembly_dependencies = GDMonoMarshal::mono_object_to_variant(r_assembly_dependencies); - return GodotSharpExport::get_exported_assembly_dependencies(initial_dependencies, build_config, custom_bcl_dir, dependencies); + return GodotSharpExport::get_exported_assembly_dependencies(initial_dependencies, build_config, custom_bcl_dir, assembly_dependencies); } MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_config) { diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp index 19b3bea5cf8e..542835fb19e8 100644 --- a/modules/mono/editor/godotsharp_export.cpp +++ b/modules/mono/editor/godotsharp_export.cpp @@ -50,13 +50,13 @@ String get_assemblyref_name(MonoImage *p_image, int index) { return String::utf8(mono_metadata_string_heap(p_image, cols[MONO_ASSEMBLYREF_NAME])); } -Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector &p_search_dirs, Dictionary &r_dependencies) { +Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector &p_search_dirs, Dictionary &r_assembly_dependencies) { MonoImage *image = p_assembly->get_image(); for (int i = 0; i < mono_image_get_table_rows(image, MONO_TABLE_ASSEMBLYREF); i++) { String ref_name = get_assemblyref_name(image, i); - if (r_dependencies.has(ref_name)) + if (r_assembly_dependencies.has(ref_name)) continue; GDMonoAssembly *ref_assembly = NULL; @@ -93,17 +93,17 @@ Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector ERR_FAIL_COND_V_MSG(!ref_assembly, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'."); // Use the path we got from the search. Don't try to get the path from the loaded assembly as we can't trust it will be from the selected BCL dir. - r_dependencies[ref_name] = path; + r_assembly_dependencies[ref_name] = path; - Error err = get_assembly_dependencies(ref_assembly, p_search_dirs, r_dependencies); + Error err = get_assembly_dependencies(ref_assembly, p_search_dirs, r_assembly_dependencies); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load one of the dependencies for the assembly: '" + ref_name + "'."); } return OK; } -Error get_exported_assembly_dependencies(const Dictionary &p_initial_dependencies, - const String &p_build_config, const String &p_custom_bcl_dir, Dictionary &r_dependencies) { +Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies, + const String &p_build_config, const String &p_custom_bcl_dir, Dictionary &r_assembly_dependencies) { MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.Domain.ProjectExport"); ERR_FAIL_NULL_V(export_domain, FAILED); _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain); @@ -113,16 +113,16 @@ Error get_exported_assembly_dependencies(const Dictionary &p_initial_dependencie Vector search_dirs; GDMonoAssembly::fill_search_dirs(search_dirs, p_build_config, p_custom_bcl_dir); - for (const Variant *key = p_initial_dependencies.next(); key; key = p_initial_dependencies.next(key)) { + for (const Variant *key = p_initial_assemblies.next(); key; key = p_initial_assemblies.next(key)) { String assembly_name = *key; - String assembly_path = p_initial_dependencies[*key]; + String assembly_path = p_initial_assemblies[*key]; GDMonoAssembly *assembly = NULL; bool load_success = GDMono::get_singleton()->load_assembly_from(assembly_name, assembly_path, &assembly, /* refonly: */ true); ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + assembly_name + "'."); - Error err = get_assembly_dependencies(assembly, search_dirs, r_dependencies); + Error err = get_assembly_dependencies(assembly, search_dirs, r_assembly_dependencies); if (err != OK) return err; } diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h index 36138f81b78f..9ab57755de28 100644 --- a/modules/mono/editor/godotsharp_export.h +++ b/modules/mono/editor/godotsharp_export.h @@ -41,8 +41,8 @@ namespace GodotSharpExport { Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector &p_search_dirs, Dictionary &r_dependencies); -Error get_exported_assembly_dependencies(const Dictionary &p_initial_dependencies, - const String &p_build_config, const String &p_custom_lib_dir, Dictionary &r_dependencies); +Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies, + const String &p_build_config, const String &p_custom_lib_dir, Dictionary &r_assembly_dependencies); } // namespace GodotSharpExport diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index d00ecc3a4170..d6d3353a8b5d 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -128,12 +128,8 @@ void gd_mono_profiler_init() { } } -#if defined(DEBUG_ENABLED) - void gd_mono_debug_init() { - mono_debug_init(MONO_DEBUG_FORMAT_MONO); - CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8(); #ifdef TOOLS_ENABLED @@ -158,6 +154,10 @@ void gd_mono_debug_init() { return; // Exported games don't use the project settings to setup the debugger agent #endif + // Debugging enabled + + mono_debug_init(MONO_DEBUG_FORMAT_MONO); + // --debugger-agent=help const char *options[] = { "--soft-breakpoints", @@ -166,7 +166,6 @@ void gd_mono_debug_init() { mono_jit_parse_options(2, (char **)options); } -#endif // defined(DEBUG_ENABLED) #endif // !defined(JAVASCRIPT_ENABLED) #if defined(JAVASCRIPT_ENABLED) @@ -174,6 +173,7 @@ MonoDomain *gd_initialize_mono_runtime() { const char *vfs_prefix = "managed"; int enable_debugging = 0; + // TODO: Provide a way to enable debugging on WASM release builds. #ifdef DEBUG_ENABLED enable_debugging = 1; #endif @@ -184,9 +184,7 @@ MonoDomain *gd_initialize_mono_runtime() { } #else MonoDomain *gd_initialize_mono_runtime() { -#ifdef DEBUG_ENABLED gd_mono_debug_init(); -#endif #if defined(IPHONE_ENABLED) || defined(ANDROID_ENABLED) // I don't know whether this actually matters or not From cf729f21115a5fb530b9891a63982dcfc7aa0423 Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Wed, 22 Apr 2020 17:19:45 +0200 Subject: [PATCH 11/12] Mono/C#: Allow exporting System.Array of type Godot.Object (cherry picked from commit 0fec3cb5ed2a009454555440b3853bc4309bc434) --- modules/mono/mono_gd/gd_mono_field.cpp | 7 ++++++ modules/mono/mono_gd/gd_mono_marshal.cpp | 31 ++++++++++++++++++++++++ modules/mono/mono_gd/gd_mono_marshal.h | 1 + 3 files changed, 39 insertions(+) diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 3e0f9a3f15bd..08f8342c8c52 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -281,6 +281,13 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ break; } + GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); + if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) { + MonoArray *managed = GDMonoMarshal::Array_to_mono_array(p_value.operator ::Array(), array_type_class); + mono_field_set_value(p_object, mono_field, managed); + break; + } + ERR_FAIL_MSG("Attempted to convert Variant to a managed array of unmarshallable element type."); } break; diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index b81c20348da8..f410eae33835 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -132,6 +132,10 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { if (array_type->eklass == CACHED_CLASS_RAW(Color)) return Variant::POOL_COLOR_ARRAY; + + GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); + if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) + return Variant::ARRAY; } break; case MONO_TYPE_CLASS: { @@ -217,6 +221,13 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type) { bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type) { switch (p_array_type.type_encoding) { + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: { + MonoArrayType *array_type = mono_type_get_array_type(p_array_type.type_class->get_mono_type()); + GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); + r_elem_type = ManagedType::from_class(array_type_class); + return true; + } break; case MONO_TYPE_GENERICINST: { MonoReflectionType *array_reftype = mono_type_get_object(mono_domain_get(), p_array_type.type_class->get_mono_type()); @@ -511,6 +522,10 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty if (array_type->eklass == CACHED_CLASS_RAW(Color)) return (MonoObject *)PoolColorArray_to_mono_array(p_var->operator PoolColorArray()); + GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); + if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) + return (MonoObject *)Array_to_mono_array(p_var->operator Array(), array_type_class); + ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to a managed array of unmarshallable element type."); } break; @@ -805,6 +820,10 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type if (array_type->eklass == CACHED_CLASS_RAW(Color)) return mono_array_to_PoolColorArray((MonoArray *)p_obj); + GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass); + if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) + return mono_array_to_Array((MonoArray *)p_obj); + if (p_fail_with_err) { ERR_FAIL_V_MSG(Variant(), "Attempted to convert a managed array of unmarshallable element type to Variant."); } else { @@ -970,6 +989,18 @@ MonoArray *Array_to_mono_array(const Array &p_array) { return ret; } +MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class) { + int length = p_array.size(); + MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class->get_mono_ptr(), length); + + for (int i = 0; i < length; i++) { + MonoObject *boxed = variant_to_mono_object(p_array[i]); + mono_array_setref(ret, i, boxed); + } + + return ret; +} + Array mono_array_to_Array(MonoArray *p_array) { Array ret; if (!p_array) diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index e662e7814ef3..2499c779205a 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -125,6 +125,7 @@ String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc); // Array MonoArray *Array_to_mono_array(const Array &p_array); +MonoArray *Array_to_mono_array(const Array &p_array, GDMonoClass *p_array_type_class); Array mono_array_to_Array(MonoArray *p_array); // PoolIntArray From dfdb7bdc8798b594aae2062138cd0a3ec3b2df9e Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Thu, 23 Apr 2020 02:23:25 +0200 Subject: [PATCH 12/12] Mono/C#: Fix assemblies being reloaded a second time unnecesarily (cherry picked from commit c9882e61e2ccc248ee3728ea936bb42e9d145528) --- modules/mono/mono_gd/gd_mono.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index d6d3353a8b5d..5c86f9a12bc9 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -1386,7 +1386,10 @@ bool _GodotSharp::is_runtime_initialized() { void _GodotSharp::_reload_assemblies(bool p_soft_reload) { #ifdef GD_MONO_HOT_RELOAD - CSharpLanguage::get_singleton()->reload_assemblies(p_soft_reload); + // This method may be called more than once with `call_deferred`, so we need to check + // again if reloading is needed to avoid reloading multiple times unnecessarily. + if (CSharpLanguage::get_singleton()->is_assembly_reloading_needed()) + CSharpLanguage::get_singleton()->reload_assemblies(p_soft_reload); #endif }