static IContainer FindContainer(IGameInstance sriv, string containerName) { string[] asmNames = new string[] { "customize_item.asm_pc", "dlc1_customize_item.asm_pc", "dlc2_customize_item.asm_pc", "dlc3_customize_item.asm_pc", "dlc4_customize_item.asm_pc", "dlc5_customize_item.asm_pc", "dlc6_customize_item.asm_pc" }; string name = Path.GetFileNameWithoutExtension(containerName); foreach (string asmName in asmNames) { using (Stream s = sriv.OpenPackfileFile(asmName)) { IAssetAssemblerFile asm = AssetAssemblerFile.FromStream(s); foreach (var container in asm.Containers) { if (container.Name == name) { return(container); } } } } return(null); }
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)); Console.ReadLine(); return; } if (options.Source == null) { string srtt = ThomasJepp.SaintsRow.Utility.GetGamePath(GameSteamID.SaintsRowTheThird); string sriv = ThomasJepp.SaintsRow.Utility.GetGamePath(GameSteamID.SaintsRowIV); string srgooh = ThomasJepp.SaintsRow.Utility.GetGamePath(GameSteamID.SaintsRowGatOutOfHell); int gameCount = 0, srttNum = 0, srivNum = 0, srgoohNum = 0; Console.WriteLine("Detected the following games:"); if (srtt != null) { gameCount++; srttNum = gameCount; Console.WriteLine("{0}. Saints Row The Third: {1}", gameCount, srtt); } if (sriv != null) { gameCount++; srivNum = gameCount; Console.WriteLine("{0}. Saints Row IV: {1}", gameCount, sriv); } if (srgooh != null) { gameCount++; srgoohNum = gameCount; Console.WriteLine("{0}. Saints Row Gat Out Of Hell: {1}", gameCount, srgooh); } if (gameCount == 0) { Console.WriteLine("Couldn't find any installed games?"); Console.WriteLine(); Console.WriteLine("Press enter to exit."); Console.ReadLine(); return; } Console.WriteLine(); while (true) { Console.Write("Which game do you want to update? (enter the number) "); ConsoleKeyInfo input = Console.ReadKey(); Console.WriteLine(); Console.WriteLine(); if (input.Key == ConsoleKey.D1 || input.Key == ConsoleKey.NumPad1) { if (srttNum == 1) { options.Source = srtt; Console.WriteLine("Updating Saints Row: The Third files."); } else if (srivNum == 1) { options.Source = sriv; Console.WriteLine("Updating Saints Row IV files."); } else if (srgoohNum == 1) { options.Source = srgooh; Console.WriteLine("Updating Saints Row: Gat Out Of Hell files."); } } else if (input.Key == ConsoleKey.D2 || input.Key == ConsoleKey.NumPad2) { if (srttNum == 2) { options.Source = srtt; Console.WriteLine("Updating Saints Row: The Third files."); } else if (srivNum == 2) { options.Source = sriv; Console.WriteLine("Updating Saints Row IV files."); } else if (srgoohNum == 2) { options.Source = srgooh; Console.WriteLine("Updating Saints Row: Gat Out Of Hell files."); } } else if (input.Key == ConsoleKey.D3 || input.Key == ConsoleKey.NumPad3) { if (srttNum == 3) { options.Source = srtt; Console.WriteLine("Updating Saints Row: The Third files."); } else if (srivNum == 3) { options.Source = sriv; Console.WriteLine("Updating Saints Row IV files."); } else if (srgoohNum == 3) { options.Source = srgooh; Console.WriteLine("Updating Saints Row: Gat Out Of Hell files."); } } if (options.Source != null) { break; } } } if (options.Source == null) { Console.WriteLine("Couldn't find a Saints Row folder?"); Console.WriteLine(); Console.WriteLine("Press enter to exit."); Console.ReadLine(); return; } string str2Dir = options.Source; //if (Directory.Exists(Path.Combine(options.Source, "mods"))) //str2Dir = Path.Combine(options.Source, "mods"); string[] str2Paths = Directory.GetFiles(str2Dir, "*.str2_pc"); List <string> str2Files = new List <string>(); foreach (string str2Path in str2Paths) { str2Files.Add(Path.GetFileName(str2Path)); } if (str2Files.Count == 0) { Console.WriteLine("No str2_pc files found - no update needed."); Console.WriteLine(); Console.WriteLine("Press enter to exit."); Console.ReadLine(); return; } string packfileCache = Path.Combine(options.Source, "packfiles", "pc", "cache"); Dictionary <string, IAssetAssemblerFile> asmsToSave = new Dictionary <string, IAssetAssemblerFile>(); string[] packfiles = Directory.GetFiles(packfileCache, "*.vpp_pc"); int vppCount = 0; foreach (string packfilePath in packfiles) { vppCount++; Console.WriteLine("[{0}/{1}] Checking {2}...", vppCount, packfiles.Length, Path.GetFileName(packfilePath)); using (Stream stream = File.OpenRead(packfilePath)) { using (IPackfile packfile = Packfile.FromStream(stream, false)) { foreach (var packedFile in packfile.Files) { if (Path.GetExtension(packedFile.Name) != ".asm_pc") { continue; } using (Stream asmStream = packedFile.GetStream()) { IAssetAssemblerFile asm = AssetAssemblerFile.FromStream(asmStream); foreach (var container in asm.Containers) { string containerName = Path.ChangeExtension(container.Name, ".str2_pc"); if (str2Files.Contains(containerName)) { if (!asmsToSave.ContainsKey(packedFile.Name)) { asmsToSave.Add(packedFile.Name, asm); } Console.Write(" - Updating {0} - {1}...", packedFile.Name, containerName); using (Stream str2Stream = File.OpenRead(Path.Combine(str2Dir, containerName))) { using (IPackfile str2 = Packfile.FromStream(str2Stream, true)) { str2.Update(container); } } Console.WriteLine(" done."); } } } } } } } Console.WriteLine(); Console.WriteLine("Writing updated asm_pc files..."); int count = 0; foreach (var asmPair in asmsToSave) { count++; Console.Write("[{0}/{1}] Saving {2}...", count, asmsToSave.Count, asmPair.Key); string outPath = Path.Combine(str2Dir, asmPair.Key); using (Stream outStream = File.Create(outPath)) { asmPair.Value.Save(outStream); } Console.WriteLine(" done."); } Console.WriteLine("Done."); Console.WriteLine(); Console.WriteLine("Press enter to exit."); Console.ReadLine(); }
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 }
private void DoBuild(object o) { DisableButton(); BuildOptions options = (BuildOptions)o; SetProgressBarSettings(0, 100, 1, ProgressBarStyle.Marquee); IPackfile packfile = null; switch (options.Game) { case GameSteamID.SaintsRow2: { packfile = new Packfiles.Version04.Packfile(); break; } case GameSteamID.SaintsRowIV: case GameSteamID.SaintsRowGatOutOfHell: { packfile = new Packfiles.Version0A.Packfile(Path.GetExtension(options.Destination) == ".str2_pc"); break; } default: { throw new NotImplementedException(); } } IAssetAssemblerFile asm = null; AssetAssembler.IContainer thisContainer = null; SetText("Setting up..."); if (Path.GetExtension(options.Destination) == ".str2_pc") { packfile.IsCondensed = true; packfile.IsCompressed = true; if (options.Asm != null) { using (Stream asmStream = File.OpenRead(options.Asm)) { asm = AssetAssemblerFile.FromStream(asmStream); } } } else { string filename = Path.GetFileName(options.Destination); if (OriginalPackfileInfo.OptionsList.ContainsKey(options.Game) && OriginalPackfileInfo.OptionsList[options.Game].ContainsKey(filename)) { var vppOptions = OriginalPackfileInfo.OptionsList[options.Game][filename]; packfile.IsCondensed = vppOptions.Condense; packfile.IsCompressed = vppOptions.Compress; } } if (asm != null) { string containerName = Path.GetFileNameWithoutExtension(options.Destination); foreach (var container in asm.Containers) { string tempContainerName = Path.GetFileNameWithoutExtension(container.Name); if (tempContainerName == containerName) { thisContainer = container; break; } } if (thisContainer == null) { SetText("Couldn't find a container called {0} in the selected asm_pc file!", containerName); SetProgressBarSettings(0, 100, 0, ProgressBarStyle.Continuous); EnableButton(); return; } SetProgressBarSettings(0, thisContainer.PrimitiveCount, 0, ProgressBarStyle.Continuous); SetText("Adding files..."); foreach (IPrimitive primitive in thisContainer.Primitives) { string primitiveFile = Path.Combine(options.Source, primitive.Name); if (!File.Exists(primitiveFile)) { SetText("Couldn't find a container called {0} in the selected asm_pc file!", containerName); SetProgressBarSettings(0, 100, 0, ProgressBarStyle.Continuous); EnableButton(); return; } string filename = Path.GetFileName(primitiveFile); Stream stream = File.OpenRead(primitiveFile); packfile.AddFile(stream, filename); string extension = Path.GetExtension(primitiveFile); string gpuExtension = ""; switch (extension) { default: { if (extension.StartsWith(".c")) { gpuExtension = ".g" + extension.Remove(0, 2); } break; } } string gpuFile = Path.ChangeExtension(primitiveFile, gpuExtension); if (File.Exists(gpuFile)) { string gpuFilename = Path.GetFileName(gpuFile); Stream gpuStream = File.OpenRead(gpuFile); packfile.AddFile(gpuStream, gpuFilename); } Step(); } } else { string[] files = Directory.GetFiles(options.Source); SetProgressBarSettings(0, files.Length, 0, ProgressBarStyle.Continuous); SetText("Adding files..."); foreach (string file in files) { string filename = Path.GetFileName(file); Stream stream = File.OpenRead(file); packfile.AddFile(stream, filename); } } SetProgressBarSettings(0, 100, 0, ProgressBarStyle.Marquee); SetText("Writing output file: {0}", options.Destination); using (Stream output = File.Open(options.Destination, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { packfile.Save(output); } if (asm != null) { SetText("Updating asm_pc file: {0}", options.Asm); packfile.Update(thisContainer); using (Stream asmStream = File.Create(options.Asm)) { asm.Save(asmStream); } Console.WriteLine("done."); } SetProgressBarSettings(0, 1, 1, ProgressBarStyle.Continuous); Step(); SetText("Finished!"); EnableButton(); }
static void Main(string[] args) { string src = @"D:\Gaming\Saints Row 4\test\in"; string temp = @"D:\Gaming\Saints Row 4\test"; string dst = @"D:\Gaming\Saints Row 4\test\out"; string[] packfileFolders = Directory.GetDirectories(src); GameSteamID game = GameSteamID.SaintsRowIV; foreach (string packfileFolder in packfileFolders) { string pfTemp = Path.Combine(temp, Path.GetFileName(packfileFolder)); Directory.CreateDirectory(pfTemp); // Copy raw files string[] pfFiles = Directory.GetFiles(packfileFolder); foreach (string file in pfFiles) { File.Copy(file, Path.Combine(pfTemp, Path.GetFileName(file))); } string[] asmFiles = Directory.GetFiles(pfTemp, "*.asm_pc"); foreach (string asmFile in asmFiles) { IAssetAssemblerFile asm = null; using (Stream stream = File.OpenRead(asmFile)) { asm = AssetAssemblerFile.FromStream(stream); } int count = 0; foreach (var container in asm.Containers) { count++; string str2Name = Path.ChangeExtension(container.Name, ".str2_pc"); string str2Src = Path.Combine(packfileFolder, str2Name); Console.Write("[{0}/{1}] Building {2}...", count, asm.Containers.Count, str2Src.Remove(0, src.Length + 1)); if (Directory.Exists(str2Src)) { string outputFile = Path.Combine(pfTemp, Path.GetFileName(str2Src)); ProcessStartInfo psi = new ProcessStartInfo(@"D:\Development\SaintsRow\bin\Release\ThomasJepp.SaintsRow.BuildPackfile.exe", String.Format("{3} \"{0}\" \"{1}\" /asm:\"{2}\"", str2Src, outputFile, asmFile, game.ToString())); psi.CreateNoWindow = true; psi.WindowStyle = ProcessWindowStyle.Hidden; Process p = Process.Start(psi); p.WaitForExit(); Console.WriteLine(" OK"); } else { Console.WriteLine(" not found!"); } } } Console.Write("Building {0}...", Path.GetFileName(packfileFolder)); var options = OriginalPackfileInfo.OptionsList[game][Path.GetFileName(packfileFolder)]; ProcessStartInfo packpsi = new ProcessStartInfo(@"D:\Development\SaintsRow\bin\Release\ThomasJepp.SaintsRow.BuildPackfile.exe", String.Format("sriv \"{0}\" \"{1}\" /condensed:{2} /compressed:{3}", pfTemp, Path.Combine(dst, Path.GetFileName(packfileFolder)), options.Condense, options.Compress)); packpsi.CreateNoWindow = true; packpsi.WindowStyle = ProcessWindowStyle.Hidden; Process packProcess = Process.Start(packpsi); packProcess.WaitForExit(); Console.WriteLine(" OK"); } Console.WriteLine("Done."); }
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; } switch (options.Action) { case "toxml": { using (Stream stream = File.OpenRead(options.Source)) { IAssetAssemblerFile file = AssetAssemblerFile.FromStream(stream); if (options.Output == null || options.Output == "") { options.Output = Path.ChangeExtension(options.Source, "xml"); } XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.IndentChars = "\t"; settings.NewLineChars = "\r\n"; using (XmlWriter xml = XmlWriter.Create(options.Output, settings)) { xml.WriteStartDocument(); xml.WriteStartElement("AssetAssembler"); xml.WriteAttributeString("Version", file.Version.ToString()); xml.WriteStartElement("AllocatorTypes"); foreach (var pair in file.AllocatorTypes) { xml.WriteStartElement("AllocatorType"); xml.WriteAttributeString("ID", pair.Key.ToString()); xml.WriteAttributeString("Name", pair.Value); xml.WriteEndElement(); } xml.WriteEndElement(); // AllocatorTypes xml.WriteStartElement("ContainerTypes"); foreach (var pair in file.ContainerTypes) { xml.WriteStartElement("ContainerType"); xml.WriteAttributeString("ID", pair.Key.ToString()); xml.WriteAttributeString("Name", pair.Value); xml.WriteEndElement(); } xml.WriteEndElement(); // ContainerTypes xml.WriteStartElement("PrimitiveTypes"); foreach (var pair in file.PrimitiveTypes) { xml.WriteStartElement("PrimitiveType"); xml.WriteAttributeString("ID", pair.Key.ToString()); xml.WriteAttributeString("Name", pair.Value); xml.WriteEndElement(); } xml.WriteEndElement(); // PrimitiveTypes xml.WriteStartElement("Containers"); foreach (var container in file.Containers) { xml.WriteStartElement("Container"); xml.WriteAttributeString("Name", container.Name); xml.WriteAttributeString("Type", file.ContainerTypes[container.ContainerType]); xml.WriteAttributeString("Flags", container.Flags.ToString()); xml.WriteAttributeString("PackfileBaseOffset", container.PackfileBaseOffset.ToString()); xml.WriteAttributeString("CompressionType", container.CompressionType.ToString()); xml.WriteAttributeString("StubContainerParentName", container.StubContainerParentName); xml.WriteAttributeString("TotalCompressedPackfileReadSize", container.TotalCompressedPackfileReadSize.ToString()); if (container.AuxData.Length > 0) { xml.WriteStartElement("AuxData"); xml.WriteString(Convert.ToBase64String(container.AuxData, Base64FormattingOptions.None)); xml.WriteEndElement(); // AuxData } for (int i = 0; i < container.PrimitiveCount; i++) { var primitive = container.Primitives[i]; //var sizes = container.PrimitiveSizes[i]; xml.WriteStartElement("Primitive"); xml.WriteAttributeString("Name", primitive.Name); xml.WriteAttributeString("Type", file.PrimitiveTypes[primitive.Type]); xml.WriteAttributeString("Allocator", file.AllocatorTypes.ContainsKey(primitive.Allocator) ? file.AllocatorTypes[primitive.Allocator] : primitive.Allocator.ToString()); xml.WriteAttributeString("Flags", primitive.Flags.ToString()); xml.WriteAttributeString("ExtensionIndex", primitive.ExtensionIndex.ToString()); xml.WriteAttributeString("CPUSize", primitive.CPUSize.ToString()); xml.WriteAttributeString("GPUSize", primitive.GPUSize.ToString()); xml.WriteAttributeString("AllocationGroup", primitive.AllocationGroup.ToString()); //xml.WriteAttributeString("WriteTimeCPUSize", sizes.CPUSize.ToString()); //xml.WriteAttributeString("WriteTimeGPUSize", sizes.GPUSize.ToString()); xml.WriteEndElement(); // Primitive } xml.WriteEndElement(); // Container } xml.WriteEndElement(); // Containers xml.WriteEndElement(); // AssetAssembler xml.WriteEndDocument(); } } break; } case "toasm": { using (Stream stream = File.OpenRead(options.Source)) { XDocument xml = XDocument.Load(stream); var asmNode = xml.Element("AssetAssembler"); uint version = uint.Parse(asmNode.Attribute("Version").Value); IAssetAssemblerFile file = AssetAssemblerFile.Create(version); if (options.Output == null || options.Output == "") { options.Output = Path.ChangeExtension(options.Source, "asm_pc"); } Dictionary <string, byte> allocatorTypesLookup = new Dictionary <string, byte>(); Dictionary <string, byte> containerTypesLookup = new Dictionary <string, byte>(); Dictionary <string, byte> primitiveTypesLookup = new Dictionary <string, byte>(); foreach (var node in xml.Descendants("AllocatorType")) { byte id = byte.Parse(node.Attribute("ID").Value); string name = node.Attribute("Name").Value; allocatorTypesLookup.Add(name, id); file.AllocatorTypes.Add(id, name); } foreach (var node in xml.Descendants("ContainerType")) { byte id = byte.Parse(node.Attribute("ID").Value); string name = node.Attribute("Name").Value; containerTypesLookup.Add(name, id); file.ContainerTypes.Add(id, name); } foreach (var node in xml.Descendants("PrimitiveType")) { byte id = byte.Parse(node.Attribute("ID").Value); string name = node.Attribute("Name").Value; primitiveTypesLookup.Add(name, id); file.PrimitiveTypes.Add(id, name); } foreach (var cNode in xml.Descendants("Container")) { IContainer container = file.CreateContainer(); container.Name = cNode.Attribute("Name").Value; container.ContainerType = containerTypesLookup[cNode.Attribute("Type").Value]; container.Flags = (ContainerFlags)ushort.Parse(cNode.Attribute("Flags").Value); container.PackfileBaseOffset = uint.Parse(cNode.Attribute("PackfileBaseOffset").Value); container.CompressionType = byte.Parse(cNode.Attribute("CompressionType").Value); container.StubContainerParentName = cNode.Attribute("StubContainerParentName").Value; container.TotalCompressedPackfileReadSize = int.Parse(cNode.Attribute("TotalCompressedPackfileReadSize").Value); var auxData = cNode.Element("AuxData"); if (auxData != null) { container.AuxData = Convert.FromBase64String(auxData.Value); } else { container.AuxData = new byte[0]; } foreach (var pNode in cNode.Descendants("Primitive")) { IPrimitive p = container.CreatePrimitive(); p.Name = pNode.Attribute("Name").Value; p.Type = primitiveTypesLookup[pNode.Attribute("Type").Value]; byte allocatorType = 0; if (byte.TryParse(pNode.Attribute("Allocator").Value, out allocatorType)) { p.Allocator = allocatorType; } else { p.Allocator = allocatorTypesLookup[pNode.Attribute("Allocator").Value]; } p.Flags = byte.Parse(pNode.Attribute("Flags").Value); p.ExtensionIndex = byte.Parse(pNode.Attribute("ExtensionIndex").Value); p.CPUSize = uint.Parse(pNode.Attribute("CPUSize").Value); p.GPUSize = uint.Parse(pNode.Attribute("GPUSize").Value); p.AllocationGroup = byte.Parse(pNode.Attribute("AllocationGroup").Value); container.Primitives.Add(p); } container.PrimitiveCount = (short)container.Primitives.Count; file.Containers.Add(container); } using (Stream outputStream = File.Create(options.Output)) { file.Save(outputStream); } } break; } case "update": { IAssetAssemblerFile file = null; using (Stream stream = File.OpenRead(options.Source)) { file = AssetAssemblerFile.FromStream(stream); string folder = Path.GetDirectoryName(options.Source); foreach (var container in file.Containers) { string str2File = Path.ChangeExtension(container.Name, ".str2_pc"); string filename = Path.Combine(folder, str2File); if (File.Exists(filename)) { Console.Write("Found {0}, updating... ", str2File); using (Stream str2Stream = File.OpenRead(filename)) { IPackfile packfile = Packfile.FromStream(str2Stream, true); packfile.Update(container); } Console.WriteLine("done."); } else { Console.WriteLine("Could not find {0}.", str2File); } } } using (Stream stream = File.Create(options.Source)) { file.Save(stream); } break; } default: { Console.WriteLine("Unrecogised action!"); break; } } #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; } IPackfile packfile = null; IAssetAssemblerFile asm = null; Console.WriteLine("Building {0} using data from {1}.", options.Output, options.Source); IGameInstance instance = GameInstance.GetFromString(options.Game); switch (instance.Game) { case GameSteamID.SaintsRow2: packfile = new Packfiles.Version04.Packfile(); break; case GameSteamID.SaintsRowTheThird: throw new NotImplementedException(); case GameSteamID.SaintsRowIV: case GameSteamID.SaintsRowGatOutOfHell: packfile = new Packfiles.Version0A.Packfile(Path.GetExtension(options.Output) == ".str2_pc"); if (Path.GetExtension(options.Output) == ".str2_pc") { packfile.IsCondensed = true; packfile.IsCompressed = true; if (options.AsmFile != null) { Console.WriteLine("Will update asm_pc file {0} with data for new package.", options.AsmFile); using (Stream asmStream = File.OpenRead(options.AsmFile)) { asm = AssetAssemblerFile.FromStream(asmStream); } } } break; default: throw new NotImplementedException(); } if (options.Condensed.ToLowerInvariant() == "true") { packfile.IsCondensed = true; } else if (options.Condensed.ToLowerInvariant() == "false") { packfile.IsCondensed = false; } if (options.Compressed.ToLowerInvariant() == "true") { packfile.IsCompressed = true; } else if (options.Compressed.ToLowerInvariant() == "false") { packfile.IsCompressed = false; } IContainer thisContainer = null; if (asm != null) { string containerName = Path.GetFileNameWithoutExtension(options.Output); foreach (var container in asm.Containers) { string tempContainerName = Path.GetFileNameWithoutExtension(container.Name); if (tempContainerName == containerName) { thisContainer = container; break; } } if (thisContainer == null) { throw new Exception(String.Format("Unable to find container {0} in asm_pc file {1}.", containerName, options.AsmFile)); } foreach (IPrimitive primitive in thisContainer.Primitives) { string primitiveFile = Path.Combine(options.Source, primitive.Name); if (!File.Exists(primitiveFile)) { Console.WriteLine("Unable to find primitive {0} for container {1}", containerName, primitive.Name); continue; } string filename = Path.GetFileName(primitiveFile); Console.Write("Adding {0}... ", filename); Stream stream = File.OpenRead(primitiveFile); packfile.AddFile(stream, filename); Console.WriteLine("done."); string extension = Path.GetExtension(primitiveFile); string gpuExtension = ""; switch (extension) { default: { if (extension.StartsWith(".c")) { gpuExtension = ".g" + extension.Remove(0, 2); } break; } } string gpuFile = Path.ChangeExtension(primitiveFile, gpuExtension); if (File.Exists(gpuFile)) { string gpuFilename = Path.GetFileName(gpuFile); Console.Write("Adding {0}... ", gpuFilename); Stream gpuStream = File.OpenRead(gpuFile); packfile.AddFile(gpuStream, gpuFilename); Console.WriteLine("done."); } } } else { string[] files = Directory.GetFiles(options.Source); foreach (string file in files) { string filename = Path.GetFileName(file); Console.Write("Adding {0}... ", filename); Stream stream = File.OpenRead(file); packfile.AddFile(stream, filename); Console.WriteLine("done."); } } using (Stream output = File.Open(options.Output, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { Console.Write("Writing packfile to {0}... ", options.Output); packfile.Save(output); Console.WriteLine("done."); } if (asm != null) { Console.Write("Updating asm_pc file {0}... ", options.AsmFile); packfile.Update(thisContainer); using (Stream asmStream = File.Create(options.AsmFile)) { asm.Save(asmStream); } Console.WriteLine("done."); } #if DEBUG Console.ReadLine(); #endif }