static ModCompiler CreateMod() { ModCompiler mc = new ModCompiler(); ModData md = new ModData(mc); md.Assembly = Assembly.GetExecutingAssembly(); md.Info = new ModInfo(mc); md.Info.author = "PoroCYon"; md.Info.displayName = "Test Mod"; md.Info.includePDB = true; md.Info.internalName = "TestMod"; md.Info.info = "Mod meant to test the MCT Tools"; md.OriginName = "TestMod"; md.OriginPath = Directory.GetCurrentDirectory() + "\\TestMod"; md.items.Add(new Item(mc) { internalName = "TestMod:TestItem", displayName = "Test Item", maxStack = 999, rare = 2, recipes = new List<Recipe>() { new Recipe(mc) { creates = 3, items = new Dictionary<string, int>() { { "g:Wood" , 5 }, { "TestMod:TestItem", 1 } }, tiles = new List<string>() { "Work Bench" } } }, value = 50 }); return mc; }
public BuildLogger(ModData md) { building = md; }
IEnumerable<CompilerError> ClearFolders(ModData mod) { List<CompilerError> errors = new List<CompilerError>(); List<string> toRemove = new List<string>(); foreach (string key in mod.Files.Keys) { if (key.Contains(BIN) || key.Contains(OBJ) || key.Contains(DEBUG) || key.Contains(RELEASE) || key.Contains(IPCH) || key.Contains(GIT) || key.Contains(SVN) || key.Contains(SLN_IDE) || key.Contains(VS) || key.EndsWith(SDF) || key.EndsWith(O_SDF) || key.EndsWith(SUO) || key.EndsWith(USER) || key.EndsWith(CACHE) || key.EndsWith(GIT_IGN) || key.EndsWith(GIT_ATTR) || key.EndsWith(DB)) toRemove.Add(key); else if (!File.Exists(mod.OriginPath)) { foreach (string ignore in mod.Info.ignore) { try { foreach (string d in Directory.EnumerateFiles(mod.OriginPath, ignore, SearchOption.AllDirectories)) if (d.Substring(mod.OriginPath.Length) == key) toRemove.Add(d); } catch (Exception e) { errors.Add(new CompilerError(Building) { Cause = e, FilePath = mod.OriginPath, IsWarning = false, Message = "Error when searching for files to exclude." }); } try { foreach (string d in Directory.EnumerateDirectories(mod.OriginPath, ignore, SearchOption.AllDirectories)) if (d.Substring(mod.OriginPath.Length) == Path.GetDirectoryName(key)) toRemove.Add(d); } catch (Exception e) { errors.Add(new CompilerError(Building) { Cause = e, FilePath = mod.OriginPath, IsWarning = false, Message = "Error when searching for direcries to exclude." }); } } } } foreach (string r in toRemove) mod.files.Remove(r); return errors; }
CompilerOutput MainCompileStuff(ModData mod, Assembly asm) { if (asm == null) return null; mod.Assembly = asm; List<CompilerError> errors = new List<CompilerError>(); Log("Checking JSON files.", MessageImportance.High); errors.AddRange(new Checker(this).Check()); Log("Writing output file.", MessageImportance.High); errors.AddRange(new Writer (this).Write()); CompilerOutput outp = CreateOutput(errors); if (outp.Succeeded) outp.outputFile = Mods.pathCompiled + "\\" + mod.OriginName + (mod.Info.compress ? ".tapi" : ".tapimod"); LogResult(outp); EndCompile(mod.OriginPath); return outp; }
bool BeginCompile(string path) { if (!Debugger.IsAttached && AppendBuilding(path)) return false; if (!Directory.Exists(Consts.MctDirectory)) Directory.CreateDirectory(Consts.MctDirectory); if (!File.Exists(Consts.MctDirectory + "\\.building.json")) File.WriteAllText(Consts.MctDirectory + "\\.building.json", "[]"); if (building == null) { building = new ModData(this); building.OriginPath = path; building.OriginName = Path.GetFileNameWithoutExtension(path); } modDict = GetInternalNameToPathDictionary(); // dat name if (!Directory.Exists(Path.GetTempPath() + "\\MCT")) Directory.CreateDirectory(Path.GetTempPath() + "\\MCT"); return true; }
/// <summary> /// Compiles a mod from a managed assembly. /// </summary> /// <param name="asm">The assembly to compile.</param> /// <returns>The output of the compiler.</returns> public CompilerOutput CompileFromAssembly(Assembly asm) { for (int i = 0; i < Loggers.Count; i++) Loggers[i].compiler_wr = new WeakReference<ModCompiler>(this); Log("Compiling assembly " + asm, MessageImportance.Normal); if (building == null) { building = new ModData(this); building.OriginPath = asm.Location; building.OriginName = Path.GetFileNameWithoutExtension(asm.Location); } if (!BeginCompile(asm.Location)) { Exception cause; LogError(cause = new CompilerException("Mod already building!")); CompilerOutput o; LogResult(o = CreateOutput(new List<CompilerError>() { new CompilerError(building) { Cause = cause, FilePath = asm.Location, IsWarning = true, Message = "The mod is already being built." } })); return o; } try { CompilerOutput outp; Log("Extracting files.", MessageImportance.High); var extracted = new Extractor(this).ExtractData(asm); outp = CreateOutput(extracted.Item3); if (!outp.Succeeded) { LogResult(outp); EndCompile(asm.Location); return outp; } Log("Validating JSONs.", MessageImportance.High); outp = Validate(extracted.Item1, extracted.Item2, true); if (!outp.Succeeded) { LogResult(outp); EndCompile(asm.Location); return outp; } return MainCompileStuff(building, asm); } catch (Exception e) { EndCompile(asm.Location); LogError(e, "Unexpected error."); CompilerOutput o; LogResult(o = CreateOutput(new List<CompilerError>() { new CompilerError(building) { Cause = e, FilePath = asm.Location, IsWarning = false, Message = "An unexpected error occured while compiling." } })); return o; } }
/// <summary> /// Compiles a mod from a managed assembly. /// </summary> /// <param name="assemblyPath">The path to the assembly file, either relative to the working directory or an absolute path.</param> /// <returns>The output of the compiler.</returns> public CompilerOutput CompileFromAssembly(string assemblyPath) { for (int i = 0; i < Loggers.Count; i++) Loggers[i].compiler_wr = new WeakReference<ModCompiler>(this); assemblyPath = Environment.ExpandEnvironmentVariables(assemblyPath); Log("Compiling assembly from path " + assemblyPath, MessageImportance.Normal); building = new ModData(this); building.OriginPath = assemblyPath; building.OriginName = Path.GetFileNameWithoutExtension(assemblyPath); if (!BeginCompile(assemblyPath)) { Exception cause; LogError(cause = new CompilerException("Mod already building!")); CompilerOutput o; LogResult(o = CreateOutput(new List<CompilerError>() { new CompilerError(building) { Cause = cause, FilePath = assemblyPath, IsWarning = true, Message = "The mod is already being built." } })); return o; } try { #region check if file exists if (!File.Exists(assemblyPath)) { CompilerOutput o; LogResult(o = new CompilerOutput() { Succeeded = false, errors = new List<CompilerError>() { new CompilerError(building) { Cause = new FileNotFoundException("File '" + assemblyPath + "' not found."), Message = "The assembly '" + assemblyPath + "' was not found." } } }); return o; } #endregion Assembly asm; try { asm = Assembly.LoadFile(assemblyPath); } #region check if assembly is valid catch (BadImageFormatException e) // if (e is BadImageFormatException || e is DllNotFoundException || e is InvalidProgramException || e is TypeLoadException) { LogError(e); CompilerOutput o; LogResult(o = new CompilerOutput() { Succeeded = false, errors = new List<CompilerError>() { new CompilerError(building) { Cause = e, Message = "The assembly is not a manged assembly -or- is not compiled with the x86 architecture.", FilePath = assemblyPath } } }); return o; } catch (Exception e) { LogError(e); CompilerOutput o; LogResult(o = new CompilerOutput() { Succeeded = false, errors = new List<CompilerError>() { new CompilerError(building) { Cause = e, Message = "The assembly could not be loaded.", FilePath = assemblyPath } } }); return o; } #endregion return CompileFromAssembly(asm); } catch (Exception e) { LogError(e, "Unexpected error."); EndCompile(assemblyPath); CompilerOutput o; LogResult(o = CreateOutput(new List<CompilerError>() { new CompilerError(building) { Cause = e, FilePath = assemblyPath, IsWarning = false, Message = "An unexpected error occured while compiling." } })); return o; } }
/// <summary> /// Compiles a mod from its source folder. /// </summary> /// <param name="folder">The mod's folder. Either an absolute path, /// relative to the working directory or the name of a folder in the Mods\Sources folder</param> /// <returns>The output of the compiler.</returns> public CompilerOutput CompileFromSource (string folder) { for (int i = 0; i < Loggers.Count; i++) Loggers[i].compiler_wr = new WeakReference<ModCompiler>(this); folder = Environment.ExpandEnvironmentVariables(folder); if (folder.EndsWith("\\")) folder = folder.Remove(folder.Length - 1); if (folder[1] != ':' && !folder.StartsWith("\\")) // <drive>:\path or \\ServerName\path // if the folder doesn't exist, it's maybe a folder in the Mods\Sources directory? if (!Directory.Exists(folder)) folder = Mods.pathSources + "\\" + folder; else folder = Path.GetFullPath(folder); Log("Compiling source " + folder, MessageImportance.Normal); building = new ModData(this); try { building.OriginPath = folder; building.OriginName = Path.GetFileName(folder); if (!BeginCompile(folder)) { Exception cause; LogError(cause = new CompilerException("Mod already building!")); CompilerOutput o; LogResult(o = CreateOutput(new List<CompilerError>() { new CompilerError(building) { Cause = cause, FilePath = folder, IsWarning = true, Message = "The mod is already being built." } })); return o; } #region check if folder exists if (!Directory.Exists(folder)) { EndCompile(folder); Exception cause; LogError(cause = new DirectoryNotFoundException("Directory '" + folder + "' not found.")); CompilerOutput o; LogResult(o = new CompilerOutput() { Succeeded = false, errors = new List<CompilerError>() { new CompilerError(building) { Cause = cause, Message = "The mod directory (" + folder + ") was not found", IsWarning = false, FilePath = folder } } }); return o; } #endregion CompilerOutput outp; Log("Loading files.", MessageImportance.High); var readFiles = new FileLoader(this).LoadFiles(folder); outp = CreateOutput(readFiles.Item3); if (!outp.Succeeded) { LogResult (outp ); EndCompile(folder); return outp; } Log("Validating JSONs.", MessageImportance.High); outp = Validate(readFiles.Item1, readFiles.Item2, true); if (!outp.Succeeded) { LogResult (outp ); EndCompile(folder); return outp; } Log("Building sources.", MessageImportance.High); var compiled = new Builder(this).Build(); outp = CreateOutput(compiled.Item3); outp.Succeeded &= compiled.Item1 != null; if (!outp.Succeeded) { LogResult (outp ); EndCompile(folder); return outp; } return MainCompileStuff(building, compiled.Item1); } catch (Exception e) { LogError(e, "Unexpected error."); EndCompile(folder); CompilerOutput o; LogResult(o = CreateOutput(new List<CompilerError>() { new CompilerError(building) { Cause = e, FilePath = folder, IsWarning = false, Message = "An unexpected error occured while compiling." } })); return o; } }
/// <summary> /// Creates a new instance of the <see cref="CompilerError" /> class. /// </summary> /// <param name="built">The mod that was being built.</param> public CompilerError(ModData built) { data = built; }
/// <summary> /// Compiles all source files of the mod into a managed assembly. /// </summary> /// <param name="mod">The mod to compile.</param> /// <returns> /// A tuple containing the built assembly (null if failed), and a collection of all errors. /// The assembly must be saved on the disk, because the .pdb file must be loaded afterwards. /// </returns> public Tuple<Assembly, IEnumerable<CompilerError>> Compile(ModData mod) { Mod = mod; List<CompilerError> errors = new List<CompilerError>(); CodeDomProvider cdp = CreateCompiler(); CompilerParameters cp = new CompilerParameters(); cp.GenerateExecutable = false; cp.GenerateInMemory = false; cp.IncludeDebugInformation = mod.Info.includePDB; cp.OutputAssembly = Path.GetTempPath() + "MCT\\" + mod.Info.internalName + ".dll"; cp.WarningLevel = mod.Info.warningLevel; cp.ReferencedAssemblies.Add("mscorlib.dll"); cp.ReferencedAssemblies.Add("System.dll"); cp.ReferencedAssemblies.Add("System.Core.dll"); cp.ReferencedAssemblies.Add("System.Numerics.dll"); cp.ReferencedAssemblies.Add("System.Xml.dll"); cp.ReferencedAssemblies.Add("System.Drawing.dll"); cp.ReferencedAssemblies.Add("System.Windows.Forms.dll"); cp.ReferencedAssemblies.Add("Microsoft.Xna.Framework.dll"); cp.ReferencedAssemblies.Add("Microsoft.Xna.Framework.Game.dll"); cp.ReferencedAssemblies.Add("Microsoft.Xna.Framework.Graphics.dll"); cp.ReferencedAssemblies.Add("Microsoft.Xna.Framework.Xact.dll"); cp.ReferencedAssemblies.AddRange(LanguageDependancyAssemblies); cp.ReferencedAssemblies.Add("tAPI.exe"); // hmm hmm hmm cp.ReferencedAssemblies.AddRange(mod.Info.dllReferences); cp.ReferencedAssemblies.AddRange(mod.Info.modReferences); for (int i = 0; i < mod.Info.modReferences.Length; i++) try { cp.ReferencedAssemblies.AddRange(WriteRefAssembliesRec(mod.Info).ToArray()); } catch (Exception e) { errors.Add(new CompilerError(Building) { Cause = e, FilePath = Path.GetTempPath() + "MCT\\" + mod.Info.modReferences[i] + ".dll", IsWarning = false, Message = "Something went wrong when extracting the mod's assembly. See the exception for more details." }); } ModifyCompilerParameters(cp); var files = GetFiles(); for (int i = 0; i < files.Length; i++) files[i] = mod.OriginPath + "\\" + files[i].Replace('/', '\\'); CompilerResults cr = cdp.CompileAssemblyFromFile(cp, files); foreach (CodeDomError ce in cr.Errors) errors.Add(new CompilerError(Building) { Cause = new CompilerException(ce.ErrorNumber), FilePath = ce.FileName, IsWarning = ce.IsWarning, LocationInFile = new Point(ce.Column, ce.Line), Message = (ce.IsWarning ? "Warning" : "Error") + " " + ce.ErrorNumber + ": " + ce.ErrorText, }); return new Tuple<Assembly, IEnumerable<CompilerError>>(cr.Errors.HasErrors ? null : cr.CompiledAssembly, errors); }