/// <summary> /// Load BNSA Shared method /// </summary> /// <param name="memory">BSNA Memory to load</param> private void LoadBNSA(byte[] memory) { ActiveBNSA = new BNSAFile(memory); ActiveBNSA.ResolveReferences(); ActiveBNSA.CreateWorkingPalettes(); animationIndexUpDown.Maximum = ActiveBNSA.Animations.Count - 1; paletteIndexUpDown.Maximum = ActiveBNSA.WorkingPalettes.Count - 1; animationCountLabel.Content = "of " + animationIndexUpDown.Maximum; paletteCountLabel.Content = "of " + (ActiveBNSA.WorkingPalettes.Count - 1); //frameIndexUpDown.Maximum = ActiveBNSA.Animations[0].Frames.Count - 1; ChangeAnimation(); }
/// <summary> /// Unpacks a BNSA file into parts. /// </summary> /// <param name="bnsaFile">Path to a BNSA file</param> /// <param name="outputFolder">Directory to output files to. Will be created if it does not exist.</param> private static void unpackBNSA(string bnsaFile, string outputFolder) { BNSAFile bnsa = new BNSAFile(bnsaFile); bnsa.ResolveReferences(); bnsa.Unpack(outputFolder); bnsa.GenerateLinkingXML(outputFolder); if (true) { endProgram("Testing done...", 0); } //TODO: Check if archive is compressed. Likely will not be, but you never know. Can be identified by first 4 bytes. writeVerboseMessage("Unpacking " + bnsaFile + " to " + outputFolder); //Extract/Unpack byte[] inputFileBytes = File.ReadAllBytes(bnsaFile); int currentOffset = 4; List <byte[]> archiveParts = new List <byte[]>(); //Animation pointers writeVerboseMessage("Reading Animation Pointers"); int animPointersLength = inputFileBytes[3] * 4; byte[] animPointers = new byte[animPointersLength]; Array.Copy(inputFileBytes, currentOffset, animPointers, 0, animPointersLength); currentOffset += animPointersLength; //Frame data writeVerboseMessage("Calculating Frames data"); int frameDataLength = findFrameDataEnd(inputFileBytes, currentOffset) - currentOffset; byte[] frameData = new byte[frameDataLength]; Array.Copy(inputFileBytes, currentOffset, frameData, 0, frameDataLength); currentOffset += frameDataLength; //Tileset data writeVerboseMessage("Calculating Tilesets data"); int tilesetDataLength = findTilesetDataEnd(inputFileBytes, currentOffset) - currentOffset; byte[] tilesetData = new byte[tilesetDataLength]; Array.Copy(inputFileBytes, currentOffset, tilesetData, 0, tilesetDataLength); List <int> tilesetOffsetList = getTilesetOffsetList(tilesetData, currentOffset - 4); List <byte[]> tilesetsList = splitTilesets(tilesetData); currentOffset += tilesetDataLength; //Palette data writeVerboseMessage("Calculating Palettes data"); int paletteDataLength = findPaletteDataEnd(inputFileBytes, currentOffset) - currentOffset; byte[] paletteData = new byte[paletteDataLength]; Array.Copy(inputFileBytes, currentOffset, paletteData, 0, paletteDataLength); List <int> paletteOffsetList = getPaletteOffsetList(paletteData, currentOffset + 4); List <byte[]> paletteList = splitPalettes(paletteData); currentOffset += paletteDataLength; //Mini-Animations data writeVerboseMessage("Calculating Mini Animations data"); int miniAnimDataLength = findMiniAnimDataEnd(inputFileBytes, currentOffset) - currentOffset; byte[] miniAnimData = new byte[miniAnimDataLength]; Array.Copy(inputFileBytes, currentOffset, miniAnimData, 0, miniAnimDataLength); List <int> miniAnimDataOffsetList = getMiniAnimOffsetList(miniAnimData, currentOffset); List <byte[]> miniAnimsList = splitMiniAnims(miniAnimData); currentOffset += miniAnimDataLength; //Object list data writeVerboseMessage("Calculating Objects Lists data"); int objectListDataLength = findObjectListDataEnd(inputFileBytes, currentOffset) - currentOffset; byte[] objectListData = new byte[objectListDataLength]; Array.Copy(inputFileBytes, currentOffset, objectListData, 0, objectListDataLength); List <int> objectListOffsetList = getObjectListOffsetList(objectListData, currentOffset); List <byte[]> objectListsList = splitObjectLists(objectListData); currentOffset += objectListDataLength; //XML document for animation frames format //XmlDocument frameDoc = new XmlDocument(); //XmlNode animNode = frameDoc.CreateElement("animation"); //frameDoc.AppendChild(animNode); //XmlNode frameNode = frameDoc.CreateElement("frame"); //XmlAttribute tilesetAttr = frameDoc.CreateAttribute("tileset"); //tilesetAttr.Value = tilesetsList[0].ToString(); //frameNode.Attributes.Append(tilesetAttr); //animNode.AppendChild(frameNode); //frameDoc.Save() //Add arrays to list for export archiveParts.Add(animPointers); archiveParts.Add(frameData); archiveParts.Add(tilesetData); archiveParts.Add(paletteData); archiveParts.Add(miniAnimData); archiveParts.Add(objectListData); //create directories and save writeVerboseMessage("Creating output directories"); string framesPath = outputFolder + @"\\frames"; string tilesetsPath = outputFolder + @"\\tilesets"; string palettesPath = outputFolder + @"\\palettes"; string miniAnimsPath = outputFolder + @"\\minianims"; string objectListsPath = outputFolder + @"\\objectlists"; Directory.CreateDirectory(outputFolder); Directory.CreateDirectory(framesPath); Directory.CreateDirectory(tilesetsPath); Directory.CreateDirectory(palettesPath); Directory.CreateDirectory(miniAnimsPath); Directory.CreateDirectory(objectListsPath); //raw parts export writeVerboseMessage("Extracting raw parts"); File.WriteAllBytes(framesPath + "\\frames.bin", archiveParts[1].ToArray()); File.WriteAllBytes(tilesetsPath + "\\tilesets.bin", archiveParts[2].ToArray()); File.WriteAllBytes(palettesPath + "\\palettes.bin", archiveParts[3].ToArray()); File.WriteAllBytes(miniAnimsPath + "\\minianims.bin", archiveParts[4].ToArray()); File.WriteAllBytes(objectListsPath + "\\objectlists.bin", archiveParts[5].ToArray()); //export tiles for (int i = 0; i < tilesetsList.Count; i++) { writeVerboseMessage("Extracting Tileset " + i); File.WriteAllBytes(tilesetsPath + "\\tiles" + i + ".bin", tilesetsList[i]); } //export palettes for (int i = 0; i < paletteList.Count; i++) { writeVerboseMessage("Extracting Palette " + i); File.WriteAllBytes(palettesPath + "\\palette" + i + ".bin", paletteList[i]); } //export minianims for (int i = 0; i < miniAnimsList.Count; i++) { writeVerboseMessage("Extracting Mini Animation " + i); File.WriteAllBytes(miniAnimsPath + "\\minianim" + i + ".bin", miniAnimsList[i]); } //export objectlists for (int i = 0; i < objectListsList.Count; i++) { writeVerboseMessage("Extracting Object List " + i); File.WriteAllBytes(objectListsPath + "\\objectlists" + i + ".bin", objectListsList[i]); } writeVerboseMessage("Creating BNSA Project file..."); XmlWriterSettings settings = new XmlWriterSettings { Indent = true }; using (XmlWriter writer = XmlWriter.Create(framesPath + "\\animations.xml", settings)) { writer.WriteStartDocument(); writer.WriteStartElement("animation"); for (int i = 0; i < frameData.Count(); i++) { writer.WriteStartElement("frame" + i.ToString()); //writer.WriteElementString("tileset", getMatchingTileset(frameData, tilesetOffsetList, i)); writer.WriteElementString("tileset", "tileset0.bin"); writer.WriteElementString("palette", "palette0.bin"); writer.WriteElementString("minianim", "minianim0.bin"); writer.WriteElementString("objectlist", "objectlist0.bin"); writer.WriteElementString("delay", 1.ToString()); writer.WriteElementString("flags", "loop"); writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndDocument(); } XDocument xDoc = new XDocument(new XDeclaration("1.0", "UTF-16", null)); for (int i = 0; i < frameData.Count(); i++) { //writer.WriteStartElement("frame" + i.ToString()); ////writer.WriteElementString("tileset", getMatchingTileset(frameData, tilesetOffsetList, i)); //writer.WriteElementString("tileset", "tileset0.bin"); //writer.WriteElementString("palette", "palette0.bin"); //writer.WriteElementString("minianim", "minianim0.bin"); //writer.WriteElementString("objectlist", "objectlist0.bin"); //writer.WriteElementString("delay", 1.ToString()); //writer.WriteElementString("flags", "loop"); //new XElement("Frame", // new XElement("tileset", // new XComment("Only 3 elements for demo purposes"), // new XElement("EmpId", "5"), // new XElement("Name", "Kimmy"), // new XElement("Sex", "Female"), // new XAttribute("index", i); // ))); } StringWriter sw = new StringWriter(); xDoc.Save(sw); Console.WriteLine(sw); //frameDoc.Save(framesPath + "\\animations.xml"); endProgram("Sprite unpacked into " + outputFolder, 0); }