using System; using System.CodeDom.Compiler; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading; using BITKit.Mod; using Microsoft.CSharp; #if UNITY_64 using static BITKit.Mod.MonoBleedingEdgeService; #endif namespace BITKit { public class BITSharp { 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) { assemblies = assemblies ?? AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { var type = assembly.GetType(fullName, false); if (type is not null) { return type; } else { continue; } } return null; } #if UNITY_64 public static Assembly Compile(params string[] codes) { var outputPath = PathHelper.GetTempFilePath(); try { if (MonoBleedingEdgeService.Installed is false) { throw new FileNotFoundException($"未从当前路径找到mcs:\n{MCSPath}"); } var argumentBuilder = new StringBuilder(); var dllPath = Assembly.GetExecutingAssembly().Location; 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(" "); argumentBuilder.Append("-target:library"); // foreach (var fileInfo in new FileInfo(Assembly.GetExecutingAssembly()!.Location!).Directory!.GetFiles()) // { // if(fileInfo.Extension is not ".dll")continue; // // argumentBuilder.Append(" "); // argumentBuilder.Append("-r:"); // argumentBuilder.Append(fileInfo.FullName); // } foreach (var x in ReferencedAssemblies) { argumentBuilder.Append(" "); argumentBuilder.Append("-r:"); argumentBuilder.Append(Path.Combine(dllPath, x)); } argumentBuilder.Append(" "); argumentBuilder.Append($"-out:{outputPath}"); BIT4Log.Log("已创建编译参数:"); BIT4Log.Log(argumentBuilder.ToString()); var StartInfo = new ProcessStartInfo { FileName = MCSPath, Arguments = argumentBuilder.ToString(), UseShellExecute = true, CreateNoWindow = false, }; var process = new Process() { StartInfo = StartInfo, }; process.OutputDataReceived += (sender, args) => { BIT4Log.Log(args.Data); }; process.ErrorDataReceived += (sender, args) => { BIT4Log.Warning(args.Data); }; //var exited=false; process.Start(); BIT4Log.Log("已启动"); process.WaitForExit(); // process.Exited += (sender, args) => // { // exited = true; // BIT4Log.Log("已退出"); // }; // BIT4Log.Log("完成"); // // while (exited is false && process.HasExited is false) // { // Thread.Sleep(100); // } var bytes = File.ReadAllBytes(outputPath); foreach (var x in tempList) { File.Delete(x); } return Assembly.Load(bytes); } catch (Exception e) { throw new Exception($"编译失败:{e}"); } // if (BITAppForUnity.IsEditor) // { // // } // else 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 } }