using System; using System.CodeDom.Compiler; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading; using BITKit.Mod; #if UNITY_5_3_OR_NEWER using System.Collections; using BITKit.UX; using UnityEngine; using UnityEngine.Rendering; using static BITKit.Mod.DotNetSdkRoslynService; #endif #if UNITY_EDITOR using UnityEditor; #endif namespace BITKit { public class BITSharp { #if UNITY_5_3_OR_NEWER [RuntimeInitializeOnLoadMethod] private static void Reload() { ReferencedAssemblies.Clear(); Dictionary.Clear(); assemblies = null; } #endif public static readonly List ReferencedAssemblies = new(); private static readonly ConcurrentDictionary Dictionary = new(); private static Assembly[] assemblies; public static bool TryGetTypeFromFullName(string fullClassName, out Type type) { type = GetTypeFromFullName(fullClassName); return type is not null ? true : false; } public static Type GetTypeFromFullName(string fullClassName) { return Dictionary.GetOrAdd(fullClassName, SearchType); } private static Type SearchType(string fullName) { if (string.IsNullOrWhiteSpace(fullName)) { throw new ArgumentException("fullName is null or empty", nameof(fullName)); } assemblies ??= AppDomain.CurrentDomain.GetAssemblies(); return assemblies.Select(assembly => assembly.GetType(fullName, false)).FirstOrDefault(type => type is not null); } #if UNITY_5_3_OR_NEWER public static Assembly Compile(params string[] codes) { var outputPath = PathHelper.GetTempFilePath(); //DI.TryGet(out var waiting); //todo IUXWaiting waiting = null; var handle = waiting?.Get(); handle?.SetMessage("正在编译"); try { if (Installed is false) { throw new FileNotFoundException($"未从当前路径找到Roslyn:\n{CSCPath}"); } var argumentBuilder = new StringBuilder(); var tempList = new List { outputPath }; foreach (var code in codes) { var temp = PathHelper.GetTempFilePath(); File.WriteAllText(temp,code); argumentBuilder.Append(" "); argumentBuilder.Append(temp); tempList.Add(temp); } argumentBuilder.Append(" -target:library"); argumentBuilder.Append(" /unsafe"); foreach (var x in ReferencedAssemblies) { argumentBuilder.Append(" "); argumentBuilder.Append("-r:"); argumentBuilder.Append(x); //argumentBuilder.Append(Path.Combine(dllPath, x)); } argumentBuilder.Append(" "); argumentBuilder.Append($"-out:{outputPath}"); BIT4Log.Log("已创建编译参数:"); BIT4Log.Log(argumentBuilder.ToString()); BIT4Log.Log($"dotnet {CSCPath} {argumentBuilder}"); //Original // var StartInfo = new ProcessStartInfo // { // //FileName = MCSPath, // FileName = "dotnet", // Arguments =$"{CSCPath} {argumentBuilder}" , // UseShellExecute = true, // CreateNoWindow = false, // }; var StartInfo = new ProcessStartInfo { //FileName = MCSPath, FileName = "dotnet", Arguments =$"{CSCPath} {argumentBuilder}" , UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true, StandardErrorEncoding = System.Text.Encoding.GetEncoding("gb2312"), StandardInputEncoding = System.Text.Encoding.GetEncoding("gb2312"), StandardOutputEncoding = System.Text.Encoding.GetEncoding("gb2312"), }; var process = new Process() { StartInfo = StartInfo, }; var reportBuilder = new StringBuilder(); process.OutputDataReceived += (sender, args) => { //BIT4Log.Log(args.Data); reportBuilder.AppendLine(args.Data); }; process.ErrorDataReceived += (sender, args) => { //BIT4Log.Warning(args.Data); reportBuilder.AppendLine($"{args.Data}"); }; process.Start(); BIT4Log.Log("已启动"); process.BeginErrorReadLine(); process.BeginOutputReadLine(); while (process.HasExited is false) { Thread.Sleep(100); if (BITApp.CancellationToken.IsCancellationRequested) throw new OperationCanceledException("程序已退出,取消编译"); } var bytes = File.ReadAllBytes(outputPath); if(process.ExitCode is not 0) { BIT4Log.LogException(new Exception($"编译失败:{process.ExitCode}")); } else { foreach (var x in tempList) { File.Delete(x); } } BIT4Log.Log(reportBuilder); waiting?.Release(handle); return Assembly.Load(bytes); } catch (Exception e) { waiting?.Release(handle); throw new Exception($"编译失败:{e}"); } // var codeProvider = new CSharpCodeProvider(); // var parameters = new CompilerParameters // { // GenerateInMemory = true, // CompilerOptions = "/unsafe", // OutputAssembly = outputPath, // }; // parameters.ReferencedAssemblies.Add("System.dll"); // foreach (var x in ReferencedAssemblies) // { // parameters.ReferencedAssemblies.Add(x); // BIT4Log.Log($"添加引用:"); // BIT4Log.Log(x); // } // // BIT4Log.Log($"程序集输出路径:{outputPath}"); // // var results = codeProvider.CompileAssemblyFromSource(parameters, codes); // // if (results.Errors.Count <= 0) // { // BIT4Log.Log($"编译成功:{results.CompiledAssembly.FullName}"); // // codeProvider.Dispose(); // return results.CompiledAssembly; // } // // foreach (CompilerError error in results.Errors) // { // var sb = new StringBuilder(); // sb.AppendLine(error.FileName); // sb.AppendLine($"Error ({error.ErrorNumber}): {error.ErrorText}"); // sb.AppendLine($"Line: {error.Line}, Column: {error.Column}"); // sb.AppendLine($"Is Warning: {error.IsWarning}"); // BIT4Log.LogException(new Exception(sb.ToString())); // } // // throw new Exception("编译失败"); } #endif } }