private static bool Build(BuildingMod mod, IBuildStatus status) { byte[] winDLL = null; byte[] monoDLL = null; byte[] winPDB = null; if (mod.properties.noCompile) { winDLL = monoDLL = ReadIfExists(Path.Combine(mod.path, "All.dll")); winPDB = ReadIfExists(Path.Combine(mod.path, "All.pdb")); if (winDLL == null) { winDLL = ReadIfExists(Path.Combine(mod.path, "Windows.dll")); monoDLL = ReadIfExists(Path.Combine(mod.path, "Mono.dll")); winPDB = ReadIfExists(Path.Combine(mod.path, "Windows.pdb")); } if (winDLL == null || monoDLL == null) { ErrorLogger.LogDllBuildError(mod.path); return(false); } } else { var refMods = FindReferencedMods(mod.properties); if (refMods == null) { return(false); } if (Program.LaunchParameters.ContainsKey("-eac")) { if (!windows) { ErrorLogger.LogBuildError("Edit and continue is only supported on windows"); return(false); } try { status.SetStatus("Loading pre-compiled Windows.dll with edit and continue support"); var winPath = Program.LaunchParameters["-eac"]; var pdbPath = Path.ChangeExtension(winPath, "pdb"); winDLL = File.ReadAllBytes(winPath); winPDB = File.ReadAllBytes(pdbPath); mod.properties.editAndContinue = true; } catch (Exception e) { ErrorLogger.LogBuildError("Failed to load pre-compiled edit and continue dll " + e); return(false); } } else { status.SetStatus(Language.GetTextValue("tModLoader.MSCompilingWindows", mod)); status.SetProgress(0, 2); CompileMod(mod, refMods, true, ref winDLL, ref winPDB); } if (winDLL == null) { return(false); } status.SetStatus(Language.GetTextValue("tModLoader.MSCompilingMono", mod)); status.SetProgress(1, 2); CompileMod(mod, refMods, false, ref monoDLL, ref winPDB); //the pdb reference won't actually be written to if (monoDLL == null) { return(false); } } if (!VerifyName(mod.Name, winDLL) || !VerifyName(mod.Name, monoDLL)) { return(false); } status.SetStatus(Language.GetTextValue("tModLoader.MSBuilding") + mod + "..."); status.SetProgress(0, 1); mod.modFile.AddFile("Info", mod.properties.ToBytes()); if (Equal(winDLL, monoDLL)) { mod.modFile.AddFile("All.dll", winDLL); if (winPDB != null) { mod.modFile.AddFile("All.pdb", winPDB); } } else { mod.modFile.AddFile("Windows.dll", winDLL); mod.modFile.AddFile("Mono.dll", monoDLL); if (winPDB != null) { mod.modFile.AddFile("Windows.pdb", winPDB); } } foreach (var resource in Directory.GetFiles(mod.path, "*", SearchOption.AllDirectories)) { var relPath = resource.Substring(mod.path.Length + 1); if (mod.properties.ignoreFile(relPath) || relPath == "build.txt" || relPath == ".gitattributes" || relPath == ".gitignore" || relPath.StartsWith(".git" + Path.DirectorySeparatorChar) || relPath.StartsWith(".vs" + Path.DirectorySeparatorChar) || relPath.StartsWith("bin" + Path.DirectorySeparatorChar) || relPath.StartsWith("obj" + Path.DirectorySeparatorChar) || !mod.properties.includeSource && sourceExtensions.Contains(Path.GetExtension(resource)) || Path.GetFileName(resource) == "Thumbs.db") { continue; } mod.modFile.AddFile(relPath, File.ReadAllBytes(resource)); } WAVCacheIO.ClearCache(mod.Name); mod.modFile.Save(); EnableMod(mod.modFile); ActivateExceptionReporting(); ModLoader.isModder = true; return(true); }
private void CompileMod(BuildingMod mod, List <LocalMod> refMods, bool forWindows, ref byte[] dll, ref byte[] pdb) { if (!LoadCompilationReferences()) { return; } bool generatePDB = mod.properties.includePDB && forWindows; if (generatePDB && !windows) { Console.WriteLine(Language.GetTextValue("tModLoader.BuildErrorPDBWindowsOnly")); generatePDB = false; } //collect all dll references var tempDir = Path.Combine(ModPath, "compile_temp"); Directory.CreateDirectory(tempDir); var refs = new List <string>(); //everything used to compile the tModLoader for the target platform refs.AddRange(GetTerrariaReferences(tempDir, forWindows)); //libs added by the mod refs.AddRange(mod.properties.dllReferences.Select(refDll => Path.Combine(mod.path, "lib/" + refDll + ".dll"))); //all dlls included in all referenced mods foreach (var refMod in refMods) { using (refMod.modFile.EnsureOpen()) { var path = Path.Combine(tempDir, refMod + ".dll"); File.WriteAllBytes(path, refMod.modFile.GetMainAssembly(forWindows)); refs.Add(path); foreach (var refDll in refMod.properties.dllReferences) { path = Path.Combine(tempDir, refDll + ".dll"); File.WriteAllBytes(path, refMod.modFile.GetBytes("lib/" + refDll + ".dll")); refs.Add(path); } } } var compileOptions = new CompilerParameters { OutputAssembly = Path.Combine(tempDir, mod + ".dll"), GenerateExecutable = false, GenerateInMemory = false, TempFiles = new TempFileCollection(tempDir, true), IncludeDebugInformation = generatePDB, CompilerOptions = "/optimize" }; compileOptions.ReferencedAssemblies.AddRange(refs.ToArray()); var files = Directory.GetFiles(mod.path, "*.cs", SearchOption.AllDirectories).Where(file => !mod.properties.ignoreFile(file.Substring(mod.path.Length + 1))).ToArray(); try { var results = RoslynCompile(compileOptions, files); if (results.Errors.HasErrors) { status.LogCompileErrors(mod.Name + (forWindows ? "/Windows.dll" : "/Mono.dll"), results.Errors, forWindows != windows ? Language.GetTextValue("tModLoader.BuildErrorModCompileFolderHint") : null); return; } dll = File.ReadAllBytes(compileOptions.OutputAssembly); dll = PostProcess(dll, forWindows); if (generatePDB) { pdb = File.ReadAllBytes(Path.Combine(tempDir, mod + ".pdb")); } } finally { int numTries = 10; while (numTries > 0) { try { Directory.Delete(tempDir, true); numTries = 0; } catch { System.Threading.Thread.Sleep(1); numTries--; } } } }
private static void CompileMod(BuildingMod mod, List <LocalMod> refMods, bool forWindows, ref byte[] dll, ref byte[] pdb) { LoadReferences(); bool generatePDB = mod.properties.includePDB && forWindows; if (generatePDB && !windows) { Console.WriteLine(Language.GetTextValue("tModLoader.BuildErrorPDBWindowsOnly")); generatePDB = false; } //collect all dll references var tempDir = Path.Combine(ModPath, "compile_temp"); Directory.CreateDirectory(tempDir); var refs = new List <string>(); //everything used to compile the tModLoader for the target platform refs.AddRange(GetTerrariaReferences(tempDir, forWindows)); //libs added by the mod refs.AddRange(mod.properties.dllReferences.Select(refDll => Path.Combine(mod.path, "lib/" + refDll + ".dll"))); //all dlls included in all referenced mods foreach (var refMod in refMods) { var path = Path.Combine(tempDir, refMod + ".dll"); File.WriteAllBytes(path, refMod.modFile.GetMainAssembly(forWindows)); refs.Add(path); foreach (var refDll in refMod.properties.dllReferences) { path = Path.Combine(tempDir, refDll + ".dll"); File.WriteAllBytes(path, refMod.modFile.GetFile("lib/" + refDll + ".dll")); refs.Add(path); } } var compileOptions = new CompilerParameters { OutputAssembly = Path.Combine(tempDir, mod + ".dll"), GenerateExecutable = false, GenerateInMemory = false, TempFiles = new TempFileCollection(tempDir, true), IncludeDebugInformation = generatePDB, CompilerOptions = "/optimize" }; compileOptions.ReferencedAssemblies.AddRange(refs.ToArray()); var files = Directory.GetFiles(mod.path, "*.cs", SearchOption.AllDirectories).Where(file => !mod.properties.ignoreFile(file.Substring(mod.path.Length + 1))).ToArray(); try { CompilerResults results; if (mod.properties.languageVersion == 6) { if (Environment.Version.Revision < 10000) { ErrorLogger.LogBuildError(Language.GetTextValue("tModLoader.BuildErrorDotNet45forCS6")); return; } results = RoslynCompile(compileOptions, files); } else { var options = new Dictionary <string, string> { { "CompilerVersion", "v" + mod.properties.languageVersion + ".0" } }; results = new CSharpCodeProvider(options).CompileAssemblyFromFile(compileOptions, files); } if (results.Errors.HasErrors) { ErrorLogger.LogCompileErrors(results.Errors, forWindows); return; } dll = File.ReadAllBytes(compileOptions.OutputAssembly); dll = PostProcess(dll, forWindows); if (generatePDB) { pdb = File.ReadAllBytes(Path.Combine(tempDir, mod + ".pdb")); } } finally { int numTries = 10; while (numTries > 0) { try { Directory.Delete(tempDir, true); numTries = 0; } catch { System.Threading.Thread.Sleep(1); numTries--; } } } }
private void BuildModForPlatform(BuildingMod mod, bool xna) { status.SetProgress(xna ? 0 : 1, 2); try { if (Directory.Exists(tempDir)) { Directory.Delete(tempDir, true); } Directory.CreateDirectory(tempDir); string dllName = mod.Name + (xna ? ".XNA.dll" : ".FNA.dll"); string dllPath = null; // look for pre-compiled paths if (mod.properties.noCompile) { var allPath = Path.Combine(mod.path, mod.Name + ".All.dll"); dllPath = File.Exists(allPath) ? allPath : Path.Combine(mod.path, dllName); } else if (xna == PlatformUtilities.IsXNA && Program.LaunchParameters.TryGetValue("-eac", out var eacValue)) { dllPath = eacValue; } var refs = GetReferencesLazy(mod, xna); // precompiled load, or fallback to Roslyn compile if (File.Exists(dllPath)) { status.SetStatus(Language.GetTextValue("tModLoader.LoadingPrecompiled", dllName, Path.GetFileName(dllPath))); } else if (dllPath != null) { throw new BuildException(Language.GetTextValue("tModLoader.BuildErrorLoadingPrecompiled", dllPath)); } else { dllPath = Path.Combine(tempDir, dllName); CompileMod(mod, dllPath, refs, xna); } // add mod assembly to file mod.modFile.AddFile(dllName, File.ReadAllBytes(dllPath)); // read mod assembly using cecil for verification and pdb processing using (var asmResolver = new BuildAssemblyResolver(Path.GetDirectoryName(dllPath), refs)) { var asm = AssemblyDefinition.ReadAssembly(dllPath, new ReaderParameters { InMemory = true, ReadSymbols = mod.properties.includePDB, AssemblyResolver = asmResolver }); VerifyModAssembly(mod.Name, asm); if (!mod.properties.includePDB) { return; } // when reading and writing a module with cecil, the debug sequence points need regenerating, even if the methods are not changed // write out the pdb file using cecil because doing it at runtime is difficult var tempDllPath = Path.Combine(tempDir, dllName); //use the temp dir to avoid overwriting a precompiled dll // force the native pdb writer when possible, to support stack traces on older .NET frameworks asm.Write(tempDllPath, new WriterParameters { WriteSymbols = true, SymbolWriterProvider = FrameworkVersion.Framework == Framework.NetFramework ? new NativePdbWriterProvider() : (ISymbolWriterProvider) new PortablePdbWriterProvider() });; mod.modFile.AddFile(Path.ChangeExtension(dllName, "pdb"), File.ReadAllBytes(Path.ChangeExtension(tempDllPath, "pdb"))); if (dllPath == tempDllPath) // load the cecil produced dll, which has the correct debug header { mod.modFile.AddFile(dllName, File.ReadAllBytes(dllPath)); } else // with a pre-loaded dll, the symbols won't match cecil symbols unless we splice in the cecil debug header { using (var cecilAsmDef = AssemblyDefinition.ReadAssembly(tempDllPath)) mod.modFile.AddFile(dllName + ".cecildebugheader", cecilAsmDef.MainModule.GetDebugHeader().GetBytes()); } // make an mdb for FNA if (!xna) { asm.Write(tempDllPath, new WriterParameters { WriteSymbols = true, SymbolWriterProvider = new MdbWriterProvider() }); mod.modFile.AddFile(dllName + ".mdb", File.ReadAllBytes(tempDllPath + ".mdb")); } } } finally { try { if (Directory.Exists(tempDir)) { Directory.Delete(tempDir, true); } } catch { } } }
private bool Build(BuildingMod mod) { status.SetMod(mod.Name); status.SetStatus(Language.GetTextValue("tModLoader.Building", mod.Name)); byte[] winDLL = null; byte[] monoDLL = null; byte[] winPDB = null; if (mod.properties.noCompile) { winDLL = monoDLL = ReadIfExists(Path.Combine(mod.path, "All.dll")); winPDB = ReadIfExists(Path.Combine(mod.path, "All.pdb")); if (winDLL == null) { winDLL = ReadIfExists(Path.Combine(mod.path, "Windows.dll")); monoDLL = ReadIfExists(Path.Combine(mod.path, "Mono.dll")); winPDB = ReadIfExists(Path.Combine(mod.path, "Windows.pdb")); } if (winDLL == null || monoDLL == null) { var missing = new List <string> { "All.dll" }; if (winDLL == null) { missing.Add("Windows.dll"); } if (monoDLL == null) { missing.Add("Mono.dll"); } status.LogError(Language.GetTextValue("tModLoader.BuildErrorMissingDllFiles", string.Join(", ", missing))); return(false); } } else { List <LocalMod> refMods; try { refMods = FindReferencedMods(mod.properties); } catch (Exception e) { status.LogError(e.Message, e.InnerException); return(false); } if (Program.LaunchParameters.ContainsKey("-eac")) { if (!windows) { status.LogError(Language.GetTextValue("tModLoader.BuildErrorEACWindowsOnly")); return(false); } var winPath = Program.LaunchParameters["-eac"]; try { status.SetStatus(Language.GetTextValue("tModLoader.LoadingEAC")); var pdbPath = Path.ChangeExtension(winPath, "pdb"); winDLL = File.ReadAllBytes(winPath); winPDB = File.ReadAllBytes(pdbPath); mod.properties.editAndContinue = true; } catch (Exception e) { status.LogError(Language.GetTextValue("tModLoader.BuildErrorEACLoadFailed", winPath + "/.pdb"), e); return(false); } } else { status.SetStatus(Language.GetTextValue("tModLoader.CompilingWindows", mod)); status.SetProgress(0, 2); CompileMod(mod, refMods, true, ref winDLL, ref winPDB); } if (winDLL == null) { return(false); } status.SetStatus(Language.GetTextValue("tModLoader.CompilingMono", mod)); status.SetProgress(1, 2); CompileMod(mod, refMods, false, ref monoDLL, ref winPDB); //the pdb reference won't actually be written to if (monoDLL == null) { return(false); } } if (!VerifyName(mod.Name, winDLL) || !VerifyName(mod.Name, monoDLL)) { return(false); } status.SetStatus(Language.GetTextValue("tModLoader.Packaging", mod)); status.SetProgress(0, 1); mod.modFile.AddFile("Info", mod.properties.ToBytes()); if (Equal(winDLL, monoDLL)) { mod.modFile.AddFile("All.dll", winDLL); if (winPDB != null) { mod.modFile.AddFile("All.pdb", winPDB); } } else { mod.modFile.AddFile("Windows.dll", winDLL); mod.modFile.AddFile("Mono.dll", monoDLL); if (winPDB != null) { mod.modFile.AddFile("Windows.pdb", winPDB); } } foreach (var resource in Directory.GetFiles(mod.path, "*", SearchOption.AllDirectories)) { var relPath = resource.Substring(mod.path.Length + 1); if (mod.properties.ignoreFile(relPath) || relPath == "build.txt" || relPath == ".gitattributes" || relPath == ".gitignore" || relPath.StartsWith(".git" + Path.DirectorySeparatorChar) || relPath.StartsWith(".vs" + Path.DirectorySeparatorChar) || relPath.StartsWith(".idea" + Path.DirectorySeparatorChar) || relPath.StartsWith("bin" + Path.DirectorySeparatorChar) || relPath.StartsWith("obj" + Path.DirectorySeparatorChar) || !mod.properties.includeSource && sourceExtensions.Contains(Path.GetExtension(resource)) || Path.GetFileName(resource) == "Thumbs.db") { continue; } AddResource(mod.modFile, relPath, resource); } WAVCacheIO.ClearCache(mod.Name); GetMod(mod.Name)?.File?.Close(); // if the mod is currently loaded, the file-handle needs to be released mod.modFile.Save(); mod.modFile.Close(); EnableMod(mod.Name); return(true); }
private static void CompileMod(BuildingMod mod, List <LoadingMod> refMods, bool forWindows, ref byte[] dll, ref byte[] pdb) { LoadReferences(); var terrariaModule = Assembly.GetExecutingAssembly(); bool generatePDB = mod.properties.includePDB && forWindows; if (generatePDB && !windows) { Console.WriteLine("PDB files can only be generated for windows, on windows."); generatePDB = false; } var refs = new List <string>(terrariaReferences); if (forWindows == windows) { refs.Add(terrariaModule.Location); } else { refs = refs.Where(path => { var name = Path.GetFileName(path); return(name != "FNA.dll" && !name.StartsWith("Microsoft.Xna.Framework")); }).ToList(); var names = forWindows ? new[] { "tModLoaderWindows.exe", "Microsoft.Xna.Framework.dll", "Microsoft.Xna.Framework.Game.dll", "Microsoft.Xna.Framework.Graphics.dll", "Microsoft.Xna.Framework.Xact.dll" } : new[] { "tModLoaderMac.exe", "FNA.dll" }; refs.AddRange(names.Select(f => Path.Combine(modCompileDir, f))); } refs.AddRange(mod.properties.dllReferences.Select(refDll => Path.Combine(mod.path, "lib/" + refDll + ".dll"))); var tempDir = Path.Combine(ModPath, "compile_temp"); Directory.CreateDirectory(tempDir); foreach (var resName in terrariaModule.GetManifestResourceNames().Where(n => n.EndsWith(".dll"))) { var path = Path.Combine(tempDir, Path.GetFileName(resName)); using (Stream res = terrariaModule.GetManifestResourceStream(resName), file = File.Create(path)) res.CopyTo(file); refs.Add(path); } foreach (var refMod in refMods) { var path = Path.Combine(tempDir, refMod + ".dll"); File.WriteAllBytes(path, refMod.modFile.GetMainAssembly(forWindows)); refs.Add(path); foreach (var refDll in refMod.properties.dllReferences) { path = Path.Combine(tempDir, refDll + ".dll"); File.WriteAllBytes(path, refMod.modFile.GetFile("lib/" + refDll + ".dll")); refs.Add(path); } } var compileOptions = new CompilerParameters { OutputAssembly = Path.Combine(tempDir, mod + ".dll"), GenerateExecutable = false, GenerateInMemory = false, TempFiles = new TempFileCollection(tempDir, true), IncludeDebugInformation = generatePDB }; compileOptions.ReferencedAssemblies.AddRange(refs.ToArray()); var files = Directory.GetFiles(mod.path, "*.cs", SearchOption.AllDirectories).Where(file => !mod.properties.ignoreFile(file.Substring(mod.path.Length + 1))).ToArray(); try { CompilerResults results; if (mod.properties.languageVersion == 6) { if (Environment.Version.Revision < 10000) { ErrorLogger.LogBuildError(".NET Framework 4.5 must be installed to compile C# 6.0"); return; } results = RoslynCompile(compileOptions, files); } else { var options = new Dictionary <string, string> { { "CompilerVersion", "v" + mod.properties.languageVersion + ".0" } }; results = new CSharpCodeProvider(options).CompileAssemblyFromFile(compileOptions, files); } if (results.Errors.HasErrors) { ErrorLogger.LogCompileErrors(results.Errors, forWindows); return; } dll = File.ReadAllBytes(compileOptions.OutputAssembly); if (generatePDB) { pdb = File.ReadAllBytes(Path.Combine(tempDir, mod + ".pdb")); } } finally { int numTries = 10; while (numTries > 0) { try { Directory.Delete(tempDir, true); numTries = 0; } catch { System.Threading.Thread.Sleep(1); numTries--; } } } }
private void CompileMod(BuildingMod mod, string outputPath, ref List <LocalMod> refMods, bool xna) { UpdateReferencesFolder(); status.SetStatus(Language.GetTextValue("tModLoader.Compiling", Path.GetFileName(outputPath))); if (!DeveloperModeReady(out string msg)) { throw new BuildException(msg); } if (refMods == null) { refMods = FindReferencedMods(mod.properties); } var refs = new List <string>(); //everything used to compile the tModLoader for the target platform refs.AddRange(GetTerrariaReferences(tempDir, xna)); // add framework assemblies refs.AddRange(Directory.GetFiles(referenceAssembliesPath, "*.dll", SearchOption.AllDirectories) .Where(path => !path.EndsWith("Thunk.dll") && !path.EndsWith("Wrapper.dll"))); //libs added by the mod refs.AddRange(mod.properties.dllReferences.Select(dllName => DllRefPath(mod, dllName))); //all dlls included in all referenced mods foreach (var refMod in refMods) { using (refMod.modFile.Open()) { var path = Path.Combine(tempDir, refMod + ".dll"); File.WriteAllBytes(path, refMod.modFile.GetModAssembly(xna)); refs.Add(path); foreach (var refDll in refMod.properties.dllReferences) { path = Path.Combine(tempDir, refDll + ".dll"); File.WriteAllBytes(path, refMod.modFile.GetBytes("lib/" + refDll + ".dll")); refs.Add(path); } } } var files = Directory.GetFiles(mod.path, "*.cs", SearchOption.AllDirectories).Where(file => !mod.properties.ignoreFile(file.Substring(mod.path.Length + 1))).ToArray(); bool allowUnsafe = Program.LaunchParameters.TryGetValue("-unsafe", out var unsafeParam) && bool.TryParse(unsafeParam, out var _allowUnsafe) && _allowUnsafe; var preprocessorSymbols = new List <string> { xna ? "XNA" : "FNA" }; if (Program.LaunchParameters.TryGetValue("-define", out var defineParam)) { preprocessorSymbols.AddRange(defineParam.Split(';', ' ')); } var results = RoslynCompile(mod.Name, outputPath, refs.ToArray(), files, preprocessorSymbols.ToArray(), mod.properties.includePDB, allowUnsafe); int numWarnings = results.Cast <CompilerError>().Count(e => e.IsWarning); int numErrors = results.Count - numWarnings; status.LogCompilerLine(Language.GetTextValue("tModLoader.CompilationResult", numErrors, numWarnings), Level.Info); foreach (CompilerError line in results) { status.LogCompilerLine(line.ToString(), line.IsWarning ? Level.Warn : Level.Error); } if (results.HasErrors) { var firstError = results.Cast <CompilerError>().First(e => !e.IsWarning); throw new BuildException(Language.GetTextValue("tModLoader.CompileError", Path.GetFileName(outputPath), numErrors, firstError)); } }
private static void CompileMod(BuildingMod mod, List<LoadingMod> refMods, bool forWindows, ref byte[] dll, ref byte[] pdb) { LoadReferences(); var terrariaModule = Assembly.GetExecutingAssembly(); bool generatePDB = mod.properties.includePDB && forWindows; if (generatePDB && !windows) { Console.WriteLine("PDB files can only be generated for windows, on windows."); generatePDB = false; } var refs = new List<string>(terrariaReferences); if (forWindows == windows) { refs.Add(terrariaModule.Location); } else { refs = refs.Where(path => { var name = Path.GetFileName(path); return name != "FNA.dll" && !name.StartsWith("Microsoft.Xna.Framework"); }).ToList(); var names = forWindows ? new[] { "tModLoaderWindows.exe", "Microsoft.Xna.Framework.dll", "Microsoft.Xna.Framework.Game.dll", "Microsoft.Xna.Framework.Graphics.dll", "Microsoft.Xna.Framework.Xact.dll" } : new[] { "tModLoaderMac.exe", "FNA.dll" }; refs.AddRange(names.Select(f => Path.Combine(modCompileDir, f))); } refs.AddRange(mod.properties.dllReferences.Select(refDll => Path.Combine(mod.path, "lib/" + refDll + ".dll"))); var tempDir = Path.Combine(ModPath, "compile_temp"); Directory.CreateDirectory(tempDir); foreach (var resName in terrariaModule.GetManifestResourceNames().Where(n => n.EndsWith(".dll"))) { var path = Path.Combine(tempDir, Path.GetFileName(resName)); using (Stream res = terrariaModule.GetManifestResourceStream(resName), file = File.Create(path)) res.CopyTo(file); refs.Add(path); } foreach (var refMod in refMods) { var path = Path.Combine(tempDir, refMod.Name + ".dll"); File.WriteAllBytes(path, refMod.modFile.GetMainAssembly(forWindows)); refs.Add(path); foreach (var refDll in refMod.properties.dllReferences) { path = Path.Combine(tempDir, refDll + ".dll"); File.WriteAllBytes(path, refMod.modFile.GetFile("lib/"+refDll+".dll")); refs.Add(path); } } var compileOptions = new CompilerParameters { OutputAssembly = Path.Combine(tempDir, mod.Name + ".dll"), GenerateExecutable = false, GenerateInMemory = false, TempFiles = new TempFileCollection(tempDir, true), IncludeDebugInformation = generatePDB }; compileOptions.ReferencedAssemblies.AddRange(refs.ToArray()); var files = Directory.GetFiles(mod.path, "*.cs", SearchOption.AllDirectories); try { CompilerResults results; if (mod.properties.languageVersion == 6) { if (Environment.Version.Revision < 10000) { ErrorLogger.LogBuildError(".NET Framework 4.5 must be installed to compile C# 6.0"); return; } results = RoslynCompile(compileOptions, files); } else { var options = new Dictionary<string, string> { { "CompilerVersion", "v" + mod.properties.languageVersion + ".0" } }; results = new CSharpCodeProvider(options).CompileAssemblyFromFile(compileOptions, files); } if (results.Errors.HasErrors) { ErrorLogger.LogCompileErrors(results.Errors); return; } dll = File.ReadAllBytes(compileOptions.OutputAssembly); if (generatePDB) pdb = File.ReadAllBytes(Path.Combine(tempDir, mod.Name + ".pdb")); } finally { int numTries = 10; while (numTries > 0) { try { Directory.Delete(tempDir, true); numTries = 0; } catch { System.Threading.Thread.Sleep(1); numTries--; } } } }
private static bool Build(BuildingMod mod, IBuildStatus status) { byte[] winDLL = null; byte[] monoDLL = null; byte[] winPDB = null; if (mod.properties.noCompile) { winDLL = monoDLL = ReadIfExists(Path.Combine(mod.path, "All.dll")); winPDB = ReadIfExists(Path.Combine(mod.path, "All.pdb")); if (winDLL == null) { winDLL = ReadIfExists(Path.Combine(mod.path, "Windows.dll")); monoDLL = ReadIfExists(Path.Combine(mod.path, "Mono.dll")); winPDB = ReadIfExists(Path.Combine(mod.path, "Windows.pdb")); } if (winDLL == null || monoDLL == null) { ErrorLogger.LogDllBuildError(mod.path); return false; } } else { var refMods = FindReferencedMods(mod.properties); if (refMods == null) return false; if (Program.LaunchParameters.ContainsKey("-eac")) { if (!windows) { ErrorLogger.LogBuildError("Edit and continue is only supported on windows"); return false; } try { status.SetStatus("Loading pre-compiled Windows.dll with edit and continue support"); var winPath = Program.LaunchParameters["-eac"]; var pdbPath = Path.ChangeExtension(winPath, "pdb"); winDLL = File.ReadAllBytes(winPath); winPDB = File.ReadAllBytes(pdbPath); mod.properties.editAndContinue = true; } catch (Exception e) { ErrorLogger.LogBuildError("Failed to load pre-compiled edit and continue dll "+e); return false; } } else { status.SetStatus("Compiling " + mod.Name + " for Windows..."); status.SetProgress(0, 2); CompileMod(mod, refMods, true, ref winDLL, ref winPDB); } status.SetStatus("Compiling " + mod.Name + " for Mono..."); status.SetProgress(1, 2); CompileMod(mod, refMods, false, ref monoDLL, ref winPDB);//the pdb reference won't actually be written to if (winDLL == null || monoDLL == null) return false; } if (!VerifyName(mod.Name, winDLL) || !VerifyName(mod.Name, monoDLL)) return false; status.SetStatus("Building "+mod.Name+"..."); status.SetProgress(0, 1); mod.modFile.AddFile("Info", mod.properties.ToBytes()); if (Equal(winDLL, monoDLL)) { mod.modFile.AddFile("All.dll", winDLL); if (winPDB != null) mod.modFile.AddFile("All.pdb", winPDB); } else { mod.modFile.AddFile("Windows.dll", winDLL); mod.modFile.AddFile("Mono.dll", monoDLL); if (winPDB != null) mod.modFile.AddFile("Windows.pdb", winPDB); } foreach (var resource in Directory.GetFiles(mod.path, "*", SearchOption.AllDirectories)) { var relPath = resource.Substring(mod.path.Length + 1); if (mod.properties.ignoreFile(relPath) || relPath == "build.txt" || !mod.properties.includeSource && Path.GetExtension(resource) == ".cs" || Path.GetFileName(resource) == "Thumbs.db") continue; mod.modFile.AddFile(relPath, File.ReadAllBytes(resource)); } WAVCacheIO.ClearCache(mod.Name); mod.modFile.Save(); EnableMod(mod.modFile); return true; }
private bool Build(BuildingMod mod) { status.SetMod(mod.Name); status.SetStatus(Language.GetTextValue("tModLoader.Building", mod.Name)); byte[] winDLL = null; byte[] monoDLL = null; byte[] winPDB = null; if (mod.properties.noCompile) { winDLL = monoDLL = ReadIfExists(Path.Combine(mod.path, "All.dll")); winPDB = ReadIfExists(Path.Combine(mod.path, "All.pdb")); if (winDLL == null) { winDLL = ReadIfExists(Path.Combine(mod.path, "Windows.dll")); monoDLL = ReadIfExists(Path.Combine(mod.path, "Mono.dll")); winPDB = ReadIfExists(Path.Combine(mod.path, "Windows.pdb")); } if (winDLL == null || monoDLL == null) { var missing = new List <string> { "All.dll" }; if (winDLL == null) { missing.Add("Windows.dll"); } if (monoDLL == null) { missing.Add("Mono.dll"); } status.LogError(Language.GetTextValue("tModLoader.BuildErrorMissingDllFiles", string.Join(", ", missing))); return(false); } } else { List <LocalMod> refMods; try { refMods = FindReferencedMods(mod.properties); } catch (Exception e) { status.LogError(e.Message, e.InnerException); return(false); } if (Program.LaunchParameters.ContainsKey("-eac")) { if (!windows) { status.LogError(Language.GetTextValue("tModLoader.BuildErrorEACWindowsOnly")); return(false); } var winPath = Program.LaunchParameters["-eac"]; try { status.SetStatus(Language.GetTextValue("tModLoader.LoadingEAC")); var pdbPath = Path.ChangeExtension(winPath, "pdb"); winDLL = File.ReadAllBytes(winPath); winPDB = File.ReadAllBytes(pdbPath); mod.properties.editAndContinue = true; } catch (Exception e) { status.LogError(Language.GetTextValue("tModLoader.BuildErrorEACLoadFailed", winPath + "/.pdb"), e); return(false); } } else { status.SetStatus(Language.GetTextValue("tModLoader.CompilingWindows", mod)); status.SetProgress(0, 2); CompileMod(mod, refMods, true, ref winDLL, ref winPDB); } if (winDLL == null) { return(false); } status.SetStatus(Language.GetTextValue("tModLoader.CompilingMono", mod)); status.SetProgress(1, 2); CompileMod(mod, refMods, false, ref monoDLL, ref winPDB); //the pdb reference won't actually be written to if (monoDLL == null) { return(false); } } if (!VerifyName(mod.Name, winDLL) || !VerifyName(mod.Name, monoDLL)) { return(false); } status.SetStatus(Language.GetTextValue("tModLoader.Packaging", mod)); status.SetProgress(0, 1); mod.modFile.AddFile("Info", mod.properties.ToBytes()); if (Equal(winDLL, monoDLL)) { mod.modFile.AddFile("All.dll", winDLL); if (winPDB != null) { mod.modFile.AddFile("All.pdb", winPDB); } } else { mod.modFile.AddFile("Windows.dll", winDLL); mod.modFile.AddFile("Mono.dll", monoDLL); if (winPDB != null) { mod.modFile.AddFile("Windows.pdb", winPDB); } } var resources = Directory.GetFiles(mod.path, "*", SearchOption.AllDirectories) .Where(res => !IgnoreResource(mod, res)) .ToList(); Parallel.ForEach(resources, resource => AddResource(mod, resource)); GetMod(mod.Name)?.File?.Close(); // if the mod is currently loaded, the file-handle needs to be released mod.modFile.Save(); mod.modFile.Close(); EnableMod(mod.Name); return(true); }