public static readonly uint Magic1 = 4; // Maybe represents format version? Similar to survival file. public void MakeBinary(List <AbstractAsset> allAssets, string outputPath, ProgressWrapper progress) { progress.Report("Initializing 'particle' file creation."); allAssets = allAssets.Where(a => File.Exists(a.EditorPath)).ToList(); byte[] fileBuffer; using (MemoryStream stream = new MemoryStream()) { stream.Write(BitConverter.GetBytes(4), 0, sizeof(int)); stream.Write(BitConverter.GetBytes(allAssets.Count), 0, sizeof(int)); int i = 0; foreach (KeyValuePair <string, byte[]> kvp in GetChunks(allAssets)) { progress.Report($"Writing file contents of \"{kvp.Key}\" to 'particle' file.", i++ / (float)allAssets.Count); stream.Write(Encoding.Default.GetBytes(kvp.Key), 0, kvp.Key.Length); stream.Write(kvp.Value, 0, kvp.Value.Length); } fileBuffer = stream.ToArray(); } progress.Report("Writing 'particle' file."); File.WriteAllBytes(outputPath, fileBuffer); }
/// <summary> /// Extracts a binary file into multiple asset files. /// </summary> /// <param name="inputPath">The binary file path.</param> /// <param name="outputPath">The path where the extracted asset files will be placed.</param> /// <param name="progress">The progress wrapper to report progress to.</param> public void ExtractBinary(string inputPath, string outputPath, ProgressWrapper progress) { byte[] sourceFileBytes = File.ReadAllBytes(inputPath); progress.Report("Validating file."); ValidateFile(sourceFileBytes); progress.Report("Reading TOC buffer."); byte[] tocBuffer = ReadTocBuffer(sourceFileBytes); progress.Report("Creating chunks."); List <ResourceChunk> chunks = ReadChunks(tocBuffer); progress.Report("Initializing extraction."); CreateFiles(outputPath, sourceFileBytes, chunks, progress); }
public void ExtractBinary(string inputPath, string outputPath, ProgressWrapper progress) { byte[] fileBuffer = File.ReadAllBytes(inputPath); Directory.CreateDirectory(Path.Combine(outputPath, AssetType.Particle.GetFolderName())); int i = HeaderSize; while (i < fileBuffer.Length) { ParticleChunk chunk = ReadParticleChunk(fileBuffer, i); i += chunk.Buffer.Length; progress.Report($"Creating Particle file for chunk \"{chunk.Name}\".", i / (float)fileBuffer.Length); File.WriteAllBytes(Path.Combine(outputPath, AssetType.Particle.GetFolderName(), chunk.Name + AssetType.Particle.GetFileExtension()), chunk.Buffer[chunk.Name.Length..]);
/// <summary> /// Inserts multiple asset files into one binary file that can be read by Devil Daggers. /// </summary> /// <param name="allAssets">The list of asset objects.</param> /// <param name="outputPath">The path where the binary file will be placed.</param> /// <param name="progress">The progress wrapper to report progress to.</param> public void MakeBinary(List <AbstractAsset> allAssets, string outputPath, ProgressWrapper progress) { progress.Report($"Initializing '{BinaryFileName}' file creation."); allAssets = allAssets.Where(a => File.Exists(a.EditorPath)).ToList(); // TODO: Also check if FragmentShader file exists. progress.Report("Generating chunks based on asset list."); List <ResourceChunk> chunks = CreateChunksFromAssets(allAssets, progress); progress.Report("Generating TOC stream."); CreateTocStream(chunks, out byte[] tocBuffer, out Dictionary <ResourceChunk, long> startOffsetBytePositions); progress.Report("Generating asset stream."); byte[] assetBuffer = CreateAssetStream(chunks, tocBuffer, startOffsetBytePositions, progress); progress.Report($"Writing buffers to '{BinaryFileName}' file."); byte[] binaryBytes = CreateBinary(tocBuffer, assetBuffer); progress.Report($"Writing '{BinaryFileName}' file."); File.WriteAllBytes(outputPath, binaryBytes); }
private static List <ResourceChunk> CreateChunksFromAssets(List <AbstractAsset> allAssets, ProgressWrapper progress) { StringBuilder loudness = new StringBuilder(); List <ResourceChunk> chunks = new List <ResourceChunk>(); foreach (AbstractAsset asset in allAssets) { progress.Report($"Generating {asset.AssetType} chunk \"{asset.AssetName}\".", chunks.Count / (float)allAssets.Count / 2); if (asset is AudioAsset audioAsset) { loudness.AppendLine($"{audioAsset.AssetName} = {audioAsset.Loudness:0.0}"); } ResourceChunk chunk = asset.AssetType switch { AssetType.Model => new ModelChunk(asset.AssetName, 0, 0), AssetType.Shader => new ShaderChunk(asset.AssetName, 0, 0), AssetType.Texture => new TextureChunk(asset.AssetName, 0, 0), _ => new ResourceChunk(asset.AssetType, asset.AssetName, 0, 0), }; chunk.MakeBinary(asset.EditorPath); chunks.Add(chunk); } if (loudness.Length != 0) { progress.Report("Generating Loudness chunk."); byte[] fileBuffer; using (MemoryStream ms = new MemoryStream()) { byte[] fileContents = Encoding.Default.GetBytes(loudness.ToString()); ms.Write(fileContents, 0, fileContents.Length); fileBuffer = ms.ToArray(); } chunks.Add(new ResourceChunk(AssetType.Audio, "loudness", 0U, (uint)fileBuffer.Length) { Buffer = fileBuffer }); } return(chunks); }
private static void CreateFiles(string outputPath, byte[] sourceFileBytes, IEnumerable <ResourceChunk> chunks, ProgressWrapper progress) { int chunksDone = 0; int totalChunks = chunks.Count(); foreach (ResourceChunk chunk in chunks) { if (chunk.Size == 0) // Filter empty chunks (garbage in TOC buffers). { continue; } string fileExtension = chunk.AssetType.GetFileExtension(); progress.Report( $"Creating {chunk.AssetType} file{(chunk.AssetType == AssetType.Shader ? "s" : string.Empty)} for chunk \"{chunk.Name}\".", chunksDone++ / (float)totalChunks); byte[] buffer = new byte[chunk.Size]; Buffer.BlockCopy(sourceFileBytes, (int)chunk.StartOffset, buffer, 0, (int)chunk.Size); chunk.Buffer = buffer; foreach (FileResult fileResult in chunk.ExtractBinary()) { string assetTypeDirectory = chunk.AssetType.GetFolderName(); if (!Directory.Exists(assetTypeDirectory)) { Directory.CreateDirectory(Path.Combine(outputPath, assetTypeDirectory)); } File.WriteAllBytes(Path.Combine(outputPath, assetTypeDirectory, fileResult.Name + (fileResult.Name == "loudness" && fileExtension == ".wav" ? ".ini" : fileExtension)), fileResult.Buffer.ToArray()); } } }
private byte[] CreateAssetStream(List <ResourceChunk> chunks, byte[] tocBuffer, Dictionary <ResourceChunk, long> startOffsetBytePositions, ProgressWrapper progress) { using MemoryStream assetStream = new MemoryStream(); int i = 0; foreach (ResourceChunk chunk in chunks) { progress.Report($"Writing file contents of \"{chunk.Name}\" to '{BinaryFileName}' file.", 0.5f + i++ / (float)chunks.Count / 2); uint startOffset = (uint)(HeaderSize + tocBuffer.Length + assetStream.Position); chunk.StartOffset = startOffset; // Write start offset to TOC stream. Buffer.BlockCopy(BitConverter.GetBytes(startOffset), 0, tocBuffer, (int)startOffsetBytePositions[chunk], sizeof(uint)); // Write asset data to asset stream. byte[] bytes = chunk.Buffer.ToArray(); assetStream.Write(bytes, 0, bytes.Length); } return(assetStream.ToArray()); }