private void bw_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker; FileManager HellgateFileManager; string cookingMessage = "Cooking {0}..."; string path = RevivalMod.DataPath; string[] excelToCook = null; string[] stringsToCook = null; string[] xmlToCook = null; string[] filesToPack = null; // Step One: Initialize the FileManager toolStripStatusLabel.Text = "Initializing the Hellgate File Manager..."; HellgateFileManager = new FileManager(Config.HglDir); if (HellgateFileManager.HasIntegrity == false) { Console.WriteLine("Could not initialize the File Manager, Integrity check failed."); e.Cancel = true; string caption = "Integrity Error"; string message = "Could not initialize the File Manager. Check Hellgate London is not running and that the installation is not corrupt."; MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // Check if the user wants to cancel. if (backgroundWorker.CancellationPending) { e.Cancel = true; return; } // Step Two: Revert modifications automatically if flagged in the mod install xml. if (RevivalMod.Data.Modifications.DoRevert == true) { DialogResult dialogResult = DialogResult.Retry; while (dialogResult == DialogResult.Retry) { toolStripStatusLabel.Text = "Reverting previous Hellgate London modifications..."; bool error = Modification.RemoveModifications(HellgateFileManager); if (error == true) { string caption = "Reversion Error"; string message = "One or more errors occurred while reverting Hellgate London modifications. Check Hellgate London is not running and the files are not in use. It is highly recommended you ammend this before continuing, even if it means reinstalling the game."; dialogResult = MessageBox.Show(message, caption, MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error); if (dialogResult == DialogResult.Abort) { e.Cancel = true; return; } } else { break; } } toolStripStatusLabel.Text = "Reloading the Hellgate File Manager..."; HellgateFileManager.Reload(); } // Check if the user wants to cancel. if (backgroundWorker.CancellationPending) { e.Cancel = true; return; } // Load the Excel tables toolStripStatusLabel.Text = "Caching the Hellgate London excel tables..."; HellgateFileManager.LoadTableFiles(); // Step Three: Cook Excel, String and XML files. // Search for files to cook excelToCook = Hellpack.SearchForExcelFiles(path); stringsToCook = Hellpack.SearchForStringFiles(path); xmlToCook = Hellpack.SearchForXmlFiles(path); if (excelToCook != null) { for (int i = 0; i < excelToCook.Length; i++) { // Check if the user wants to cancel. if (backgroundWorker.CancellationPending) { e.Cancel = true; return; } string epath = excelToCook[i]; string hglPath = epath.Substring(epath.IndexOf("data"), epath.Length - epath.IndexOf("data")); string report = String.Format(cookingMessage, hglPath); toolStripStatusLabel.Text = report; Hellpack.CookExcelFile(epath); } } if (stringsToCook != null) { for (int i = 0; i < stringsToCook.Length; i++) { // Check if the user wants to cancel. if (backgroundWorker.CancellationPending) { e.Cancel = true; return; } string epath = stringsToCook[i]; string hglPath = epath.Substring(epath.IndexOf("data"), epath.Length - epath.IndexOf("data")); string report = String.Format(cookingMessage, hglPath); toolStripStatusLabel.Text = report; Hellpack.CookStringFile(epath); } } if (xmlToCook != null) { for (int i = 0; i < xmlToCook.Length; i++) { // Check if the user wants to cancel. if (backgroundWorker.CancellationPending) { e.Cancel = true; return; } string epath = xmlToCook[i]; string hglPath = epath.Substring(epath.IndexOf("data"), epath.Length - epath.IndexOf("data")); string report = String.Format(cookingMessage, hglPath); toolStripStatusLabel.Text = report; Hellpack.CookXmlFile(epath, HellgateFileManager); } } // Step Four: Pack the base idx/dat. filesToPack = Hellpack.SearchForFilesToPack(path, true); toolStripStatusLabel.Text = String.Format("Packing {0}...", RevivalMod.Data.Modifications.ID + ".idx"); string hglDataPath = Path.Combine(Config.HglDir, "data"); string modDatPath = Path.Combine(hglDataPath, RevivalMod.Data.Modifications.ID) + ".idx"; bool packResult = Hellpack.PackDatFile(filesToPack, modDatPath, true); if (packResult == false) { HellgateFileManager.Dispose(); string caption = "Fatal Error"; string message = "An error occurred while packing the modification."; MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } // Step Five: Apply scripts. Scripts are only applied if they are checked or are hidden. if (optionalCheckedListBox.CheckedItems.Count != 0 || RevivalMod.Data.Modifications.Scripts.Where(s => s.Type == "hidden").Any() == true) { List <Script> scriptList = new List <Script>(); // Append optional list foreach (Script script in optionalCheckedListBox.CheckedItems) { scriptList.Add(script); } // Append hidden list foreach (Script script in RevivalMod.Data.Modifications.Scripts.Where(s => s.Type == "hidden")) { scriptList.Add(script); } // Reinitalize the File Manager HellgateFileManager.Reload(); HellgateFileManager.LoadTableFiles(); string indexPath = Path.Combine(Config.HglDir, "data", RevivalMod.Data.Modifications.ID + "_125.idx"); IndexFile indexFile = new IndexFile(indexPath); // Apply the scripts List <string> modifiedTables = new List <string>(); foreach (Script script in scriptList) { // Interface stuff toolStripStatusLabel.Text = String.Format("Applying {0} script...", script.Title); if (script.Extraction != null) { toolStripStatusLabel.Text = "MP conversion in progress, this may between 5 and 10 minutes."; } // The script Modification.ApplyScript(script, ref HellgateFileManager); if (script.Tables != null) { foreach (Script.Table table in script.Tables) { string tableID = table.ID.ToUpper(); if (modifiedTables.Contains(tableID) == false) { modifiedTables.Add(tableID); } } } // Copy files if any if (String.IsNullOrEmpty(script.ID) == false) { string optionalPath = Path.Combine(path, "optional", script.ID); if (Directory.Exists(optionalPath) == false) { continue; } string[] fileList = Directory.GetFiles(optionalPath, "*", SearchOption.AllDirectories); if (fileList == null) { continue; } if (fileList.Length == 0) { continue; } foreach (string filePath in fileList) { string relativePath = filePath.Replace(optionalPath + "\\", ""); string directory = Path.GetDirectoryName(relativePath) + "\\"; string fileName = Path.GetFileName(relativePath); byte[] fbuffer = null; try { fbuffer = File.ReadAllBytes(filePath); } catch (Exception ex) { ExceptionLogger.LogException(ex); continue; } indexFile.AddFile(directory, fileName, fbuffer, DateTime.Now); } } } // Repack the modified Tables. // These go in their own idx/dat under the same name as the base modification with the string _125 appended. foreach (string tableID in modifiedTables) { DataFile dataTable = HellgateFileManager.DataFiles[tableID]; byte[] ebuffer = dataTable.ToByteArray(); string fileName = Path.GetFileName(dataTable.FilePath); string fileDir = Path.GetDirectoryName(dataTable.FilePath) + "\\"; indexFile.AddFile(fileDir, fileName, ebuffer, DateTime.Now); } if (indexFile.Count > 0) { // Write the index byte[] ibuffer = indexFile.ToByteArray(); Crypt.Encrypt(ibuffer); try { File.WriteAllBytes(indexPath, ibuffer); HellgateFileManager.Dispose(); indexFile.EndDatAccess(); indexFile.Dispose(); } catch (Exception ex) { ExceptionLogger.LogException(ex); HellgateFileManager.Dispose(); indexFile.EndDatAccess(); indexFile.Dispose(); string caption = "Fatal Error"; string message = "An error occurred while packing the optional modification."; MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } } string msgCaption = "Success"; string msgDescription = "Modification successfully installed!"; MessageBox.Show(msgDescription, msgCaption, MessageBoxButtons.OK, MessageBoxIcon.Information); }
/// <summary> /// /// </summary> /// <param name="script"></param> /// <param name="fileManager"></param> /// <returns></returns> public static bool ApplyScript(Script script, ref FileManager fileManager) { #region Table Modifications if (script.Tables != null) { foreach (Script.Table table in script.Tables) { string tableID = table.ID.ToUpper(); if (fileManager.DataFiles.ContainsKey(tableID) == false) { Console.WriteLine(String.Format("Error: The table id is incorrect or does not exist: {0} ", tableID)); continue; } ExcelFile dataTable = fileManager.DataFiles[tableID] as ExcelFile; if (dataTable == null) { Console.WriteLine(String.Format("Error: Could not open {0} due to null reference.", tableID)); continue; } foreach (Script.Table.Entity entity in table.Entities) { foreach (Script.Table.Entity.Attribute attribute in entity.Attributes) { string whereColumn = String.Empty; string[] whereValue = null; int step = 0; int min = 1; int max = 0; int last = 0; //for recursive function string function; int[] list; try { //determine the range if (entity.ID.Contains(",")) { string[] explode = entity.ID.Split(','); list = new int[explode.Length]; for (int i = 0; i < list.Length; i++) { list[i] = Convert.ToInt32(explode[i]); } } else { if (entity.ID.Contains("*")) { min = 0; max = dataTable.Count - 1; } else if (entity.ID.Contains("-")) { int idx = entity.ID.IndexOf('-'); int len = entity.ID.Length - idx - 1; min = Convert.ToInt32(entity.ID.Substring(0, idx)); max = Convert.ToInt32(entity.ID.Substring(idx + 1, len)); } else { min = Convert.ToInt32(entity.ID); max = Convert.ToInt32(entity.ID); } int listlen = max - min + 1; list = new int[listlen]; int i = 0; for (int row = min; row <= max; row++) { list[i++] = row; } } //check for where condition if (attribute.Where != null) { int equalsIndex = attribute.Where.IndexOf('='); if (equalsIndex == -1) { Console.WriteLine("Bad syntax in where condition."); return(false); } whereColumn = attribute.Where.Substring(0, equalsIndex); string whereValueString = attribute.Where.Substring(equalsIndex + 1, attribute.Where.Length - equalsIndex - 1); if (whereValueString.Contains('|')) { whereValue = whereValueString.Split('|'); } else { whereValue = new string[] { whereValueString }; } } //determine function if (attribute.Bit != null) { function = "bitwise"; } else if (attribute.Operation == null) { function = "replace"; } else if (attribute.Operation.Contains("*")) { function = "multiply"; } else if (attribute.Operation.Contains("/")) { function = "divide"; } else if (attribute.Operation.Contains("+")) { string s = attribute.Operation.Remove(0); step = Convert.ToInt32(s); function = "recursive"; } else if (attribute.Operation.Contains("-")) { step = Convert.ToInt32(attribute.Operation); function = "recursive"; } else { continue; // syntax error } //main loop, alters the dataset foreach (int row in list) { object obj = null; string col = attribute.ID; Type type = dataTable.DataType.GetField(col).FieldType; Object currentValue = dataTable.DataType.GetField(col).GetValue(dataTable.Rows[row]); if (String.IsNullOrEmpty(whereColumn) == false) { Type typeWhere = dataTable.DataType.GetField(whereColumn).FieldType; Object currentValueWhere = dataTable.DataType.GetField(whereColumn).GetValue(dataTable.Rows[row]); if (whereValue.Where(val => FileTools.StringToObject(val, typeWhere).Equals(currentValueWhere)).Any() == false) { continue; } } switch (function) { case "replace": obj = FileTools.StringToObject(attribute.Data, type); break; case "multiply": if (type.Equals(typeof(int))) { obj = (int)currentValue * Convert.ToInt32(attribute.Data); } else if (type.Equals(typeof(float))) { obj = (float)currentValue * Convert.ToSingle(attribute.Data); } break; case "divide": if (type.Equals(typeof(int))) { obj = (int)currentValue / Convert.ToInt32(attribute.Data); } else if (type.Equals(typeof(float))) { obj = (float)currentValue / Convert.ToSingle(attribute.Data); } break; case "bitwise": uint bit = (uint)Enum.Parse(type, attribute.Bit, true); uint mask = (uint)currentValue; bool flick = Convert.ToBoolean(attribute.Data); bool current = (mask & bit) > 0; if (flick != current) { obj = mask ^= bit; } else { obj = mask; } break; case "recursive": if (row.Equals(min)) //first time only { if (type.Equals(typeof(int))) { obj = Convert.ToInt32(attribute.Data); last = (int)obj; } } else { last += step; obj = last; } break; } dataTable.DataType.GetField(col).SetValue(dataTable.Rows[row], obj); } } catch (Exception ex) { ExceptionLogger.LogException(ex); return(false); } } } fileManager.DataFiles[tableID] = dataTable; } } #endregion #region Extraction Script if (script.Extraction != null) { string sourcePath = Path.Combine(fileManager.HellgateDataPath, script.Extraction.Source + ".idx"); string destinationPath = sourcePath.Replace(script.Extraction.Source, script.Extraction.Destination); // Check source index exists if (File.Exists(sourcePath) == false) { return(false); } // Try open the index file //byte[] sbuffer; PackFile sourceIndex = new IndexFile(sourcePath); PackFile destinationIndex = new IndexFile(destinationPath); try { sourceIndex.ParseFileBytes(File.ReadAllBytes(sourcePath)); } catch (Exception ex) { Console.WriteLine("Error: {0} filed to load. Make sure you have run Hellgate London at least once (MP version for MP files) before installating this modification.", sourceIndex); ExceptionLogger.LogException(ex); return(false); } sourceIndex.BeginDatReading(); // Extract each path/file foreach (PackFileEntry fileEntry in sourceIndex.Files) { if (!script.Extraction.paths.Where(p => Regex.IsMatch(fileEntry.Path, p.Replace(@"\", @"\\"))).Any()) { continue; } byte[] fileBytes = sourceIndex.GetFileBytes(fileEntry); //if (fileEntry.FileNameString.Contains(XmlCookedFile.FileExtention)) //{ // try // { // XmlCookedFile xmlCookedFile = new XmlCookedFile(); // xmlCookedFile.Uncook(fileBytes); // XmlCookedFile reCooked = new XmlCookedFile(); // fileBytes = reCooked.CookXmlDocument(xmlCookedFile.XmlDoc); // } // catch (Exception) { } //} destinationIndex.AddFile(fileEntry.Directory, fileEntry.Name, fileBytes); } // Write the file byte[] ibuffer = destinationIndex.ToByteArray(); Crypt.Encrypt(ibuffer); try { File.WriteAllBytes(destinationIndex.Path, ibuffer); } catch (Exception ex) { ExceptionLogger.LogException(ex); return(false); } finally { sourceIndex.EndDatAccess(); sourceIndex.Dispose(); destinationIndex.Dispose(); } } #endregion return(true); }