1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Merge pull request #106031 from samuelll3d/fix-slnpath-resolve

C#: Fix loading correct solution file for projects in subdirectories
This commit is contained in:
Thaddeus Crews
2025-10-30 10:45:58 -05:00
2 changed files with 63 additions and 6 deletions

View File

@@ -37,6 +37,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
<PackageReference Include="JetBrains.Rider.PathLocator" Version="1.0.12" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.VisualStudio.SolutionPersistence" Version="1.0.52" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<Reference Include="GodotSharp">
<HintPath>$(GodotApiAssembliesDir)/GodotSharp.dll</HintPath>

View File

@@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading;
using Godot;
using Godot.NativeInterop;
using GodotTools.Core;
using static GodotTools.Internals.Globals;
using Microsoft.VisualStudio.SolutionPersistence;
using Microsoft.VisualStudio.SolutionPersistence.Serializer;
namespace GodotTools.Internals
{
@@ -73,17 +76,70 @@ namespace GodotTools.Internals
string? slnParentDir = (string?)ProjectSettings.GetSetting("dotnet/project/solution_directory");
if (string.IsNullOrEmpty(slnParentDir))
slnParentDir = "res://";
else if (!slnParentDir.StartsWith("res://", System.StringComparison.Ordinal))
else if (!slnParentDir.StartsWith("res://", StringComparison.Ordinal))
slnParentDir = "res://" + slnParentDir;
// The csproj should be in the same folder as project.godot.
string csprojParentDir = "res://";
_projectSlnPath = Path.Combine(ProjectSettings.GlobalizePath(slnParentDir),
string.Concat(_projectAssemblyName, ".sln"));
// Set csproj path first and use it to find the sln/slnx file with the assembly
_projectCsProjPath = Path.Combine(ProjectSettings.GlobalizePath(csprojParentDir),
string.Concat(_projectAssemblyName, ".csproj"));
_projectSlnPath = FindSolutionFileWithAssemblyName(slnParentDir, _projectAssemblyName);
}
private static string FindSolutionFileWithAssemblyName(string directory, string assemblyName)
{
// Will convert ".." to load solutions from parent directory when appropriate
string slnAbsolutePath = Path.GetFullPath(ProjectSettings.GlobalizePath(directory));
List<string> solutionFilePaths = new();
solutionFilePaths.AddRange(Directory.GetFiles(slnAbsolutePath, "*.sln"));
solutionFilePaths.AddRange(Directory.GetFiles(slnAbsolutePath, "*.slnx"));
if (solutionFilePaths.Count == 0)
return Path.Combine(slnAbsolutePath, $"{assemblyName}.sln");
List<string> matchingSolutions = new();
foreach (string solutionFilePath in solutionFilePaths)
{
ISolutionSerializer? serializer = SolutionSerializers.GetSerializerByMoniker(solutionFilePath);
if (serializer is null)
continue;
string? solutionDirectory = Path.GetDirectoryName(solutionFilePath);
if (solutionDirectory is null)
continue;
var solution = serializer.OpenAsync(solutionFilePath, CancellationToken.None).Result;
foreach (var project in solution.SolutionProjects)
{
// Convert '\' path separators on Windows to '/' to match Godot's Unix style separators
var absoluteProjectFilePath = Path.GetFullPath(project.FilePath, solutionDirectory).Replace('\\', '/');
if (string.Equals(absoluteProjectFilePath, _projectCsProjPath, StringComparison.Ordinal))
matchingSolutions.Add(solutionFilePath);
}
}
switch (matchingSolutions.Count)
{
case 1:
return matchingSolutions[0];
case > 1:
GD.PushError(
$"Multiple solutions containing a project with assembly name '{assemblyName}' were found:\n"
+ $"{string.Join('\n', matchingSolutions).Replace('\\', '/')}\n"
+ "Please ensure only one solution contains the project assembly.\n"
+ "If you have recently migrated to .slnx please ensure that you have removed the unused .sln.");
break;
}
return Path.Combine(slnAbsolutePath, $"{assemblyName}.sln");
}
private static string? _projectAssemblyName;