Files
BusyRabbit/Plugins/UnrealSharp/Managed/Shared/DotNetUtilities.cs
wyatt 648386cd73 Lua向C#逻辑迁移 一期 #13
将整个插件代码上传
2025-10-26 21:48:39 +08:00

253 lines
6.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Text;
namespace UnrealSharp.Shared;
public static class DotNetUtilities
{
public const string DOTNET_MAJOR_VERSION = "9.0";
public const string DOTNET_MAJOR_VERSION_DISPLAY = "net" + DOTNET_MAJOR_VERSION;
public static string FindDotNetExecutable()
{
const string DOTNET_WIN = "dotnet.exe";
const string DOTNET_UNIX = "dotnet";
var dotnetExe = OperatingSystem.IsWindows() ? DOTNET_WIN : DOTNET_UNIX;
var pathVariable = Environment.GetEnvironmentVariable("PATH");
if (pathVariable == null)
{
throw new Exception($"Couldn't find {dotnetExe}!");
}
var paths = pathVariable.Split(Path.PathSeparator);
foreach (var path in paths)
{
// This is a hack to avoid using the dotnet.exe from the Unreal Engine installation directory.
// Can't use the dotnet.exe from the Unreal Engine installation directory because it's .NET 6.0
if (!path.Contains(@"\dotnet\"))
{
continue;
}
var dotnetExePath = Path.Combine(path, dotnetExe);
if (File.Exists(dotnetExePath))
{
return dotnetExePath;
}
}
if ( OperatingSystem.IsMacOS() ) {
if ( File.Exists( "/usr/local/share/dotnet/dotnet" ) ) {
return "/usr/local/share/dotnet/dotnet";
}
if ( File.Exists( "/opt/homebrew/bin/dotnet" ) ) {
return "/opt/homebrew/bin/dotnet";
}
}
throw new Exception($"Couldn't find {dotnetExe} in PATH!");
}
public static string GetLatestDotNetSdkPath()
{
string dotNetExecutable = FindDotNetExecutable();
string dotNetExecutableDirectory = Path.GetDirectoryName(dotNetExecutable)!;
string dotNetSdkDirectory = Path.Combine(dotNetExecutableDirectory!, "sdk");
string[] folderPaths = Directory.GetDirectories(dotNetSdkDirectory);
string highestVersion = "0.0.0";
foreach (string folderPath in folderPaths)
{
string folderName = Path.GetFileName(folderPath);
if (string.IsNullOrEmpty(folderName) || !char.IsDigit(folderName[0]))
{
continue;
}
if (string.Compare(folderName, highestVersion, StringComparison.Ordinal) > 0)
{
highestVersion = folderName;
}
}
if (highestVersion == "0.0.0")
{
throw new Exception("Failed to find the latest .NET SDK version.");
}
if (!highestVersion.StartsWith(DOTNET_MAJOR_VERSION))
{
throw new Exception($"Failed to find the latest .NET SDK version. Expected version to start with {DOTNET_MAJOR_VERSION} but found: {highestVersion}");
}
return Path.Combine(dotNetSdkDirectory, highestVersion);
}
public static void BuildSolution(string projectRootDirectory, string managedBinariesPath)
{
if (!Directory.Exists(projectRootDirectory))
{
throw new Exception($"Couldn't find project root directory: {projectRootDirectory}");
}
if (!Directory.Exists(managedBinariesPath))
{
Directory.CreateDirectory(managedBinariesPath);
}
Collection<string> arguments = new Collection<string>
{
"publish",
$"-p:PublishDir=\"{managedBinariesPath}\""
};
InvokeDotNet(arguments, projectRootDirectory);
}
public static bool InvokeDotNet(Collection<string> arguments, string? workingDirectory = null)
{
string dotnetPath = FindDotNetExecutable();
var startInfo = new ProcessStartInfo
{
FileName = dotnetPath,
RedirectStandardOutput = true,
RedirectStandardError = true
};
foreach (string argument in arguments)
{
startInfo.ArgumentList.Add(argument);
}
if (workingDirectory != null)
{
startInfo.WorkingDirectory = workingDirectory;
}
// Set the MSBuild environment variables to the latest .NET SDK that U# supports.
// Otherwise, we'll use the .NET SDK that comes with the Unreal Engine.
{
string latestDotNetSdkPath = GetLatestDotNetSdkPath();
startInfo.Environment["MSBuildExtensionsPath"] = latestDotNetSdkPath;
startInfo.Environment["MSBUILD_EXE_PATH"] = $@"{latestDotNetSdkPath}\MSBuild.dll";
startInfo.Environment["MSBuildSDKsPath"] = $@"{latestDotNetSdkPath}\Sdks";
}
using Process process = new Process();
process.StartInfo = startInfo;
try
{
StringBuilder outputBuilder = new StringBuilder();
process.OutputDataReceived += (sender, e) =>
{
if (e.Data != null)
{
outputBuilder.AppendLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data != null)
{
outputBuilder.AppendLine(e.Data);
}
};
if (!process.Start())
{
throw new Exception("Failed to start process");
}
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
if (process.ExitCode != 0)
{
string errorMessage = outputBuilder.ToString();
if (string.IsNullOrEmpty(errorMessage))
{
errorMessage = "Process exited with non-zero exit code but no output was captured.";
}
throw new Exception($"Process failed with exit code {process.ExitCode}: {errorMessage}");
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
return false;
}
return true;
}
public static bool InvokeUSharpBuildTool(string action,
string managedBinariesPath,
string projectName,
string pluginDirectory,
string projectDirectory,
string engineDirectory,
IEnumerable<KeyValuePair<string, string>>? additionalArguments = null)
{
string dotNetExe = FindDotNetExecutable();
string unrealSharpBuildToolPath = Path.Combine(managedBinariesPath, "UnrealSharpBuildTool.dll");
if (!File.Exists(unrealSharpBuildToolPath))
{
throw new Exception($"Failed to find UnrealSharpBuildTool.dll at: {unrealSharpBuildToolPath}");
}
Collection<string> arguments = new Collection<string>
{
unrealSharpBuildToolPath,
"--Action",
action,
"--EngineDirectory",
$"{engineDirectory}",
"--ProjectDirectory",
$"{projectDirectory}",
"--ProjectName",
projectName,
"--PluginDirectory",
$"{pluginDirectory}",
"--DotNetPath",
$"{dotNetExe}"
};
if (additionalArguments != null)
{
arguments.Add("--AdditionalArgs");
foreach (KeyValuePair<string, string> argument in additionalArguments)
{
arguments.Add($"{argument.Key}={argument.Value}");
}
}
return InvokeDotNet(arguments);
}
}