Browse Source

Mono: Fix Api HintPath and update old game projects

Fixed Api assembly references with more than one HintPath.
Also made the editor update old C# projects use the new Api assembly HintPaths.
Ignacio Etcheverry 6 years ago
parent
commit
9eb0729a05

+ 0 - 2
modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs

@@ -91,13 +91,11 @@ namespace GodotTools.ProjectEditor
 
             var coreApiRef = root.AddItem("Reference", CoreApiProjectName);
             coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", CoreApiProjectName + ".dll"));
-            coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", CoreApiProjectName + ".dll"));
             coreApiRef.AddMetadata("Private", "False");
 
             var editorApiRef = root.AddItem("Reference", EditorApiProjectName);
             editorApiRef.Condition = " '$(Configuration)' == 'Tools' ";
             editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", EditorApiProjectName + ".dll"));
-            editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", EditorApiProjectName + ".dll"));
             editorApiRef.AddMetadata("Private", "False");
 
             GenAssemblyInfoFile(root, dir, name);

+ 105 - 2
modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs

@@ -1,6 +1,8 @@
 using GodotTools.Core;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.IO;
+using System.Linq;
 using DotNet.Globbing;
 using Microsoft.Build.Construction;
 
@@ -12,6 +14,8 @@ namespace GodotTools.ProjectEditor
         {
             var dir = Directory.GetParent(projectPath).FullName;
             var root = ProjectRootElement.Open(projectPath);
+            Debug.Assert(root != null);
+
             var normalizedInclude = include.RelativeToPath(dir).Replace("/", "\\");
 
             if (root.AddItemChecked(itemType, normalizedInclude))
@@ -23,7 +27,8 @@ namespace GodotTools.ProjectEditor
             string[] files = Directory.GetFiles(rootDirectory, mask, SearchOption.AllDirectories);
 
             // We want relative paths
-            for (int i = 0; i < files.Length; i++) {
+            for (int i = 0; i < files.Length; i++)
+            {
                 files[i] = files[i].RelativeToPath(rootDirectory);
             }
 
@@ -35,7 +40,7 @@ namespace GodotTools.ProjectEditor
             var result = new List<string>();
             var existingFiles = GetAllFilesRecursive(Path.GetDirectoryName(projectPath), "*.cs");
 
-            GlobOptions globOptions = new GlobOptions();
+            var globOptions = new GlobOptions();
             globOptions.Evaluation.CaseInsensitive = false;
 
             var root = ProjectRootElement.Open(projectPath);
@@ -68,5 +73,103 @@ namespace GodotTools.ProjectEditor
 
             return result.ToArray();
         }
+
+        ///  Simple function to make sure the Api assembly references are configured correctly
+        public static void FixApiHintPath(string projectPath)
+        {
+            var root = ProjectRootElement.Open(projectPath);
+            Debug.Assert(root != null);
+
+            bool dirty = false;
+
+            void AddPropertyIfNotPresent(string name, string condition, string value)
+            {
+                if (root.PropertyGroups
+                    .Any(g => g.Condition == string.Empty || g.Condition == condition &&
+                              g.Properties
+                                  .Any(p => p.Name == name &&
+                                            p.Value == value &&
+                                            (p.Condition == condition || g.Condition == condition))))
+                {
+                    return;
+                }
+
+                root.AddProperty(name, value).Condition = condition;
+                dirty = true;
+            }
+
+            AddPropertyIfNotPresent(name: "ApiConfiguration",
+                condition: " '$(Configuration)' != 'Release' ",
+                value: "Debug");
+            AddPropertyIfNotPresent(name: "ApiConfiguration",
+                condition: " '$(Configuration)' == 'Release' ",
+                value: "Release");
+
+            void SetReferenceHintPath(string referenceName, string condition, string hintPath)
+            {
+                foreach (var itemGroup in root.ItemGroups.Where(g =>
+                    g.Condition == string.Empty || g.Condition == condition))
+                {
+                    var references = itemGroup.Items.Where(item =>
+                        item.ItemType == "Reference" &&
+                        item.Include == referenceName &&
+                        (item.Condition == condition || itemGroup.Condition == condition));
+
+                    var referencesWithHintPath = references.Where(reference =>
+                        reference.Metadata.Any(m => m.Name == "HintPath"));
+
+                    if (referencesWithHintPath.Any(reference => reference.Metadata
+                        .Any(m => m.Name == "HintPath" && m.Value == hintPath)))
+                    {
+                        // Found a Reference item with the right HintPath
+                        return;
+                    }
+
+                    var referenceWithHintPath = referencesWithHintPath.FirstOrDefault();
+                    if (referenceWithHintPath != null)
+                    {
+                        // Found a Reference item with a wrong HintPath
+                        foreach (var metadata in referenceWithHintPath.Metadata.ToList()
+                            .Where(m => m.Name == "HintPath"))
+                        {
+                            // Safe to remove as we duplicate with ToList() to loop
+                            referenceWithHintPath.RemoveChild(metadata);
+                        }
+
+                        referenceWithHintPath.AddMetadata("HintPath", hintPath);
+                        dirty = true;
+                        return;
+                    }
+
+                    var referenceWithoutHintPath = references.FirstOrDefault();
+                    if (referenceWithoutHintPath != null)
+                    {
+                        // 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";
+            const string editorProjectName = "GodotSharpEditor";
+
+            const string coreCondition = "";
+            const string editorCondition = " '$(Configuration)' == 'Tools' ";
+
+            var coreHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{coreProjectName}.dll";
+            var editorHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{editorProjectName}.dll";
+
+            SetReferenceHintPath(coreProjectName, coreCondition, coreHintPath);
+            SetReferenceHintPath(editorProjectName, editorCondition, editorHintPath);
+
+            if (dirty)
+                root.Save();
+        }
     }
 }

+ 12 - 0
modules/mono/editor/GodotTools/GodotTools/CSharpProject.cs

@@ -32,6 +32,18 @@ namespace GodotTools
             ProjectUtils.AddItemToProjectChecked(projectPath, itemType, include);
         }
 
+        public static void FixApiHintPath(string projectPath)
+        {
+            try
+            {
+                ProjectUtils.FixApiHintPath(projectPath);
+            }
+            catch (Exception e)
+            {
+                GD.PushError(e.ToString());
+            }
+        }
+
         private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
 
         private static ulong ConvertToTimestamp(this DateTime value)

+ 3 - 0
modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs

@@ -464,6 +464,9 @@ namespace GodotTools
             {
                 // Defer this task because EditorProgress calls Main::iterarion() and the main loop is not yet initialized.
                 CallDeferred(nameof(_MakeApiSolutionsIfNeeded));
+
+                // Make sure the existing project has Api assembly references configured correctly
+                CSharpProject.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath);
             }
             else
             {