public static void Main(string[] args) { Options options = null; try { options = CommandLine.Parse <Options>(); } catch (CommandLineException exception) { Console.WriteLine(exception.ArgumentHelp.Message); Console.WriteLine(); Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth)); #if DEBUG Console.ReadLine(); #endif return; } string outputFile = options.Output != null ? options.Output : Path.ChangeExtension(options.Input, ".le_strings"); Console.WriteLine("Packing {0} and creating {1}...", options.Input, outputFile); XDocument xml = null; using (Stream s = File.OpenRead(options.Input)) { xml = XDocument.Load(s); } var stringsNode = xml.Descendants("Strings").First(); string languageString = stringsNode.Attribute("Language").Value; string gameString = stringsNode.Attribute("Game").Value; Language language = LanguageUtility.GetLanguageFromCode(languageString); IGameInstance instance = GameInstance.GetFromString(gameString); StringFile stringFile = new StringFile(language, instance); var stringNodes = stringsNode.Descendants("String"); foreach (var stringNode in stringNodes) { uint hash; var nameAttribute = stringNode.Attribute("Name"); if (nameAttribute != null) { hash = Hashes.CrcVolition(nameAttribute.Value); } else { hash = uint.Parse(stringNode.Attribute("Hash").Value, System.Globalization.NumberStyles.HexNumber); } string value = stringNode.Value; if (stringFile.ContainsKey(hash)) { Console.WriteLine("You are attempting to add a duplicate key to the strings file."); Console.WriteLine("Name: \"{0}\", Hash: {1}, Value: {2}", nameAttribute != null ? nameAttribute.Value : "", hash, value); Console.WriteLine("Other value: {0}", stringFile.GetString(hash)); return; } stringFile.AddString(hash, value); } using (Stream s = File.Create(outputFile)) { stringFile.Save(s); } Console.WriteLine("Done."); #if DEBUG Console.ReadLine(); #endif }
static void Main(string[] args) { Options options = null; try { options = CommandLine.Parse <Options>(); } catch (CommandLineException exception) { Console.WriteLine(exception.ArgumentHelp.Message); Console.WriteLine(); Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth)); #if DEBUG Console.ReadLine(); #endif return; } if (options.Output == null) { options.Output = options.NewName; } string outputFolder = options.Output; Directory.CreateDirectory(outputFolder); IGameInstance sriv = GameInstance.GetFromSteamId(GameSteamID.SaintsRowIV); LoadStrings(sriv); IAssetAssemblerFile newAsm; using (Stream newAsmStream = File.OpenRead(Path.Combine("templates", "template_customize_item.asm_pc"))) { newAsm = AssetAssemblerFile.FromStream(newAsmStream); } XDocument customizationItem = null; using (Stream itemsTemplateStream = File.OpenRead(Path.Combine("templates", "template_customization_items.xtbl"))) { customizationItem = XDocument.Load(itemsTemplateStream); } var customizationItemTable = customizationItem.Descendants("Table").First(); XElement itemNode = FindCustomizationItem(options.Source, sriv); if (itemNode == null) { Console.WriteLine("Couldn't find {0}.", options.Source); #if DEBUG Console.ReadLine(); #endif return; } string itemName = itemNode.Element("Name").Value; itemNode.Element("Name").Value = options.NewName; string originalDisplayName = itemNode.Element("DisplayName").Value; uint originalStringCrc = Hashes.CrcVolition(originalDisplayName); string newDisplayName = "DUPLICATED_" + options.NewName.ToUpperInvariant(); itemNode.Element("DisplayName").Value = newDisplayName; List <string> str2Names = new List <string>(); bool found = false; var dlcElement = itemNode.Element("Is_DLC"); if (dlcElement != null) { string isDLCString = dlcElement.Value; // Remove Is_DLC element so DLC items show up in SRIV dlcElement.Remove(); } var wearOptionsNode = itemNode.Element("Wear_Options"); int wearOption = 0; foreach (var wearOptionNode in wearOptionsNode.Descendants("Wear_Option")) { var meshInformationNode = wearOptionNode.Element("Mesh_Information"); var maleMeshFilenameNode = meshInformationNode.Element("Male_Mesh_Filename"); var filenameNode = maleMeshFilenameNode.Element("Filename"); string maleMeshFilename = filenameNode.Value; string newMaleMeshFilename = (wearOption == 0) ? String.Format("cm_{0}.cmeshx", options.NewName) : String.Format("cm_{0}_{1}.cmeshx", options.NewName, wearOption); filenameNode.Value = newMaleMeshFilename; var femaleMeshFilenameNode = meshInformationNode.Element("Female_Mesh_Filename"); filenameNode = femaleMeshFilenameNode.Element("Filename"); string femaleMeshFilename = filenameNode.Value; string newFemaleMeshFilename = (wearOption == 0) ? String.Format("cf_{0}.cmeshx", options.NewName) : String.Format("cf_{0}_{1}.cmeshx", options.NewName, wearOption); filenameNode.Value = newFemaleMeshFilename; Console.WriteLine("Mapping mesh {0} -> {1}", maleMeshFilename, newMaleMeshFilename); Console.WriteLine("Mapping mesh {0} -> {1}", femaleMeshFilename, newFemaleMeshFilename); string clothSimFilename = null; var clothSimFilenameNode = meshInformationNode.Element("Cloth_Sim_Filename"); if (clothSimFilenameNode != null) { filenameNode = clothSimFilenameNode.Element("Filename"); string xmlClothSimFilename = filenameNode.Value; clothSimFilename = Path.ChangeExtension(xmlClothSimFilename, ".sim_pc"); string newClothSimFilename = (wearOption == 0) ? String.Format("cm_{0}.simx", options.NewName) : String.Format("cm_{0}_{1}.simx", options.NewName, wearOption); filenameNode.Value = newClothSimFilename; Console.WriteLine("Mapping cloth sim {0} -> {1}", xmlClothSimFilename, newClothSimFilename); } var variantNodes = itemNode.Element("Variants").Descendants("Variant"); foreach (var variantNode in variantNodes) { var meshVariantInfoNode = variantNode.Element("Mesh_Variant_Info"); var variantIdNode = meshVariantInfoNode.Element("VariantID"); uint variantId = uint.Parse(variantIdNode.Value); int crc = Hashes.CustomizationItemCrc(itemName, maleMeshFilename, variantId); string maleStr2 = String.Format("custmesh_{0}.str2_pc", crc); string femaleStr2 = String.Format("custmesh_{0}f.str2_pc", crc); int newCrc = Hashes.CustomizationItemCrc(options.NewName, newMaleMeshFilename, variantId); string newMaleStr2 = String.Format("custmesh_{0}.str2_pc", newCrc); string newFemaleStr2 = String.Format("custmesh_{0}f.str2_pc", newCrc); string newMaleName = (wearOption == 0) ? String.Format("cm_{0}", options.NewName) : String.Format("cm_{0}_{1}", options.NewName, wearOption); string newFemaleName = (wearOption == 0) ? String.Format("cf_{0}", options.NewName) : String.Format("cf_{0}_{1}", options.NewName, wearOption); bool foundMale = ClonePackfile(sriv, maleStr2, clothSimFilename, options.Output, newAsm, itemName, newMaleName, Path.Combine(outputFolder, newMaleStr2)); bool foundFemale = ClonePackfile(sriv, femaleStr2, clothSimFilename, options.Output, newAsm, itemName, newFemaleName, Path.Combine(outputFolder, newFemaleStr2)); if (foundMale || foundFemale) { found = true; } } wearOption++; } if (found) { customizationItemTable.Add(itemNode); } using (Stream xtblOutStream = File.Create(Path.Combine(outputFolder, "customization_items.xtbl"))) { XmlWriterSettings settings = new XmlWriterSettings(); settings.OmitXmlDeclaration = true; settings.Encoding = new UTF8Encoding(false); settings.NewLineChars = "\r\n"; settings.Indent = true; settings.IndentChars = "\t"; using (XmlWriter writer = XmlWriter.Create(xtblOutStream, settings)) { customizationItem.Save(writer); } } using (Stream asmOutStream = File.Create(Path.Combine(outputFolder, "customize_item.asm_pc"))) { newAsm.Save(asmOutStream); } string stringXmlFolder = Path.Combine(outputFolder, "stringxml"); Directory.CreateDirectory(stringXmlFolder); foreach (var pair in languageStrings) { Language language = pair.Key; Dictionary <uint, string> strings = pair.Value; StringFile file = new StringFile(language, sriv); string newString = "CLONE: " + options.NewName; if (strings.ContainsKey(originalStringCrc)) { string originalString = strings[originalStringCrc]; newString = "CLONE: " + originalString; } else { Console.WriteLine("Warning: original language string could not be found for {0}.", language); } file.AddString(newDisplayName, newString); string newFilename = Path.Combine(outputFolder, String.Format("{0}_{1}.le_strings", options.NewName, LanguageUtility.GetLanguageCode(language))); string newXmlFilename = Path.Combine(stringXmlFolder, String.Format("{0}_{1}.xml", options.NewName, LanguageUtility.GetLanguageCode(language))); using (Stream s = File.Create(newFilename)) { file.Save(s); } XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = "\t"; settings.NewLineChars = "\r\n"; using (XmlWriter xml = XmlTextWriter.Create(newXmlFilename, settings)) { xml.WriteStartDocument(); xml.WriteStartElement("Strings"); xml.WriteAttributeString("Language", language.ToString()); xml.WriteAttributeString("Game", sriv.Game.ToString()); xml.WriteStartElement("String"); xml.WriteAttributeString("Name", newDisplayName); xml.WriteString(newString); xml.WriteEndElement(); // String xml.WriteEndElement(); // Strings xml.WriteEndDocument(); } } Console.WriteLine("Finished cloning customization item {0} to {1}!", options.Source, options.NewName); #if DEBUG Console.ReadLine(); #endif }
public static void Main(string[] args) { Options options = null; try { options = CommandLine.Parse<Options>(); } catch (CommandLineException exception) { Console.WriteLine(exception.ArgumentHelp.Message); Console.WriteLine(); Console.WriteLine(exception.ArgumentHelp.GetHelpText(Console.BufferWidth)); #if DEBUG Console.ReadLine(); #endif return; } string outputFile = options.Output != null ? options.Output : Path.ChangeExtension(options.Input, ".le_strings"); Console.WriteLine("Packing {0} and creating {1}...", options.Input, outputFile); XDocument xml = null; using (Stream s = File.OpenRead(options.Input)) { xml = XDocument.Load(s); } var stringsNode = xml.Descendants("Strings").First(); string languageString = stringsNode.Attribute("Language").Value; string gameString = stringsNode.Attribute("Game").Value; Language language = LanguageUtility.GetLanguageFromCode(languageString); IGameInstance instance = GameInstance.GetFromString(gameString); var stringNodes = stringsNode.Descendants("String"); UInt16 bucketCount = (UInt16)(stringNodes.Count() / 5); if (bucketCount < 32) bucketCount = 32; else if (bucketCount < 64) bucketCount = 64; else if (bucketCount < 128) bucketCount = 128; else if (bucketCount < 256) bucketCount = 256; else if (bucketCount < 512) bucketCount = 512; else bucketCount = 1024; StringFile stringFile = new StringFile(bucketCount, language, instance); foreach (var stringNode in stringNodes) { uint hash; var nameAttribute = stringNode.Attribute("Name"); if (nameAttribute != null) { hash = Hashes.CrcVolition(nameAttribute.Value); } else { hash = uint.Parse(stringNode.Attribute("Hash").Value, System.Globalization.NumberStyles.HexNumber); } string value = stringNode.Value; if (stringFile.ContainsKey(hash)) { Console.WriteLine("You are attempting to add a duplicate key to the strings file."); Console.WriteLine("Name: \"{0}\", Hash: {1}, Value: {2}", nameAttribute != null ? nameAttribute.Value : "", hash, value); Console.WriteLine("Other value: {0}", stringFile.GetString(hash)); return; } stringFile.AddString(hash, value); } using (Stream s = File.Create(outputFile)) { stringFile.Save(s); } Console.WriteLine("Done."); #if DEBUG Console.ReadLine(); #endif }