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);
        }
Exemple #2
0
        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--;
                    }
                }
            }
        }
Exemple #3
0
        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--;
                    }
                }
            }
        }
Exemple #4
0
        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 { }
            }
        }
Exemple #5
0
        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);
        }
Exemple #6
0
        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));
            }
        }
Exemple #8
0
        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--;
                    }
                }
            }
        }
Exemple #9
0
        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;
        }
Exemple #10
0
        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);
        }