From ac091708560afe99e156d74a4df282d7ad71da62 Mon Sep 17 00:00:00 2001 From: wuwenbo Date: Thu, 11 Jun 2026 02:08:26 +0800 Subject: [PATCH] Add migration smoke build command --- .../HybridCLRGenerate/AOTGenericReferences.cs | 46 --- .../Editor/TH1MigrationCommandLine.cs | 377 ++++++++++++++++++ .../Editor/TH1MigrationCommandLine.cs.meta | 3 + 3 files changed, 380 insertions(+), 46 deletions(-) create mode 100644 Unity/Assets/Scripts/TH1_Logic/Editor/TH1MigrationCommandLine.cs create mode 100644 Unity/Assets/Scripts/TH1_Logic/Editor/TH1MigrationCommandLine.cs.meta diff --git a/Unity/Assets/HybridCLRGenerate/AOTGenericReferences.cs b/Unity/Assets/HybridCLRGenerate/AOTGenericReferences.cs index 8a423a9b9..6ae2f9113 100644 --- a/Unity/Assets/HybridCLRGenerate/AOTGenericReferences.cs +++ b/Unity/Assets/HybridCLRGenerate/AOTGenericReferences.cs @@ -103,7 +103,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Action // System.Action // System.Action - // System.Action // System.Action // System.Action // System.Action @@ -240,7 +239,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Buffers.ArrayPool // System.Buffers.ConfigurableArrayPool.Bucket // System.Buffers.ConfigurableArrayPool - // System.Buffers.IBufferWriter // System.Buffers.MemoryManager // System.Buffers.MemoryManager // System.Buffers.TlsOverPerCoreLockedStacksArrayPool.LockedStack @@ -262,7 +260,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.ArraySortHelper // System.Collections.Generic.ArraySortHelper // System.Collections.Generic.ArraySortHelper - // System.Collections.Generic.ArraySortHelper // System.Collections.Generic.ArraySortHelper // System.Collections.Generic.ArraySortHelper // System.Collections.Generic.ArraySortHelper @@ -305,7 +302,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.Comparer // System.Collections.Generic.Comparer // System.Collections.Generic.Comparer - // System.Collections.Generic.Comparer // System.Collections.Generic.Comparer // System.Collections.Generic.Comparer // System.Collections.Generic.Comparer @@ -349,7 +345,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.ComparisonComparer // System.Collections.Generic.ComparisonComparer // System.Collections.Generic.ComparisonComparer - // System.Collections.Generic.ComparisonComparer // System.Collections.Generic.ComparisonComparer // System.Collections.Generic.ComparisonComparer // System.Collections.Generic.ComparisonComparer @@ -408,7 +403,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.Dictionary.Enumerator // System.Collections.Generic.Dictionary.Enumerator // System.Collections.Generic.Dictionary.Enumerator - // System.Collections.Generic.Dictionary.Enumerator // System.Collections.Generic.Dictionary.Enumerator // System.Collections.Generic.Dictionary.Enumerator // System.Collections.Generic.Dictionary.Enumerator @@ -437,7 +431,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.Dictionary.KeyCollection.Enumerator // System.Collections.Generic.Dictionary.KeyCollection.Enumerator // System.Collections.Generic.Dictionary.KeyCollection.Enumerator - // System.Collections.Generic.Dictionary.KeyCollection.Enumerator // System.Collections.Generic.Dictionary.KeyCollection.Enumerator // System.Collections.Generic.Dictionary.KeyCollection.Enumerator // System.Collections.Generic.Dictionary.KeyCollection.Enumerator @@ -466,7 +459,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.Dictionary.KeyCollection // System.Collections.Generic.Dictionary.KeyCollection // System.Collections.Generic.Dictionary.KeyCollection - // System.Collections.Generic.Dictionary.KeyCollection // System.Collections.Generic.Dictionary.KeyCollection // System.Collections.Generic.Dictionary.KeyCollection // System.Collections.Generic.Dictionary.KeyCollection @@ -495,7 +487,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.Dictionary.ValueCollection.Enumerator // System.Collections.Generic.Dictionary.ValueCollection.Enumerator // System.Collections.Generic.Dictionary.ValueCollection.Enumerator - // System.Collections.Generic.Dictionary.ValueCollection.Enumerator // System.Collections.Generic.Dictionary.ValueCollection.Enumerator // System.Collections.Generic.Dictionary.ValueCollection.Enumerator // System.Collections.Generic.Dictionary.ValueCollection.Enumerator @@ -524,7 +515,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.Dictionary.ValueCollection // System.Collections.Generic.Dictionary.ValueCollection // System.Collections.Generic.Dictionary.ValueCollection - // System.Collections.Generic.Dictionary.ValueCollection // System.Collections.Generic.Dictionary.ValueCollection // System.Collections.Generic.Dictionary.ValueCollection // System.Collections.Generic.Dictionary.ValueCollection @@ -553,7 +543,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.Dictionary // System.Collections.Generic.Dictionary // System.Collections.Generic.Dictionary - // System.Collections.Generic.Dictionary // System.Collections.Generic.Dictionary // System.Collections.Generic.Dictionary // System.Collections.Generic.Dictionary @@ -563,7 +552,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.Dictionary // System.Collections.Generic.EqualityComparer // System.Collections.Generic.EqualityComparer - // System.Collections.Generic.EqualityComparer // System.Collections.Generic.EqualityComparer // System.Collections.Generic.EqualityComparer // System.Collections.Generic.EqualityComparer @@ -611,7 +599,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.ICollection // System.Collections.Generic.ICollection // System.Collections.Generic.ICollection - // System.Collections.Generic.ICollection // System.Collections.Generic.ICollection // System.Collections.Generic.ICollection // System.Collections.Generic.ICollection @@ -638,7 +625,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.ICollection> // System.Collections.Generic.ICollection> // System.Collections.Generic.ICollection> - // System.Collections.Generic.ICollection> // System.Collections.Generic.ICollection> // System.Collections.Generic.ICollection> // System.Collections.Generic.ICollection> @@ -682,7 +668,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.IComparer // System.Collections.Generic.IComparer // System.Collections.Generic.IComparer - // System.Collections.Generic.IComparer // System.Collections.Generic.IComparer // System.Collections.Generic.IComparer // System.Collections.Generic.IComparer @@ -727,7 +712,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.IEnumerable // System.Collections.Generic.IEnumerable // System.Collections.Generic.IEnumerable - // System.Collections.Generic.IEnumerable // System.Collections.Generic.IEnumerable // System.Collections.Generic.IEnumerable // System.Collections.Generic.IEnumerable @@ -754,7 +738,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.IEnumerable> // System.Collections.Generic.IEnumerable> // System.Collections.Generic.IEnumerable> - // System.Collections.Generic.IEnumerable> // System.Collections.Generic.IEnumerable> // System.Collections.Generic.IEnumerable> // System.Collections.Generic.IEnumerable> @@ -798,7 +781,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.IEnumerator // System.Collections.Generic.IEnumerator // System.Collections.Generic.IEnumerator - // System.Collections.Generic.IEnumerator // System.Collections.Generic.IEnumerator // System.Collections.Generic.IEnumerator // System.Collections.Generic.IEnumerator @@ -825,7 +807,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.IEnumerator> // System.Collections.Generic.IEnumerator> // System.Collections.Generic.IEnumerator> - // System.Collections.Generic.IEnumerator> // System.Collections.Generic.IEnumerator> // System.Collections.Generic.IEnumerator> // System.Collections.Generic.IEnumerator> @@ -882,7 +863,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.IList // System.Collections.Generic.IList // System.Collections.Generic.IList - // System.Collections.Generic.IList // System.Collections.Generic.IList // System.Collections.Generic.IList // System.Collections.Generic.IList @@ -952,7 +932,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.KeyValuePair // System.Collections.Generic.KeyValuePair // System.Collections.Generic.KeyValuePair - // System.Collections.Generic.KeyValuePair // System.Collections.Generic.KeyValuePair // System.Collections.Generic.KeyValuePair // System.Collections.Generic.KeyValuePair @@ -969,7 +948,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.List.Enumerator // System.Collections.Generic.List.Enumerator // System.Collections.Generic.List.Enumerator - // System.Collections.Generic.List.Enumerator // System.Collections.Generic.List.Enumerator // System.Collections.Generic.List.Enumerator // System.Collections.Generic.List.Enumerator @@ -1012,7 +990,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.List // System.Collections.Generic.List // System.Collections.Generic.List - // System.Collections.Generic.List // System.Collections.Generic.List // System.Collections.Generic.List // System.Collections.Generic.List @@ -1055,7 +1032,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.ObjectComparer // System.Collections.Generic.ObjectComparer // System.Collections.Generic.ObjectComparer - // System.Collections.Generic.ObjectComparer // System.Collections.Generic.ObjectComparer // System.Collections.Generic.ObjectComparer // System.Collections.Generic.ObjectComparer @@ -1095,7 +1071,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.Generic.ObjectComparer // System.Collections.Generic.ObjectEqualityComparer // System.Collections.Generic.ObjectEqualityComparer - // System.Collections.Generic.ObjectEqualityComparer // System.Collections.Generic.ObjectEqualityComparer // System.Collections.Generic.ObjectEqualityComparer // System.Collections.Generic.ObjectEqualityComparer @@ -1154,7 +1129,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Collections.ObjectModel.ReadOnlyCollection // System.Collections.ObjectModel.ReadOnlyCollection // System.Collections.ObjectModel.ReadOnlyCollection - // System.Collections.ObjectModel.ReadOnlyCollection // System.Collections.ObjectModel.ReadOnlyCollection // System.Collections.ObjectModel.ReadOnlyCollection // System.Collections.ObjectModel.ReadOnlyCollection @@ -1197,7 +1171,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Comparison // System.Comparison // System.Comparison - // System.Comparison // System.Comparison // System.Comparison // System.Comparison @@ -1313,7 +1286,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Predicate // System.Predicate // System.Predicate - // System.Predicate // System.Predicate // System.Predicate // System.Predicate @@ -1458,9 +1430,7 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // byte& MemoryPack.Internal.MemoryMarshalEx.GetArrayDataReference(byte[]) // int& MemoryPack.Internal.MemoryMarshalEx.GetArrayDataReference(int[]) // object& MemoryPack.Internal.MemoryMarshalEx.GetArrayDataReference(object[]) - // MemoryPack.MemoryPackFormatter MemoryPack.MemoryPackFormatterProvider.GetFormatter() // MemoryPack.MemoryPackFormatter MemoryPack.MemoryPackFormatterProvider.GetFormatter() - // MemoryPack.MemoryPackFormatter MemoryPack.MemoryPackFormatterProvider.GetFormatter() // bool MemoryPack.MemoryPackFormatterProvider.IsRegistered() // bool MemoryPack.MemoryPackFormatterProvider.IsRegistered() // bool MemoryPack.MemoryPackFormatterProvider.IsRegistered() @@ -1559,19 +1529,10 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // object MemoryPack.MemoryPackReader.ReadValue() // int MemoryPack.MemoryPackSerializer.Deserialize(System.ReadOnlySpan,object&,MemoryPack.MemoryPackSerializerOptions) // object MemoryPack.MemoryPackSerializer.Deserialize(System.ReadOnlySpan,MemoryPack.MemoryPackSerializerOptions) - // System.Void MemoryPack.MemoryPackSerializer.Serialize(MemoryPack.MemoryPackWriter&,int&) - // System.Void MemoryPack.MemoryPackSerializer.Serialize(MemoryPack.MemoryPackWriter&,object&) - // System.Void MemoryPack.MemoryPackSerializer.Serialize(System.Buffers.IBufferWriter&,object&,MemoryPack.MemoryPackSerializerOptions) - // System.Void MemoryPack.MemoryPackSerializer.Serialize(MemoryPack.MemoryPackWriter&,uint&) - // byte[] MemoryPack.MemoryPackSerializer.Serialize(int&,MemoryPack.MemoryPackSerializerOptions) - // byte[] MemoryPack.MemoryPackSerializer.Serialize(object&,MemoryPack.MemoryPackSerializerOptions) - // byte[] MemoryPack.MemoryPackSerializer.Serialize(uint&,MemoryPack.MemoryPackSerializerOptions) // System.Void MemoryPack.MemoryPackWriter.DangerousWriteUnmanagedArray(byte[]) // System.Void MemoryPack.MemoryPackWriter.DangerousWriteUnmanagedArray(int[]) // System.Void MemoryPack.MemoryPackWriter.DangerousWriteUnmanagedArray(object[]) - // MemoryPack.IMemoryPackFormatter MemoryPack.MemoryPackWriter.GetFormatter() // MemoryPack.IMemoryPackFormatter MemoryPack.MemoryPackWriter.GetFormatter() - // MemoryPack.IMemoryPackFormatter MemoryPack.MemoryPackWriter.GetFormatter() // System.Void MemoryPack.MemoryPackWriter.WriteArray(object[]) // System.Void MemoryPack.MemoryPackWriter.WritePackable(object&) // System.Void MemoryPack.MemoryPackWriter.WriteUnmanaged(byte&,RuntimeData.UnitFullType&,int&,int&,uint&,int&,int&,int&,RuntimeData.UnitFullType&,RuntimeData.UnitFullType&,int&,int&,uint&,float&,RuntimeData.UnitFullType&) @@ -1653,9 +1614,7 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Void MemoryPack.MemoryPackWriter.WriteUnmanagedWithObjectHeader(byte,ulong&,uint&,uint&,uint&,byte&,int&,int&,byte&,byte&,byte&) // System.Void MemoryPack.MemoryPackWriter.WriteUnmanagedWithObjectHeader(byte,ulong&,ulong&) // System.Void MemoryPack.MemoryPackWriter.WriteUnmanagedWithObjectHeader(byte,ulong&) - // System.Void MemoryPack.MemoryPackWriter.WriteValue(int&) // System.Void MemoryPack.MemoryPackWriter.WriteValue(object&) - // System.Void MemoryPack.MemoryPackWriter.WriteValue(uint&) // Microsoft.ML.OnnxRuntime.Tensors.Tensor Microsoft.ML.OnnxRuntime.NamedOnnxValue.AsTensor() // Microsoft.ML.OnnxRuntime.NamedOnnxValue Microsoft.ML.OnnxRuntime.NamedOnnxValue.CreateFromTensor(string,Microsoft.ML.OnnxRuntime.Tensors.Tensor) // NodeCanvas.Framework.Variable NodeCanvas.Framework.IBlackboardExtensions.GetVariable(NodeCanvas.Framework.IBlackboard,string) @@ -1740,9 +1699,7 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Void System.Runtime.CompilerServices.AsyncTaskMethodBuilder>.Start(object&) // System.Void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start(object&) // System.Void System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start(object&) - // bool System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences() // bool System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences() - // bool System.Runtime.CompilerServices.RuntimeHelpers.IsReferenceOrContainsReferences() // byte& System.Runtime.CompilerServices.Unsafe.Add(byte&,int) // byte& System.Runtime.CompilerServices.Unsafe.As(byte&) // byte& System.Runtime.CompilerServices.Unsafe.As(int&) @@ -1750,9 +1707,7 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // object& System.Runtime.CompilerServices.Unsafe.As(object&) // object& System.Runtime.CompilerServices.Unsafe.As(object&) // System.Void* System.Runtime.CompilerServices.Unsafe.AsPointer(object&) - // int& System.Runtime.CompilerServices.Unsafe.AsRef(int&) // object& System.Runtime.CompilerServices.Unsafe.AsRef(object&) - // uint& System.Runtime.CompilerServices.Unsafe.AsRef(uint&) // Empire System.Runtime.CompilerServices.Unsafe.ReadUnaligned(byte&) // RuntimeData.UnitFullType System.Runtime.CompilerServices.Unsafe.ReadUnaligned(byte&) // byte System.Runtime.CompilerServices.Unsafe.ReadUnaligned(byte&) @@ -1777,7 +1732,6 @@ public class AOTGenericReferences : UnityEngine.MonoBehaviour // System.Void System.Runtime.CompilerServices.Unsafe.WriteUnaligned(byte&,float) // System.Void System.Runtime.CompilerServices.Unsafe.WriteUnaligned(byte&,int) // System.Void System.Runtime.CompilerServices.Unsafe.WriteUnaligned(byte&,long) - // System.Void System.Runtime.CompilerServices.Unsafe.WriteUnaligned(byte&,object) // System.Void System.Runtime.CompilerServices.Unsafe.WriteUnaligned(byte&,uint) // System.Void System.Runtime.CompilerServices.Unsafe.WriteUnaligned(byte&,ulong) // Steamworks.SteamNetworkingMessage_t System.Runtime.InteropServices.Marshal.PtrToStructure(System.IntPtr) diff --git a/Unity/Assets/Scripts/TH1_Logic/Editor/TH1MigrationCommandLine.cs b/Unity/Assets/Scripts/TH1_Logic/Editor/TH1MigrationCommandLine.cs new file mode 100644 index 000000000..69afe6140 --- /dev/null +++ b/Unity/Assets/Scripts/TH1_Logic/Editor/TH1MigrationCommandLine.cs @@ -0,0 +1,377 @@ +using System; +using System.IO; +using System.Linq; +using TH1_Logic.Editor.HybridCLR; +using TH1_Logic.Editor.YooAssetTools; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEngine; +using DiagnosticsProcess = System.Diagnostics.Process; +using DiagnosticsProcessStartInfo = System.Diagnostics.ProcessStartInfo; + +namespace TH1_Logic.Editor +{ + public static class TH1MigrationCommandLine + { + private const string BuildDirArg = "-th1SmokeBuildDir"; + private const string DefaultBuildSubDirectory = "TH1/CodexSmoke"; + private const string ExeName = "TOHOTOPIA.exe"; + + [MenuItem("Tools/TH1/iOS Migration/Command Line/Prepare And Build Windows Smoke")] + public static void PrepareAndBuildWindowsSmoke() + { + RunBatchAction(() => + { + ConfigureWindowsIl2CppSmokeSettings(); + PrepareCurrentPlatform(true); + + var exePath = BuildWindowsSmokePlayer(); + Debug.Log($"[TH1.Migration.CLI] Windows smoke build OK: {exePath}"); + }); + } + + [MenuItem("Tools/TH1/iOS Migration/Command Line/Prepare Current Platform")] + public static void PrepareCurrentPlatformMenu() + { + RunBatchAction(() => PrepareCurrentPlatform(true)); + } + + public static void PrepareCurrentPlatform(bool developmentBuild) + { + AssetDatabase.SaveAssets(); + + TH1HybridCLRBuildTools.ConfigureHotfixSettings(); + TH1YooAssetBuildTools.ConfigureDefaultPackageCollector(); + TH1HybridCLRBuildTools.GenerateAll(); + + if (!TH1HybridCLRBuildTools.BuildAndCopyHotfixArtifacts(developmentBuild)) + { + throw new BuildFailedException("[TH1.Migration.CLI] Build hotfix dll failed."); + } + + TH1YooAssetBuildTools.BuildBuiltinDefaultPackage(); + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + + var blockers = TH1MigrationBuildStatus.GetBuildBlockingMessages(EditorUserBuildSettings.activeBuildTarget); + if (blockers.Count > 0) + { + throw new BuildFailedException( + "[TH1.Migration.CLI] Build preparation still has blocking errors:\n" + + string.Join("\n", blockers)); + } + + Debug.Log("[TH1.Migration.CLI] Prepare current platform OK."); + } + + private static void ConfigureWindowsIl2CppSmokeSettings() + { + const BuildTargetGroup group = BuildTargetGroup.Standalone; + const BuildTarget target = BuildTarget.StandaloneWindows64; + + if (EditorUserBuildSettings.activeBuildTarget != target) + { + EditorUserBuildSettings.SwitchActiveBuildTarget(group, target); + } + + PlayerSettings.SetScriptingBackend(group, ScriptingImplementation.IL2CPP); + EditorUserBuildSettings.development = true; + EditorUserBuildSettings.allowDebugging = true; + PlayerSettings.usePlayerLog = true; + PlayerSettings.SetStackTraceLogType(LogType.Log, StackTraceLogType.ScriptOnly); + PlayerSettings.SetStackTraceLogType(LogType.Warning, StackTraceLogType.ScriptOnly); + PlayerSettings.SetStackTraceLogType(LogType.Error, StackTraceLogType.ScriptOnly); + PlayerSettings.SetStackTraceLogType(LogType.Assert, StackTraceLogType.ScriptOnly); + PlayerSettings.SetStackTraceLogType(LogType.Exception, StackTraceLogType.ScriptOnly); + + Debug.Log("[TH1.Migration.CLI] Configured Windows IL2CPP smoke build settings."); + } + + private static string BuildWindowsSmokePlayer() + { + var outputRoot = GetSmokeBuildDirectory(); + CleanSmokeBuildDirectory(outputRoot); + + var outputExe = Path.Combine(outputRoot, ExeName); + var scenes = EditorBuildSettings.scenes + .Where(scene => scene.enabled) + .Select(scene => scene.path) + .ToArray(); + + if (scenes.Length == 0) + { + throw new BuildFailedException("[TH1.Migration.CLI] No enabled scenes in EditorBuildSettings."); + } + + var options = new BuildPlayerOptions + { + scenes = scenes, + locationPathName = outputExe, + target = BuildTarget.StandaloneWindows64, + targetGroup = BuildTargetGroup.Standalone, + options = BuildOptions.Development | BuildOptions.AllowDebugging + }; + + var report = BuildPipeline.BuildPlayer(options); + var summary = report.summary; + if (summary.result != BuildResult.Succeeded) + { + throw new BuildFailedException( + $"[TH1.Migration.CLI] Build failed: {summary.result}, errors={summary.totalErrors}, warnings={summary.totalWarnings}"); + } + + var playerExe = FindPlayerExecutable(outputRoot, outputExe); + if (string.IsNullOrEmpty(playerExe)) + { + BuildExportedVisualStudioSolution(outputRoot); + playerExe = FindPlayerExecutable(outputRoot, outputExe); + } + + if (string.IsNullOrEmpty(playerExe)) + { + throw new BuildFailedException( + $"[TH1.Migration.CLI] Build succeeded but no runnable player exe was found under {outputRoot}."); + } + + return playerExe; + } + + private static string GetSmokeBuildDirectory() + { + var argValue = GetCommandLineValue(BuildDirArg); + if (!string.IsNullOrEmpty(argValue)) + { + return Path.GetFullPath(argValue); + } + + return Path.GetFullPath(Path.Combine(GetProjectRoot(), DefaultBuildSubDirectory)); + } + + private static string FindPlayerExecutable(string outputRoot, string expectedExe) + { + if (File.Exists(expectedExe)) return expectedExe; + if (!Directory.Exists(outputRoot)) return string.Empty; + + var exeFiles = Directory.GetFiles(outputRoot, "*.exe", SearchOption.AllDirectories) + .Where(path => + { + if (path.IndexOf("Il2CppOutputProject", StringComparison.OrdinalIgnoreCase) >= 0) return false; + var fileName = Path.GetFileName(path); + if (fileName.IndexOf("CrashHandler", StringComparison.OrdinalIgnoreCase) >= 0) return false; + if (fileName.Equals("il2cpp.exe", StringComparison.OrdinalIgnoreCase)) return false; + if (fileName.Equals("UnityLinker.exe", StringComparison.OrdinalIgnoreCase)) return false; + if (fileName.Equals("bee_backend.exe", StringComparison.OrdinalIgnoreCase)) return false; + if (fileName.Equals("Analytics.exe", StringComparison.OrdinalIgnoreCase)) return false; + if (fileName.Equals("createdump.exe", StringComparison.OrdinalIgnoreCase)) return false; + return true; + }) + .OrderBy(path => path.Length) + .ToArray(); + + return exeFiles.FirstOrDefault() ?? string.Empty; + } + + private static void BuildExportedVisualStudioSolution(string outputRoot) + { + var solutionPath = Directory.GetFiles(outputRoot, "*.sln", SearchOption.TopDirectoryOnly) + .OrderBy(path => path.Length) + .FirstOrDefault(); + if (string.IsNullOrEmpty(solutionPath)) + { + return; + } + + var msBuildPath = FindMSBuildPath(); + if (string.IsNullOrEmpty(msBuildPath)) + { + throw new BuildFailedException( + $"[TH1.Migration.CLI] Unity exported a Visual Studio solution but MSBuild was not found: {solutionPath}"); + } + + Debug.Log($"[TH1.Migration.CLI] Unity exported Visual Studio solution, building it with MSBuild: {solutionPath}"); + var windowsSdkVersion = FindLatestWindowsSdkVersion(); + var platformToolset = FindLatestPlatformToolset(msBuildPath); + var retargetArgs = string.Empty; + if (!string.IsNullOrEmpty(windowsSdkVersion)) + { + retargetArgs += $" /p:WindowsTargetPlatformVersion={windowsSdkVersion}"; + } + + if (!string.IsNullOrEmpty(platformToolset)) + { + retargetArgs += $" /p:PlatformToolset={platformToolset}"; + } + + RunProcess( + msBuildPath, + $"\"{solutionPath}\" /m /p:Configuration=Debug /p:Platform=x64{retargetArgs} /verbosity:minimal", + outputRoot); + } + + private static string FindMSBuildPath() + { + var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); + var vsWherePath = Path.Combine(programFilesX86, "Microsoft Visual Studio", "Installer", "vswhere.exe"); + if (File.Exists(vsWherePath)) + { + var output = RunProcess(vsWherePath, "-latest -products * -requires Microsoft.Component.MSBuild -find MSBuild\\**\\Bin\\MSBuild.exe", GetProjectRoot(), false); + var path = output + .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) + .FirstOrDefault(File.Exists); + if (!string.IsNullOrEmpty(path)) + { + return path; + } + } + + var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); + var candidates = new[] + { + Path.Combine(programFiles, "Microsoft Visual Studio", "2022", "Community", "MSBuild", "Current", "Bin", "MSBuild.exe"), + Path.Combine(programFiles, "Microsoft Visual Studio", "2022", "Professional", "MSBuild", "Current", "Bin", "MSBuild.exe"), + Path.Combine(programFiles, "Microsoft Visual Studio", "2022", "Enterprise", "MSBuild", "Current", "Bin", "MSBuild.exe"), + Path.Combine(programFilesX86, "Microsoft Visual Studio", "2022", "BuildTools", "MSBuild", "Current", "Bin", "MSBuild.exe") + }; + + return candidates.FirstOrDefault(File.Exists) ?? string.Empty; + } + + private static string FindLatestWindowsSdkVersion() + { + var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); + var sdkLibRoot = Path.Combine(programFilesX86, "Windows Kits", "10", "Lib"); + if (!Directory.Exists(sdkLibRoot)) + { + return string.Empty; + } + + return Directory.GetDirectories(sdkLibRoot) + .Select(Path.GetFileName) + .Where(name => Version.TryParse(name?.TrimEnd('.'), out _)) + .OrderByDescending(name => Version.Parse(name.TrimEnd('.'))) + .FirstOrDefault() ?? string.Empty; + } + + private static string FindLatestPlatformToolset(string msBuildPath) + { + var current = new FileInfo(msBuildPath).Directory; + while (current != null) + { + var toolsetRoot = Path.Combine(current.FullName, "Microsoft", "VC", "v170", "Platforms", "x64", "PlatformToolsets"); + if (Directory.Exists(toolsetRoot)) + { + return Directory.GetDirectories(toolsetRoot) + .Select(Path.GetFileName) + .Where(name => name != null && name.StartsWith("v", StringComparison.OrdinalIgnoreCase)) + .OrderByDescending(name => name) + .FirstOrDefault() ?? string.Empty; + } + + current = current.Parent; + } + + return string.Empty; + } + + private static string RunProcess(string fileName, string arguments, string workingDirectory, bool throwOnError = true) + { + var process = new DiagnosticsProcess + { + StartInfo = new DiagnosticsProcessStartInfo + { + FileName = fileName, + Arguments = arguments, + WorkingDirectory = workingDirectory, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true + } + }; + + process.Start(); + var output = process.StandardOutput.ReadToEnd(); + var error = process.StandardError.ReadToEnd(); + process.WaitForExit(); + + if (!string.IsNullOrWhiteSpace(output)) + { + Debug.Log(output); + } + + if (!string.IsNullOrWhiteSpace(error)) + { + Debug.LogWarning(error); + } + + if (throwOnError && process.ExitCode != 0) + { + throw new BuildFailedException( + $"[TH1.Migration.CLI] Process failed ({process.ExitCode}): {fileName} {arguments}\n{output}\n{error}"); + } + + return output; + } + + private static string GetCommandLineValue(string name) + { + var args = Environment.GetCommandLineArgs(); + for (var i = 0; i < args.Length - 1; i++) + { + if (string.Equals(args[i], name, StringComparison.OrdinalIgnoreCase)) + { + return args[i + 1]; + } + } + + return string.Empty; + } + + private static string GetProjectRoot() + { + return Directory.GetParent(Application.dataPath)?.FullName ?? Application.dataPath; + } + + private static void CleanSmokeBuildDirectory(string outputRoot) + { + var fullOutputRoot = Path.GetFullPath(outputRoot); + var defaultSafeRoot = Path.GetFullPath(Path.Combine(GetProjectRoot(), "TH1")); + if (!fullOutputRoot.StartsWith(defaultSafeRoot, StringComparison.OrdinalIgnoreCase) && + string.IsNullOrEmpty(GetCommandLineValue(BuildDirArg))) + { + throw new BuildFailedException($"[TH1.Migration.CLI] Refuse to clean unexpected smoke build dir: {fullOutputRoot}"); + } + + if (Directory.Exists(fullOutputRoot)) + { + Directory.Delete(fullOutputRoot, true); + } + + Directory.CreateDirectory(fullOutputRoot); + } + + private static void RunBatchAction(System.Action action) + { + try + { + action(); + if (Application.isBatchMode) + { + EditorApplication.Exit(0); + } + } + catch (Exception e) + { + Debug.LogError($"[TH1.Migration.CLI] Failed:\n{e}"); + if (Application.isBatchMode) + { + EditorApplication.Exit(1); + return; + } + + throw; + } + } + } +} diff --git a/Unity/Assets/Scripts/TH1_Logic/Editor/TH1MigrationCommandLine.cs.meta b/Unity/Assets/Scripts/TH1_Logic/Editor/TH1MigrationCommandLine.cs.meta new file mode 100644 index 000000000..9fc487200 --- /dev/null +++ b/Unity/Assets/Scripts/TH1_Logic/Editor/TH1MigrationCommandLine.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3ef088115a5f4492b90b43c79291c551 +timeCreated: 1781111040