private void Backup(string rootPath) { System.IO.Directory.CreateDirectory(Path.Combine(rootPath, "Backup")); System.IO.Directory.CreateDirectory(Path.Combine(rootPath, "Backup/DataBase")); System.IO.Directory.CreateDirectory(Path.Combine(rootPath, "Backup/Modules")); System.IO.Directory.CreateDirectory(Path.Combine(rootPath, "Backup/Terrain Sources")); if (File.Exists(Path.Combine(rootPath, "Backup/terrains.xml"))) { /*if backups are already there, the game's already been modded to some extent * backing up now would back up mods, meaning you can break the backup by running * the compiler twice) */ debugLog.Add("Skipping backup"); return; } debugLog.Add("Create debug dirs"); TerrainsXML.Save(Path.Combine(rootPath, "Backup/terrains.xml")); ModulesXML.Save(Path.Combine(rootPath, "Backup/eventModules.xml")); DBXML.Save(Path.Combine(rootPath, "Backup/database.xml")); debugLog.Add("Backup XML collections"); foreach (XMLStore x in Terrains) { x.data.Save(Path.Combine(rootPath, "Backup/Terrain Sources/" + x.fileName)); } foreach (XMLStore x in Modules) { x.data.Save(Path.Combine(rootPath, "Backup/" + x.fileName)); } foreach (XMLStore x in DB) { x.data.Save(Path.Combine(rootPath, "Backup/DataBase/" + x.fileName)); } debugLog.Add("Backup files"); }
public List <string> ParseData(List <string> mods, string path, string strictParam, string inferFromProto, string defaultTo) { //clear values TerrainsXML = null; ModulesXML = null; DBXML = null; Terrains = new List <XMLStore>(); Modules = new List <XMLStore>(); DB = new List <XMLStore>(); ProtoDB = new List <XElement>(); //set behavior bool StrictParamParse = strictParam == "Strict paramteter parsing"; bool InferFromProto = inferFromProto == "Infer from prototype"; RootPath = path; debugLog.Clear(); //load default data ReadXML(RootPath); //load mod data foreach (string dir in mods) { ReadXML(Path.Combine(path, dir)); } //copy scripts (overwrite existing, a mod should only ever overwrite the stock files, and even then only to add "partial") foreach (string dir in mods) { var dataPath = Path.Combine(path, dir); var copyTo = Path.Combine(RootPath, "Scripts"); dataPath = Path.Combine(dataPath, "Scripts"); try { foreach (string f in Directory.GetFiles(dataPath)) { string fileName = Path.GetFileName(f); string destFile = Path.Combine(copyTo, fileName); File.Copy(f, destFile, true); } } catch (FileNotFoundException) {//not an error, per se, just not used debugLog.Add("no scripts in mod"); } } //compile if (debugLog.Any(p => p.Contains("##error"))) { debugLog.Add("Compile aborted"); return(debugLog); } else { string[] lines; /*When saving, check if the XML is just a node (most data files have no header), then * save, then load as string and resave to strip them of BOM, so the game doesn't * throw it's toys out of the pram. */ XmlWriterSettings settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent = true, IndentChars = " " }; if (DBXML.Declaration != null) { DBXML.Save(Path.Combine(path, "database.xml")); } else { DBXML.Root.Save(Path.Combine(path, "database.xml")); } if (TerrainsXML.Declaration != null) { TerrainsXML.Save(Path.Combine(path, "terrains.xml")); } else { TerrainsXML.Root.Save(Path.Combine(path, "terrains.xml")); } if (ModulesXML.Declaration != null) { ModulesXML.Save(Path.Combine(path, "eventModules.xml")); } else { ModulesXML.Root.Save(Path.Combine(path, "eventModules.xml")); } lines = File.ReadAllLines(Path.Combine(path, "terrains.xml")); File.WriteAllLines(Path.Combine(path, "terrains.xml"), lines); lines = File.ReadAllLines(Path.Combine(path, "eventModules.xml")); File.WriteAllLines(Path.Combine(path, "eventModules.xml"), lines); lines = File.ReadAllLines(Path.Combine(path, "database.xml")); File.WriteAllLines(Path.Combine(path, "database.xml"), lines); foreach (XMLStore x in Terrains) { if (x.data.Declaration != null) { x.data.Save(Path.Combine(path, "Terrain Sources/" + x.fileName)); lines = File.ReadAllLines(Path.Combine(path, "Terrain Sources/" + x.fileName)); File.WriteAllLines(Path.Combine(path, "Terrain Sources/" + x.fileName), lines); } else { using (XmlWriter xw = XmlWriter.Create(Path.Combine(path, "Terrain Sources/" + x.fileName), settings)) { x.data.Save(xw); } lines = File.ReadAllLines(Path.Combine(path, "Terrain Sources/" + x.fileName)); File.WriteAllLines(Path.Combine(path, "Terrain Sources/" + x.fileName), lines); } } foreach (XMLStore x in Modules) { if (x.data.Declaration != null) { x.data.Save(Path.Combine(path, x.fileName)); lines = File.ReadAllLines(Path.Combine(path, x.fileName)); File.WriteAllLines(Path.Combine(path, x.fileName), lines); } else { using (XmlWriter xw = XmlWriter.Create(Path.Combine(path, x.fileName), settings)) { x.data.Save(xw); } lines = File.ReadAllLines(Path.Combine(path, x.fileName)); File.WriteAllLines(Path.Combine(path, x.fileName), lines); } } foreach (XMLStore x in DB) { if (x.data.Declaration != null) { var foo = x.data.Declaration; x.data.Save(Path.Combine(path, "DataBase/" + x.fileName)); lines = File.ReadAllLines(Path.Combine(path, "DataBase/" + x.fileName)); File.WriteAllLines(Path.Combine(path, "DataBase/" + x.fileName), lines); } else { using (XmlWriter xw = XmlWriter.Create(Path.Combine(path, "DataBase/" + x.fileName), settings)) { x.data.Save(xw); } lines = File.ReadAllLines(Path.Combine(path, "DataBase/" + x.fileName)); File.WriteAllLines(Path.Combine(path, "DataBase/" + x.fileName), lines); } } debugLog.Add("Files compiled"); debugLog.Add("Mod compile complete"); } return(debugLog); }
private void ReadXML(string dataPath, bool strictParamParse = false, bool inferFromProto = false, string defaultTo = "Default to merge")//path is root folder, either of game or of mod { //set paths for current dir (StreamingAssets, or @mod string TerrainsPath = Path.Combine(dataPath, "Terrain Sources"); //for some reason,terrains string ModulesPath = Path.Combine(dataPath, ""); //and DB are listed as filenames string DBPath = Path.Combine(dataPath, "DataBase"); //but modules as full paths. if (TerrainsXML == null && ModulesXML == null && DBXML == null) { /*LOAD DEFAULT ARRAYS*/ try { TerrainsXML = XDocument.Load($"{Path.Combine(dataPath, "terrains.xml")}"); ModulesXML = XDocument.Load($"{Path.Combine(dataPath, "eventModules.xml")}"); DBXML = XDocument.Load($"{Path.Combine(dataPath, "database.xml")}"); } catch (FileNotFoundException e) { //if files not found, notify user, and abort MessageBox.Show(e.Message); return; } /*LOAD DEFAULT FILES*/ foreach (XElement x in TerrainsXML.Element("TERRAINS").Elements()) { try { string name = x.Attribute("name").Value; Terrains.Add(new XMLStore(name, XDocument.Load($"{Path.Combine(TerrainsPath, name)}"))); debugLog.Add("load " + name); } catch (FileNotFoundException e) { debugLog.Add("##error: " + e.Message); } catch { debugLog.Add(TerrainsPath); debugLog.Add("##error in terrains.xml : element read error"); } } foreach (XElement x in ModulesXML.Element("ROOT").Elements()) { try { string name = x.Attribute("path").Value; if (!name.Contains("DEBUG")) { Modules.Add(new XMLStore(name, XDocument.Load($"{Path.Combine(ModulesPath, name)}"))); debugLog.Add("load " + name); } else { debugLog.Add("skip " + name); } } catch (FileNotFoundException e) { debugLog.Add("##error: " + e.Message); } catch { debugLog.Add(TerrainsPath); debugLog.Add("##error in eventModules.xml : element read error"); } } foreach (XElement x in DBXML.Element("DATA_BASE").Elements()) { try { string name = x.Attribute("name").Value; if (!name.Contains("Prototype")) { DB.Add(new XMLStore(name, XDocument.Load($"{Path.Combine(DBPath, name)}"))); debugLog.Add("load " + name); } else { //crawl through /DataBase/Proto for potential arrays XDocument newFile = XDocument.Load($"{Path.Combine(DBPath, name)}"); foreach (XElement y in newFile.Root.Elements()) { getArrays(y); } } } catch (FileNotFoundException e) { debugLog.Add("##error: " + e.Message); } catch { debugLog.Add(DBPath); debugLog.Add("##error in database.xml : name = null"); } } //back up files before altering Backup(dataPath); return; } else { /*LOAD MOD DATA*/ /*First load the index files from the mod folders, (if they're missing, log and continue). * Then read the indexes, then start reading new files, merging or adding to XMLStore * and main index as you go. */ XDocument newTerrainsXML = null; XDocument newModulesXML = null; XDocument newDBXML = null; debugLog.Add("Loading " + dataPath); try { newTerrainsXML = XDocument.Load($"{Path.Combine(dataPath, "terrains.xml")}"); debugLog.Add("terrains.xml loaded"); foreach (XElement x in newTerrainsXML.Root.Elements()) { string fileName; XDocument newFile; try {//get file, if it exists, else log and skip fileName = x.Attribute("name").Value; newFile = XDocument.Load($"{Path.Combine(TerrainsPath, fileName)}"); debugLog.Add("load " + fileName); } catch (FileNotFoundException e) { debugLog.Add("##error: " + e.Message + ", skipping"); continue; } catch { debugLog.Add(TerrainsPath); debugLog.Add("##error in terrains.xml : element read error"); continue; } if (!TerrainsXML.Root.Elements().Any(p => p.Attribute("name").Value != fileName)) {//if data files are not already listed, add them to the index and load file to file list XElement newEntry = new XElement("DEFINITION"); newEntry.SetAttributeValue("name", x.Attribute("name").Value); TerrainsXML.Root.Add(newEntry); Terrains.Add(new XMLStore(fileName, newFile)); } else {//else, update existing XMLStore oldFile = Terrains.Where(p => p.fileName == fileName).FirstOrDefault(); //note, oldfile and newfile are disparate object types List <string> output = oldFile.Update(newFile, strictParamParse, inferFromProto, defaultTo, ProtoDB); debugLog.AddRange(output); } } } catch (FileNotFoundException) {//not an error, per se, just not used debugLog.Add("terrains.xml not found"); } try { newModulesXML = XDocument.Load($"{Path.Combine(dataPath, "eventModules.xml")}"); debugLog.Add("eventModules.xml loaded"); foreach (XElement x in newModulesXML.Root.Elements()) { string fileName; XDocument newFile; try {//get file, if it exists, else log and skip fileName = x.Attribute("path").Value; newFile = XDocument.Load($"{Path.Combine(ModulesPath, fileName)}"); debugLog.Add("load " + fileName); } catch (FileNotFoundException e) { debugLog.Add("##error: " + e.Message + ", skipping"); continue; } catch { debugLog.Add(ModulesPath); debugLog.Add("##error in eventModules.xml : element read error"); continue; } if (!ModulesXML.Root.Elements().Any(p => p.Attribute("path").Value == fileName)) {//if data files are not already listed, add them to the index and load file to file list XElement newEntry = new XElement("FILE"); newEntry.SetAttributeValue("path", x.Attribute("path").Value); ModulesXML.Root.Add(newEntry); Modules.Add(new XMLStore(fileName, newFile)); } else {//else, update existing XMLStore oldFile = Modules.Where(p => p.fileName == fileName).FirstOrDefault(); //note, oldfile and newfile are disparate object types List <string> output = oldFile.Update(newFile, strictParamParse, inferFromProto, defaultTo, ProtoDB); debugLog.AddRange(output); } } } catch (FileNotFoundException) {//not an error, per se, just not used debugLog.Add("eventModules.xml not found"); } try { newDBXML = XDocument.Load($"{Path.Combine(dataPath, "database.xml")}"); debugLog.Add("database.xml loaded"); foreach (XElement x in newDBXML.Root.Elements()) { string fileName; XDocument newFile; try {//get file, if it exists, else log and skip fileName = x.Attribute("name").Value; newFile = XDocument.Load($"{Path.Combine(DBPath, fileName)}"); debugLog.Add("load " + fileName); } catch (FileNotFoundException e) { debugLog.Add("##error: " + e.Message + ", skipping"); continue; } catch { debugLog.Add(ModulesPath); debugLog.Add("##error in database.xml : element read error"); continue; } if (!DBXML.Root.Elements().Any(p => p.Attribute("name").Value != fileName)) {//if data files are not already listed, add them to the index and load file to file list XElement newEntry = new XElement("DATA"); newEntry.SetAttributeValue("name", x.Attribute("name").Value); ModulesXML.Root.Add(newEntry); Modules.Add(new XMLStore(fileName, newFile)); } else {//else, update existing XMLStore oldFile = DB.Where(p => p.fileName == fileName).FirstOrDefault(); //note, oldfile and newfile are disparate object types List <string> output = oldFile.Update(newFile, strictParamParse, inferFromProto, defaultTo, ProtoDB); debugLog.AddRange(output); } } } catch (FileNotFoundException) {//not an error, per se, just not used debugLog.Add("database.xml not found"); } } }