/// <summary> /// Parses the mod's information from Json, loading any required references, and returns its <see cref="ModInfo"/> object. /// </summary> /// <param name="j">Json Data to load the <see cref="ModInfo"/> from</param> /// <param name="path">The path to the mod</param> /// <returns>The <see cref="ModInfo"/> of the mod</returns> public static ModInfo ParseModInfo(JsonData j, string path) { var refs = new List<IReference>(); if (j.Has("dllReferences")) foreach (object s in j["dllReferences"]) refs.Add(new AssemblyReference(s.ToString(), path)); if (j.Has("modReferences")) foreach (object s in j["modReferences"]) refs.Add(new ModReference(s.ToString())); string internalName = j.GetOrExn<string>("internalName"); return new ModInfo( path, internalName, j.GetOrDef("displayName", internalName), j.GetOrDef("author", "<unspecified>"), j.GetOrDef("version", "0.0.0.0"), j.GetOrDef<string>("description"), j.GetOrExn<string>("asmFileName"), j.GetOrExn<string>("modDefTypeName"), refs.ToArray() ); }
static void BuildSource(string sourcePath, string outputPath, JsonData modInfo, CompileException cex, Dictionary<string, string> dictNames) { string[] modPathSplit = sourcePath.Split('\\', '/'); string modName = modPathSplit[modPathSplit.Length - 1].Split('.')[0]; if (modInfo.Has("MSBuild")) if ((bool)modInfo["MSBuild"]) { // done by msbuild anyway ModsCompile.BuildSource(sourcePath, outputPath, modInfo, cex, dictNames); return; } bool generatePDB = false; if (modInfo.Has("includePDB")) generatePDB = (bool)modInfo["includePDB"]; // but this has to change - other CodeDomProviders (default stays C#) CodeDomProvider cdp = new CSharpCodeProvider(); foreach (string fileName in Directory.EnumerateFiles(sourcePath, "*.json", SearchOption.AllDirectories)) { string fname = fileName.Substring(sourcePath.Length + 1).Replace('\\', '/'); if (fname == "ModInfo.json") continue; try { JsonData json2 = JsonMapper.ToObject(File.ReadAllText(fileName)); if (fname.ToLower().StartsWith("item/")) ValidateJson.Item(modName, fileName, json2, cex); if (fname.ToLower().StartsWith("npc/")) ValidateJson.NPC(modName, fileName, json2, cex); if (fname.ToLower().StartsWith("projectile/")) ValidateJson.Projectile(modName, fileName, json2, cex); //TODO: check all the JSON files other than ModInfo.json for required fields } catch (Exception e) { cex.AddProblem(fileName, "Invalid JSON file.\n" + e.Message); } } CompilerParameters cp = new CompilerParameters(); cp.GenerateExecutable = false; cp.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location); cp.IncludeDebugInformation = generatePDB; 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.Xact.dll"); cp.ReferencedAssemblies.Add("Microsoft.Xna.Framework.Game.dll"); cp.ReferencedAssemblies.Add("Microsoft.Xna.Framework.Graphics.dll"); if (modInfo != null) { if (modInfo.Has("language")) switch (((string)modInfo["language"]).ToLowerInvariant()) { case "js": case "js.net": case "jscript": case "jscript.net": case "javascript": case "javascript.net": cdp = new JScriptCodeProvider(); break; case "vb": case "vb.net": case "visualbasic": case "visualbasic.net": case "visual basic": case "visual basic.net": cdp = new VBCodeProvider(); break; } if (modInfo.Has("modReferences")) { if (Directory.Exists(Mods.pathDirMods + "/.Temp")) Directory.Delete(Mods.pathDirMods + "/.Temp", true); Directory.CreateDirectory(Mods.pathDirMods + "/.Temp"); JsonData jRefs = (JsonData)modInfo["modReferences"]; for (int i = 0; i < jRefs.Count; i++) { string jRef = (string)jRefs[i]; if (!dictNames.ContainsKey(jRef)) continue; string modfile = dictNames[jRef]; cp.ReferencedAssemblies.Add(Mods.pathDirMods + "/.Temp/" + jRef + ".dll"); string[] split = jRef.Split('\\'); if (modfile.EndsWith(".tapimod")) { using (FileStream fileStream = new FileStream(modfile, FileMode.Open)) { BinBuffer bb2 = new BinBuffer(new BinBufferStream(fileStream)); bb2.ReadInt(); bb2.ReadString(); int count = bb2.ReadInt(); int skip = 0; while (count-- > 0) { bb2.ReadString(); skip += bb2.ReadInt(); } while (skip-- > 0) bb2.ReadByte(); File.WriteAllBytes(Mods.pathDirMods + "/.Temp/" + jRef + ".dll", bb2.ReadBytes(bb2.BytesLeft())); } } else if (modfile.EndsWith(".tapi")) { using (ZipFile zip = ZipFile.Read(modfile)) { if (zip.ContainsEntry("Mod.tapimod")) { ZipEntry ze = zip["Mod.tapimod"]; using (MemoryStream ms = new MemoryStream()) { ze.Extract(ms); ms.Position = 0; BinBuffer bb2 = new BinBuffer(new BinBufferStream(ms)); bb2.ReadInt(); bb2.ReadString(); int count = bb2.ReadInt(); int skip = 0; while (count-- > 0) { bb2.ReadString(); skip += bb2.ReadInt(); } while (skip-- > 0) bb2.ReadByte(); File.WriteAllBytes(Mods.pathDirMods + "/.Temp/" + jRef + ".dll", bb2.ReadBytes(bb2.BytesLeft())); } } } } } } if (modInfo.Has("dllReferences")) { JsonData jRefs = (JsonData)modInfo["dllReferences"]; for (int i = 0; i < jRefs.Count; i++) { string jRef = (string)jRefs[i]; if (File.Exists(sourcePath + "/" + jRef)) // remove .dll -> can also reference .exes cp.ReferencedAssemblies.Add(sourcePath + "/" + jRef); else cp.ReferencedAssemblies.Add(jRef); // somewhere else, like the GAC } } } cp.OutputAssembly = outputPath + (cdp is VBCodeProvider ? "" : ".dll"); // VBCodeProvider automatically adds '.dll' List<string> toCompile = new List<string>(); foreach (string fileName in Directory.EnumerateFiles(sourcePath, cdp.FileExtension, SearchOption.AllDirectories)) toCompile.Add(fileName); CompilerResults cr = cdp.CompileAssemblyFromFile(cp, toCompile.ToArray()); if (Directory.Exists(Mods.pathDirMods + "/.Temp")) Directory.Delete(Mods.pathDirMods + "/.Temp", true); if (cr.Errors.HasErrors) { foreach (CodeDomError ce in cr.Errors) { StringBuilder sb = new StringBuilder(); if (ce.FileName != "") { sb.Append("(" + ce.Column + "," + ce.Line + "): " + ce.ErrorText); sb.Append("\n" + File.ReadLines(ce.FileName).Skip(ce.Line - 1).Take(1).First().Replace("\t", " ")); sb.Append('\n'); for (int i = 0; i < ce.Column - 1; i++) sb.Append(' '); sb.Append('^'); cex.AddProblem(ce.FileName, sb.ToString()); } else // general error (without file) - .dll not found, etc cex.AddProblem(outputPath, (ce.IsWarning ? "warning" : "error") + " " + ce.ErrorNumber + ": " + ce.ErrorText); } } if (cex.problems.Count != 0) { if (File.Exists(outputPath + ".dll")) File.Delete(outputPath + ".dll"); throw cex; } }