feat: updated engine version to 4.4-rc1
This commit is contained in:
parent
ee00efde1f
commit
21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions
|
|
@ -86,7 +86,7 @@ namespace GodotTools.BuildLogger
|
|||
|
||||
WriteLine(line);
|
||||
|
||||
string errorLine = $@"error,{e.File.CsvEscape()},{e.LineNumber},{e.ColumnNumber}," +
|
||||
string errorLine = $@"error,{e.File?.CsvEscape() ?? string.Empty},{e.LineNumber},{e.ColumnNumber}," +
|
||||
$"{e.Code?.CsvEscape() ?? string.Empty},{e.Message.CsvEscape()}," +
|
||||
$"{e.ProjectFile?.CsvEscape() ?? string.Empty}";
|
||||
_issuesStreamWriter.WriteLine(errorLine);
|
||||
|
|
@ -101,7 +101,7 @@ namespace GodotTools.BuildLogger
|
|||
|
||||
WriteLine(line);
|
||||
|
||||
string warningLine = $@"warning,{e.File.CsvEscape()},{e.LineNumber},{e.ColumnNumber}," +
|
||||
string warningLine = $@"warning,{e.File?.CsvEscape() ?? string.Empty},{e.LineNumber},{e.ColumnNumber}," +
|
||||
$"{e.Code?.CsvEscape() ?? string.Empty},{e.Message.CsvEscape()}," +
|
||||
$"{e.ProjectFile?.CsvEscape() ?? string.Empty}";
|
||||
_issuesStreamWriter.WriteLine(warningLine);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{639E48BD-44E5-4091-8EDD-22D36DC0768D}</ProjectGuid>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>10</LangVersion>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>12</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<LangVersion>10</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
||||
<SelfContained>False</SelfContained>
|
||||
<RollForward>LatestMajor</RollForward>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}</ProjectGuid>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>10</LangVersion>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>12</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Build" Version="15.1.548" ExcludeAssets="runtime" />
|
||||
<PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
|
||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
|
||||
<PackageReference Include="NuGet.Frameworks" Version="6.12.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj" />
|
||||
<ProjectReference Include="..\GodotTools.Shared\GodotTools.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ namespace GodotTools.ProjectEditor
|
|||
{
|
||||
public static string GodotSdkAttrValue => $"Godot.NET.Sdk/{GeneratedGodotNupkgsVersions.GodotNETSdk}";
|
||||
|
||||
public static string GodotMinimumRequiredTfm => "net8.0";
|
||||
|
||||
public static ProjectRootElement GenGameProject(string name)
|
||||
{
|
||||
if (name.Length == 0)
|
||||
|
|
@ -22,13 +24,7 @@ namespace GodotTools.ProjectEditor
|
|||
root.Sdk = GodotSdkAttrValue;
|
||||
|
||||
var mainGroup = root.AddPropertyGroup();
|
||||
mainGroup.AddProperty("TargetFramework", "net6.0");
|
||||
|
||||
var net7 = mainGroup.AddProperty("TargetFramework", "net7.0");
|
||||
net7.Condition = " '$(GodotTargetPlatform)' == 'android' ";
|
||||
|
||||
var net8 = mainGroup.AddProperty("TargetFramework", "net8.0");
|
||||
net8.Condition = " '$(GodotTargetPlatform)' == 'ios' ";
|
||||
mainGroup.AddProperty("TargetFramework", GodotMinimumRequiredTfm);
|
||||
|
||||
mainGroup.AddProperty("EnableDynamicLoading", "true");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Build.Construction;
|
||||
using Microsoft.Build.Evaluation;
|
||||
using Microsoft.Build.Locator;
|
||||
using NuGet.Frameworks;
|
||||
|
||||
namespace GodotTools.ProjectEditor
|
||||
{
|
||||
|
|
@ -19,8 +23,21 @@ namespace GodotTools.ProjectEditor
|
|||
}
|
||||
}
|
||||
|
||||
public static class ProjectUtils
|
||||
public static partial class ProjectUtils
|
||||
{
|
||||
[GeneratedRegex(@"\s*'\$\(GodotTargetPlatform\)'\s*==\s*'(?<platform>[A-z]+)'\s*", RegexOptions.IgnoreCase)]
|
||||
private static partial Regex GodotTargetPlatformConditionRegex();
|
||||
|
||||
private static readonly string[] _platformNames =
|
||||
{
|
||||
"windows",
|
||||
"linuxbsd",
|
||||
"macos",
|
||||
"android",
|
||||
"ios",
|
||||
"web",
|
||||
};
|
||||
|
||||
public static void MSBuildLocatorRegisterLatest(out Version version, out string path)
|
||||
{
|
||||
var instance = MSBuildLocator.QueryVisualStudioInstances()
|
||||
|
|
@ -36,11 +53,22 @@ namespace GodotTools.ProjectEditor
|
|||
|
||||
public static MSBuildProject? Open(string path)
|
||||
{
|
||||
var root = ProjectRootElement.Open(path);
|
||||
var root = ProjectRootElement.Open(path, ProjectCollection.GlobalProjectCollection, preserveFormatting: true);
|
||||
return root != null ? new MSBuildProject(root) : null;
|
||||
}
|
||||
|
||||
public static void MigrateToProjectSdksStyle(MSBuildProject project, string projectName)
|
||||
public static void UpgradeProjectIfNeeded(MSBuildProject project, string projectName)
|
||||
{
|
||||
// NOTE: The order in which changes are made to the project is important.
|
||||
|
||||
// Migrate to MSBuild project Sdks style if using the old style.
|
||||
MigrateToProjectSdksStyle(project, projectName);
|
||||
|
||||
EnsureGodotSdkIsUpToDate(project);
|
||||
EnsureTargetFrameworkMatchesMinimumRequirement(project);
|
||||
}
|
||||
|
||||
private static void MigrateToProjectSdksStyle(MSBuildProject project, string projectName)
|
||||
{
|
||||
var origRoot = project.Root;
|
||||
|
||||
|
|
@ -64,5 +92,128 @@ namespace GodotTools.ProjectEditor
|
|||
root.Sdk = godotSdkAttrValue;
|
||||
project.HasUnsavedChanges = true;
|
||||
}
|
||||
|
||||
private static void EnsureTargetFrameworkMatchesMinimumRequirement(MSBuildProject project)
|
||||
{
|
||||
var root = project.Root;
|
||||
string minTfmValue = ProjectGenerator.GodotMinimumRequiredTfm;
|
||||
var minTfmVersion = NuGetFramework.Parse(minTfmValue).Version;
|
||||
|
||||
ProjectPropertyGroupElement? mainPropertyGroup = null;
|
||||
ProjectPropertyElement? mainTargetFrameworkProperty = null;
|
||||
|
||||
var propertiesToChange = new List<ProjectPropertyElement>();
|
||||
|
||||
foreach (var propertyGroup in root.PropertyGroups)
|
||||
{
|
||||
bool groupHasCondition = !string.IsNullOrEmpty(propertyGroup.Condition);
|
||||
|
||||
// Check if the property group should be excluded from checking for 'TargetFramework' properties.
|
||||
if (groupHasCondition && !ConditionMatchesGodotPlatform(propertyGroup.Condition))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store a reference to the first property group without conditions,
|
||||
// in case we need to add a new 'TargetFramework' property later.
|
||||
if (mainPropertyGroup == null && !groupHasCondition)
|
||||
{
|
||||
mainPropertyGroup = propertyGroup;
|
||||
}
|
||||
|
||||
foreach (var property in propertyGroup.Properties)
|
||||
{
|
||||
// We are looking for 'TargetFramework' properties.
|
||||
if (property.Name != "TargetFramework")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool propertyHasCondition = !string.IsNullOrEmpty(property.Condition);
|
||||
|
||||
// Check if the property should be excluded.
|
||||
if (propertyHasCondition && !ConditionMatchesGodotPlatform(property.Condition))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!groupHasCondition && !propertyHasCondition)
|
||||
{
|
||||
// Store a reference to the 'TargetFramework' that has no conditions
|
||||
// because it applies to all platforms.
|
||||
if (mainTargetFrameworkProperty == null)
|
||||
{
|
||||
mainTargetFrameworkProperty = property;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the 'TargetFramework' property is conditional, it may no longer be needed
|
||||
// when the main one is upgraded to the new minimum version.
|
||||
var tfmVersion = NuGetFramework.Parse(property.Value).Version;
|
||||
if (tfmVersion <= minTfmVersion)
|
||||
{
|
||||
propertiesToChange.Add(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mainTargetFrameworkProperty == null)
|
||||
{
|
||||
// We haven't found a 'TargetFramework' property without conditions,
|
||||
// we'll just add one in the first property group without conditions.
|
||||
if (mainPropertyGroup == null)
|
||||
{
|
||||
// We also don't have a property group without conditions,
|
||||
// so we'll add a new one to the project.
|
||||
mainPropertyGroup = root.AddPropertyGroup();
|
||||
}
|
||||
|
||||
mainTargetFrameworkProperty = mainPropertyGroup.AddProperty("TargetFramework", minTfmValue);
|
||||
project.HasUnsavedChanges = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var tfmVersion = NuGetFramework.Parse(mainTargetFrameworkProperty.Value).Version;
|
||||
if (tfmVersion < minTfmVersion)
|
||||
{
|
||||
mainTargetFrameworkProperty.Value = minTfmValue;
|
||||
project.HasUnsavedChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
var mainTfmVersion = NuGetFramework.Parse(mainTargetFrameworkProperty.Value).Version;
|
||||
foreach (var property in propertiesToChange)
|
||||
{
|
||||
// If the main 'TargetFramework' property targets a version newer than
|
||||
// the minimum required by Godot, we don't want to remove the conditional
|
||||
// 'TargetFramework' properties, only upgrade them to the new minimum.
|
||||
// Otherwise, it can be removed.
|
||||
if (mainTfmVersion > minTfmVersion)
|
||||
{
|
||||
property.Value = minTfmValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
property.Parent.RemoveChild(property);
|
||||
}
|
||||
|
||||
project.HasUnsavedChanges = true;
|
||||
}
|
||||
|
||||
static bool ConditionMatchesGodotPlatform(string condition)
|
||||
{
|
||||
// Check if the condition is checking the 'GodotTargetPlatform' for one of the
|
||||
// Godot platforms with built-in support in the Godot.NET.Sdk.
|
||||
var match = GodotTargetPlatformConditionRegex().Match(condition);
|
||||
if (match.Success)
|
||||
{
|
||||
string platform = match.Groups["platform"].Value;
|
||||
return _platformNames.Contains(platform, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<!-- Specify compile items manually to avoid including dangling generated items. -->
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
</PropertyGroup>
|
||||
<Import Project="GenerateGodotNupkgsVersions.targets" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>12</LangVersion>
|
||||
<!-- Specify compile items manually to avoid including dangling generated items. -->
|
||||
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="GenerateGodotNupkgsVersions.targets" />
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -265,11 +265,6 @@ namespace GodotTools.Build
|
|||
success = Publish(buildInfo);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
ShowBuildErrorDialog("Failed to publish .NET project");
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,7 +75,19 @@ namespace GodotTools.Export
|
|||
};
|
||||
}
|
||||
|
||||
private string? _maybeLastExportError;
|
||||
private void AddExceptionMessage(EditorExportPlatform platform, Exception exception)
|
||||
{
|
||||
string? exceptionMessage = exception.Message;
|
||||
if (string.IsNullOrEmpty(exceptionMessage))
|
||||
{
|
||||
exceptionMessage = $"Exception thrown: {exception.GetType().Name}";
|
||||
}
|
||||
|
||||
platform.AddMessage(EditorExportPlatform.ExportMessageType.Error, "Export .NET Project", exceptionMessage);
|
||||
|
||||
// We also print exceptions as we receive them to stderr.
|
||||
Console.Error.WriteLine(exception);
|
||||
}
|
||||
|
||||
// With this method we can override how a file is exported in the PCK
|
||||
public override void _ExportFile(string path, string type, string[] features)
|
||||
|
|
@ -92,8 +104,8 @@ namespace GodotTools.Export
|
|||
|
||||
if (!ProjectContainsDotNet())
|
||||
{
|
||||
_maybeLastExportError = $"This project contains C# files but no solution file was found at the following path: {GodotSharpDirs.ProjectSlnPath}\n" +
|
||||
"A solution file is required for projects with C# files. Please ensure that the solution file exists in the specified location and try again.";
|
||||
GetExportPlatform().AddMessage(EditorExportPlatform.ExportMessageType.Error, "Export .NET Project", $"This project contains C# files but no solution file was found at the following path: {GodotSharpDirs.ProjectSlnPath}\n" +
|
||||
"A solution file is required for projects with C# files. Please ensure that the solution file exists in the specified location and try again.");
|
||||
throw new InvalidOperationException($"{path} is a C# file but no solution file exists.");
|
||||
}
|
||||
|
||||
|
|
@ -124,16 +136,7 @@ namespace GodotTools.Export
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_maybeLastExportError = e.Message;
|
||||
|
||||
// 'maybeLastExportError' cannot be null or empty if there was an error, so we
|
||||
// must consider the possibility of exceptions being thrown without a message.
|
||||
if (string.IsNullOrEmpty(_maybeLastExportError))
|
||||
_maybeLastExportError = $"Exception thrown: {e.GetType().Name}";
|
||||
|
||||
GD.PushError($"Failed to export project: {_maybeLastExportError}");
|
||||
Console.Error.WriteLine(e);
|
||||
// TODO: Do something on error once _ExportBegin supports failing.
|
||||
AddExceptionMessage(GetExportPlatform(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +147,9 @@ namespace GodotTools.Export
|
|||
if (!ProjectContainsDotNet())
|
||||
return;
|
||||
|
||||
if (!DeterminePlatformFromFeatures(features, out string? platform))
|
||||
string osName = GetExportPlatform().GetOsName();
|
||||
|
||||
if (!TryDeterminePlatformFromOSName(osName, out string? platform))
|
||||
throw new NotSupportedException("Target platform not supported.");
|
||||
|
||||
if (!new[] { OS.Platforms.Windows, OS.Platforms.LinuxBSD, OS.Platforms.MacOS, OS.Platforms.Android, OS.Platforms.iOS }
|
||||
|
|
@ -211,6 +216,8 @@ namespace GodotTools.Export
|
|||
|
||||
bool embedBuildResults = ((bool)GetOption("dotnet/embed_build_outputs") || platform == OS.Platforms.Android) && platform != OS.Platforms.MacOS;
|
||||
|
||||
var exportedJars = new HashSet<string>();
|
||||
|
||||
foreach (PublishConfig config in targets)
|
||||
{
|
||||
string ridOS = config.RidOS;
|
||||
|
|
@ -240,7 +247,6 @@ namespace GodotTools.Export
|
|||
{
|
||||
publishOutputDir = Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, "godot-publish-dotnet",
|
||||
$"{buildConfig}-{runtimeIdentifier}");
|
||||
|
||||
}
|
||||
|
||||
outputPaths.Add(publishOutputDir);
|
||||
|
|
@ -317,6 +323,41 @@ namespace GodotTools.Export
|
|||
{
|
||||
if (embedBuildResults)
|
||||
{
|
||||
if (platform == OS.Platforms.Android)
|
||||
{
|
||||
string fileName = Path.GetFileName(path);
|
||||
|
||||
if (IsSharedObject(fileName))
|
||||
{
|
||||
AddSharedObject(path, tags: new string[] { arch },
|
||||
Path.Join(projectDataDirName,
|
||||
Path.GetRelativePath(publishOutputDir,
|
||||
Path.GetDirectoryName(path)!)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool IsSharedObject(string fileName)
|
||||
{
|
||||
if (fileName.EndsWith(".jar"))
|
||||
{
|
||||
// Don't export the same jar twice. Otherwise we will have conflicts.
|
||||
// This can happen when exporting for multiple architectures. Dotnet
|
||||
// stores the jars in .godot/mono/temp/bin/Export[Debug|Release] per
|
||||
// target architecture. Jars are cpu agnostic so only 1 is needed.
|
||||
var jarName = Path.GetFileName(fileName);
|
||||
return exportedJars.Add(jarName);
|
||||
}
|
||||
|
||||
if (fileName.EndsWith(".so") || fileName.EndsWith(".a") || fileName.EndsWith(".dex"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
string filePath = SanitizeSlashes(Path.GetRelativePath(publishOutputDir, path));
|
||||
byte[] fileData = File.ReadAllBytes(path);
|
||||
string hash = Convert.ToBase64String(SHA512.HashData(fileData));
|
||||
|
|
@ -355,24 +396,23 @@ namespace GodotTools.Export
|
|||
if (outputPaths.Count > 2)
|
||||
{
|
||||
// lipo the simulator binaries together
|
||||
// TODO: Move this to the native lipo implementation we have in the macos export plugin.
|
||||
var lipoArgs = new List<string>();
|
||||
lipoArgs.Add("-create");
|
||||
lipoArgs.AddRange(outputPaths.Skip(1).Select(x => Path.Combine(x, $"{GodotSharpDirs.ProjectAssemblyName}.dylib")));
|
||||
lipoArgs.Add("-output");
|
||||
lipoArgs.Add(Path.Combine(outputPaths[1], $"{GodotSharpDirs.ProjectAssemblyName}.dylib"));
|
||||
|
||||
int lipoExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("lipo"), lipoArgs);
|
||||
if (lipoExitCode != 0)
|
||||
throw new InvalidOperationException($"Command 'lipo' exited with code: {lipoExitCode}.");
|
||||
string outputPath = Path.Combine(outputPaths[1], $"{GodotSharpDirs.ProjectAssemblyName}.dylib");
|
||||
string[] files = outputPaths
|
||||
.Skip(1)
|
||||
.Select(path => Path.Combine(path, $"{GodotSharpDirs.ProjectAssemblyName}.dylib"))
|
||||
.ToArray();
|
||||
|
||||
if (!Internal.LipOCreateFile(outputPath, files))
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to 'lipo' simulator binaries.");
|
||||
}
|
||||
|
||||
outputPaths.RemoveRange(2, outputPaths.Count - 2);
|
||||
}
|
||||
|
||||
var xcFrameworkPath = Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, publishConfig.BuildConfig,
|
||||
$"{GodotSharpDirs.ProjectAssemblyName}_aot.xcframework");
|
||||
if (!BuildManager.GenerateXCFrameworkBlocking(outputPaths,
|
||||
Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, publishConfig.BuildConfig, xcFrameworkPath)))
|
||||
string xcFrameworkPath = Path.Combine(GodotSharpDirs.ProjectBaseOutputPath, publishConfig.BuildConfig, $"{GodotSharpDirs.ProjectAssemblyName}_aot.xcframework");
|
||||
if (!BuildManager.GenerateXCFrameworkBlocking(outputPaths, xcFrameworkPath))
|
||||
{
|
||||
throw new InvalidOperationException("Failed to generate xcframework.");
|
||||
}
|
||||
|
|
@ -446,25 +486,22 @@ namespace GodotTools.Export
|
|||
Directory.Delete(folder, recursive: true);
|
||||
}
|
||||
_tempFolders.Clear();
|
||||
|
||||
// TODO: The following is just a workaround until the export plugins can be made to abort with errors
|
||||
|
||||
// We check for empty as well, because it's set to empty after hot-reloading
|
||||
if (!string.IsNullOrEmpty(_maybeLastExportError))
|
||||
{
|
||||
string lastExportError = _maybeLastExportError;
|
||||
_maybeLastExportError = null;
|
||||
|
||||
GodotSharpEditor.Instance.ShowErrorDialog(lastExportError, "Failed to export C# project");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool DeterminePlatformFromFeatures(IEnumerable<string> features, [NotNullWhen(true)] out string? platform)
|
||||
/// <summary>
|
||||
/// Tries to determine the platform from the export preset's platform OS name.
|
||||
/// </summary>
|
||||
/// <param name="osName">Name of the export operating system.</param>
|
||||
/// <param name="platform">Platform name for the recognized supported platform.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> when the platform OS name is recognized as a supported platform,
|
||||
/// <see langword="false"/> otherwise.
|
||||
/// </returns>
|
||||
private static bool TryDeterminePlatformFromOSName(string osName, [NotNullWhen(true)] out string? platform)
|
||||
{
|
||||
foreach (var feature in features)
|
||||
if (OS.PlatformFeatureMap.TryGetValue(osName, out platform))
|
||||
{
|
||||
if (OS.PlatformFeatureMap.TryGetValue(feature, out platform))
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
platform = null;
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace GodotTools.Export
|
||||
{
|
||||
public static class XcodeHelper
|
||||
{
|
||||
private static string? _XcodePath = null;
|
||||
|
||||
public static string XcodePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_XcodePath == null)
|
||||
{
|
||||
_XcodePath = FindXcode();
|
||||
|
||||
if (_XcodePath == null)
|
||||
throw new FileNotFoundException("Could not find Xcode.");
|
||||
}
|
||||
|
||||
return _XcodePath;
|
||||
}
|
||||
}
|
||||
|
||||
private static string? FindSelectedXcode()
|
||||
{
|
||||
var outputWrapper = new Godot.Collections.Array();
|
||||
|
||||
int exitCode = Godot.OS.Execute("xcode-select", new string[] { "--print-path" }, output: outputWrapper);
|
||||
|
||||
if (exitCode == 0)
|
||||
{
|
||||
string output = (string)outputWrapper[0];
|
||||
return output.Trim();
|
||||
}
|
||||
|
||||
Console.Error.WriteLine($"'xcode-select --print-path' exited with code: {exitCode}");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string? FindXcode()
|
||||
{
|
||||
string? selectedXcode = FindSelectedXcode();
|
||||
if (selectedXcode != null)
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(selectedXcode, "Contents", "Developer")))
|
||||
return selectedXcode;
|
||||
|
||||
// The path already pointed to Contents/Developer
|
||||
var dirInfo = new DirectoryInfo(selectedXcode);
|
||||
if (dirInfo is not { Parent.Name: "Contents", Name: "Developer" })
|
||||
{
|
||||
Console.WriteLine(Path.GetDirectoryName(selectedXcode));
|
||||
Console.WriteLine(System.IO.Directory.GetParent(selectedXcode)?.Name);
|
||||
Console.Error.WriteLine("Unrecognized path for selected Xcode");
|
||||
}
|
||||
else
|
||||
{
|
||||
return System.IO.Path.GetFullPath($"{selectedXcode}/../..");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error.WriteLine("Could not find the selected Xcode; trying with a hint path");
|
||||
}
|
||||
|
||||
const string XcodeHintPath = "/Applications/Xcode.app";
|
||||
|
||||
if (Directory.Exists(XcodeHintPath))
|
||||
{
|
||||
if (Directory.Exists(Path.Combine(XcodeHintPath, "Contents", "Developer")))
|
||||
return XcodeHintPath;
|
||||
|
||||
Console.Error.WriteLine($"Found Xcode at '{XcodeHintPath}' but it's missing the 'Contents/Developer' sub-directory");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string FindXcodeTool(string toolName)
|
||||
{
|
||||
string XcodeDefaultToolchain = Path.Combine(XcodePath, "Contents", "Developer", "Toolchains", "XcodeDefault.xctoolchain");
|
||||
|
||||
string path = Path.Combine(XcodeDefaultToolchain, "usr", "bin", toolName);
|
||||
if (File.Exists(path))
|
||||
return path;
|
||||
|
||||
throw new FileNotFoundException($"Cannot find Xcode tool: {toolName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using GodotTools.Build;
|
||||
using GodotTools.Ides;
|
||||
using GodotTools.Ides.Rider;
|
||||
|
|
@ -176,7 +177,7 @@ namespace GodotTools
|
|||
|
||||
private static readonly string[] VsCodeNames =
|
||||
{
|
||||
"code", "code-oss", "vscode", "vscode-oss", "visual-studio-code", "visual-studio-code-oss"
|
||||
"code", "code-oss", "vscode", "vscode-oss", "visual-studio-code", "visual-studio-code-oss", "codium"
|
||||
};
|
||||
|
||||
[UsedImplicitly]
|
||||
|
|
@ -259,11 +260,12 @@ namespace GodotTools
|
|||
|
||||
var args = new List<string>
|
||||
{
|
||||
Path.Combine(GodotSharpDirs.DataEditorToolsDir, "GodotTools.OpenVisualStudio.dll"),
|
||||
GodotSharpDirs.ProjectSlnPath,
|
||||
line >= 0 ? $"{scriptPath};{line + 1};{col + 1}" : scriptPath
|
||||
};
|
||||
|
||||
string command = Path.Combine(GodotSharpDirs.DataEditorToolsDir, "GodotTools.OpenVisualStudio.exe");
|
||||
string command = DotNetFinder.FindDotNetExe() ?? "dotnet";
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -328,7 +330,7 @@ namespace GodotTools
|
|||
args.Add("-b");
|
||||
args.Add(vscodeBundleId);
|
||||
|
||||
// The reusing of existing windows made by the 'open' command might not choose a wubdiw that is
|
||||
// The reusing of existing windows made by the 'open' command might not choose a window that is
|
||||
// editing our folder. It's better to ask for a new window and let VSCode do the window management.
|
||||
args.Add("-n");
|
||||
|
||||
|
|
@ -337,6 +339,28 @@ namespace GodotTools
|
|||
|
||||
args.Add("--args");
|
||||
}
|
||||
|
||||
// Try VSCodium as a fallback if Visual Studio Code can't be found.
|
||||
if (!macOSAppBundleInstalled)
|
||||
{
|
||||
const string VscodiumBundleId = "com.vscodium.codium";
|
||||
macOSAppBundleInstalled = Internal.IsMacOSAppBundleInstalled(VscodiumBundleId);
|
||||
|
||||
if (macOSAppBundleInstalled)
|
||||
{
|
||||
args.Add("-b");
|
||||
args.Add(VscodiumBundleId);
|
||||
|
||||
// The reusing of existing windows made by the 'open' command might not choose a window that is
|
||||
// editing our folder. It's better to ask for a new window and let VSCode do the window management.
|
||||
args.Add("-n");
|
||||
|
||||
// The open process must wait until the application finishes (which is instant in VSCode's case)
|
||||
args.Add("--wait-apps");
|
||||
|
||||
args.Add("--args");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
args.Add(Path.GetDirectoryName(GodotSharpDirs.ProjectSlnPath)!);
|
||||
|
|
@ -359,7 +383,7 @@ namespace GodotTools
|
|||
{
|
||||
if (!macOSAppBundleInstalled && string.IsNullOrEmpty(_vsCodePath))
|
||||
{
|
||||
GD.PushError("Cannot find code editor: VSCode");
|
||||
GD.PushError("Cannot find code editor: Visual Studio Code or VSCodium");
|
||||
return Error.FileNotFound;
|
||||
}
|
||||
|
||||
|
|
@ -369,7 +393,7 @@ namespace GodotTools
|
|||
{
|
||||
if (string.IsNullOrEmpty(_vsCodePath))
|
||||
{
|
||||
GD.PushError("Cannot find code editor: VSCode");
|
||||
GD.PushError("Cannot find code editor: Visual Studio Code or VSCodium");
|
||||
return Error.FileNotFound;
|
||||
}
|
||||
|
||||
|
|
@ -382,7 +406,7 @@ namespace GodotTools
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
GD.PushError($"Error when trying to run code editor: VSCode. Exception message: '{e.Message}'");
|
||||
GD.PushError($"Error when trying to run code editor: Visual Studio Code or VSCodium. Exception message: '{e.Message}'");
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -415,12 +439,7 @@ namespace GodotTools
|
|||
var msbuildProject = ProjectUtils.Open(GodotSharpDirs.ProjectCsProjPath)
|
||||
?? throw new InvalidOperationException("Cannot open C# project.");
|
||||
|
||||
// NOTE: The order in which changes are made to the project is important
|
||||
|
||||
// Migrate to MSBuild project Sdks style if using the old style
|
||||
ProjectUtils.MigrateToProjectSdksStyle(msbuildProject, GodotSharpDirs.ProjectAssemblyName);
|
||||
|
||||
ProjectUtils.EnsureGodotSdkIsUpToDate(msbuildProject);
|
||||
ProjectUtils.UpgradeProjectIfNeeded(msbuildProject, GodotSharpDirs.ProjectAssemblyName);
|
||||
|
||||
if (msbuildProject.HasUnsavedChanges)
|
||||
{
|
||||
|
|
@ -548,7 +567,7 @@ namespace GodotTools
|
|||
{
|
||||
settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudio}" +
|
||||
$",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
|
||||
$",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
|
||||
$",Visual Studio Code and VSCodium:{(int)ExternalEditorId.VsCode}" +
|
||||
$",JetBrains Rider and Fleet:{(int)ExternalEditorId.Rider}" +
|
||||
$",Custom:{(int)ExternalEditorId.CustomEditor}";
|
||||
}
|
||||
|
|
@ -556,14 +575,14 @@ namespace GodotTools
|
|||
{
|
||||
settingsHintStr += $",Visual Studio:{(int)ExternalEditorId.VisualStudioForMac}" +
|
||||
$",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
|
||||
$",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
|
||||
$",Visual Studio Code and VSCodium:{(int)ExternalEditorId.VsCode}" +
|
||||
$",JetBrains Rider and Fleet:{(int)ExternalEditorId.Rider}" +
|
||||
$",Custom:{(int)ExternalEditorId.CustomEditor}";
|
||||
}
|
||||
else if (OS.IsUnixLike)
|
||||
{
|
||||
settingsHintStr += $",MonoDevelop:{(int)ExternalEditorId.MonoDevelop}" +
|
||||
$",Visual Studio Code:{(int)ExternalEditorId.VsCode}" +
|
||||
$",Visual Studio Code and VSCodium:{(int)ExternalEditorId.VsCode}" +
|
||||
$",JetBrains Rider and Fleet:{(int)ExternalEditorId.Rider}" +
|
||||
$",Custom:{(int)ExternalEditorId.CustomEditor}";
|
||||
}
|
||||
|
|
@ -700,6 +719,23 @@ namespace GodotTools
|
|||
private static IntPtr InternalCreateInstance(IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
|
||||
{
|
||||
Internal.Initialize(unmanagedCallbacks, unmanagedCallbacksSize);
|
||||
|
||||
var populateConstructorMethod =
|
||||
AppDomain.CurrentDomain
|
||||
.GetAssemblies()
|
||||
.First(x => x.GetName().Name == "GodotSharpEditor")
|
||||
.GetType("Godot.EditorConstructors")?
|
||||
.GetMethod("AddEditorConstructors",
|
||||
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
if (populateConstructorMethod == null)
|
||||
{
|
||||
throw new MissingMethodException("Godot.EditorConstructors",
|
||||
"AddEditorConstructors");
|
||||
}
|
||||
|
||||
populateConstructorMethod.Invoke(null, null);
|
||||
|
||||
return new GodotSharpEditor().NativeInstance;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{27B00618-A6F2-4828-B922-05CAEB08C286}</ProjectGuid>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>12</LangVersion>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<LangVersion>10</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<!-- The Godot editor uses the Debug Godot API assemblies -->
|
||||
<GodotApiConfiguration>Debug</GodotApiConfiguration>
|
||||
|
|
@ -13,13 +14,16 @@
|
|||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Needed for our source generators to work despite this not being a Godot game project -->
|
||||
<PropertyGroup>
|
||||
<IsGodotToolsProject>true</IsGodotToolsProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<CompilerVisibleProperty Include="IsGodotToolsProject" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" Exists('$(GodotApiAssembliesDir)/GodotSharp.dll') ">
|
||||
<!-- The project is part of the Godot source tree -->
|
||||
<!-- Use the Godot source tree output folder instead of '$(ProjectDir)/bin' -->
|
||||
|
|
@ -27,6 +31,7 @@
|
|||
<!-- Must not append '$(TargetFramework)' to the output path in this case -->
|
||||
<AppendTargetFrameworkToOutputPath>False</AppendTargetFrameworkToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3.0" ExcludeAssets="runtime" PrivateAssets="all" />
|
||||
<PackageReference Include="JetBrains.Rider.PathLocator" Version="1.0.9" />
|
||||
|
|
@ -41,14 +46,17 @@
|
|||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Godot.NET.Sdk\Godot.SourceGenerators\Godot.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\..\..\glue\GodotSharp\Godot.SourceGenerators.Internal\Godot.SourceGenerators.Internal.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GodotTools.BuildLogger\GodotTools.BuildLogger.csproj" />
|
||||
<ProjectReference Include="..\GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj" />
|
||||
<ProjectReference Include="..\GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj" />
|
||||
<ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,13 @@ namespace GodotTools.Internals
|
|||
return godot_icall_Internal_IsMacOSAppBundleInstalled(bundleIdIn);
|
||||
}
|
||||
|
||||
public static bool LipOCreateFile(string outputPath, string[] files)
|
||||
{
|
||||
using godot_string outputPathIn = Marshaling.ConvertStringToNative(outputPath);
|
||||
using godot_packed_string_array filesIn = Marshaling.ConvertSystemArrayToNativePackedStringArray(files);
|
||||
return godot_icall_Internal_LipOCreateFile(outputPathIn, filesIn);
|
||||
}
|
||||
|
||||
public static bool GodotIs32Bits() => godot_icall_Internal_GodotIs32Bits();
|
||||
|
||||
public static bool GodotIsRealTDouble() => godot_icall_Internal_GodotIsRealTDouble();
|
||||
|
|
@ -121,6 +128,8 @@ namespace GodotTools.Internals
|
|||
|
||||
private static partial bool godot_icall_Internal_IsMacOSAppBundleInstalled(in godot_string bundleId);
|
||||
|
||||
private static partial bool godot_icall_Internal_LipOCreateFile(in godot_string outputPath, in godot_packed_string_array files);
|
||||
|
||||
private static partial bool godot_icall_Internal_GodotIs32Bits();
|
||||
|
||||
private static partial bool godot_icall_Internal_GodotIsRealTDouble();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue