/// <summary> /// Constructs a list of mini-animations from a file stream, starting with the beginning pointer table. /// </summary> /// <param name="stream">Stream to read from, starting with a pointer table to sub-mini anims.</param> public MiniAnimGroup(Stream stream) { Pointer = stream.Position; int firstAnimPointer = int.MaxValue; while (stream.Position < firstAnimPointer + Pointer) { int animationPointer = BNSAFile.ReadIntegerFromStream(stream); firstAnimPointer = Math.Min(firstAnimPointer, animationPointer); //should only be triggered by the first pointer as it goes ascending. long nextPosition = stream.Position; stream.Seek(Pointer + animationPointer, SeekOrigin.Begin); //Move cursor to start of minianim MiniAnim animation = new MiniAnim(stream, Pointer); IsValid &= animation.IsValid; if (!IsValid) { break; //Invalid data, stop caring and exit. } MiniAnimations.Add(animation); if (nextPosition < firstAnimPointer + Pointer) { //Read the next 4 bytes in the pointer table as its a new pointer stream.Seek(nextPosition, SeekOrigin.Begin); } } }
/// <summary> /// Reads a project XML file and relinks all the parts for file rebuilding /// </summary> /// <param name="filePath">XML file to parse</param> public BNSAXMLFile(string filePath) { this.FilePath = filePath; Console.WriteLine("Loading project file: " + filePath); XmlDocument doc = new XmlDocument(); doc.Load(filePath); //Parse Process: //1. Read animation tree //2. Read tileset folder //3. Read minianim folder //4. Read palette folder //5. Read oamdatalists folder //6. Link all objects //Build lists, mark pointer placeholders //Byte align after lists are built //insert pointers //merge into single file string tilesetBasepath = Directory.GetParent(filePath).FullName + "\\tilesets\\tileset"; string palettesBasepath = Directory.GetParent(filePath).FullName + "\\palettes\\palette"; string oamDataListsBasepath = Directory.GetParent(filePath).FullName + "\\oamdatalists\\oamdatalist"; string miniAnimsBasepath = Directory.GetParent(filePath).FullName + "\\minianims\\minianim"; XmlNodeList animationNodes = doc.DocumentElement.SelectNodes("/bnsafile/animations/animation"); Console.WriteLine("Found " + animationNodes.Count + " animations"); Animations = new List <Animation>(); foreach (XmlNode animationNode in animationNodes) { //Read Animation XML Animation animation = new Animation(animationNode); //Verify references exist in filesystem foreach (Frame f in animation.Frames) { //Verify Tileset string tilesetPath = tilesetBasepath + f.TilesetIndex.ToString().PadLeft(3, '0') + ".bin"; if (!File.Exists(tilesetPath)) { IsValid = false; Console.WriteLine("Tileset file missing: " + tilesetPath + ", referenced by Anim " + animation.Index + " frame " + f.Index); return; } //Verify OAM string oamPath = oamDataListsBasepath + f.OAMDataListIndex + "-0-0.bin"; if (!File.Exists(oamPath)) { IsValid = false; Console.WriteLine("OAM Data List file missing: " + oamPath + ", referenced by Anim " + animation.Index + " frame " + f.Index); return; } //Verify MiniAnim string minianimFrame1 = miniAnimsBasepath + f.MiniAnimationIndex + "-0-0.bin"; if (!File.Exists(minianimFrame1)) { IsValid = false; Console.WriteLine("MiniAnimation file missing: " + minianimFrame1 + ", referenced by Anim " + animation.Index + " frame " + f.Index); return; } } Animations.Add(animation); Console.WriteLine("OK - animation contains all direct binary references"); } //Read Tilesets Tilesets = new List <Tileset>(); int index = 0; for (int i = 0; i < 999; i++) { string tilesetPath = tilesetBasepath + index.ToString().PadLeft(3, '0') + ".bin"; if (File.Exists(tilesetPath)) { Tileset tileset = new Tileset(tilesetPath, i); Tilesets.Add(tileset); } else { break; //No more tilesets } index++; } Console.WriteLine("Read " + Tilesets.Count + " tilesets"); //Read Palettes Palettes = new List <Palette>(); for (int i = 0; i < 16; i++) { string palettePath = palettesBasepath + i.ToString().PadLeft(2, '0') + ".bin"; if (File.Exists(palettePath)) { Palette palette = new Palette(palettePath); Palettes.Add(palette); } else { break; //No more palettes } } Console.WriteLine("Read " + Palettes.Count + " palettes"); //Read MiniAnims string[] miniAnimFiles = Directory.GetFiles(Directory.GetParent(filePath).FullName + "\\minianims"); int maxindex = 0; foreach (string file in miniAnimFiles) { string fname = Path.GetFileNameWithoutExtension(file); fname = fname.Substring(8); int dashIndex = fname.IndexOf('-'); fname = fname.Substring(0, dashIndex); maxindex = Math.Max(maxindex, Int32.Parse(fname)); } Console.WriteLine("Found " + (maxindex + 1) + " mini animations"); MiniAnimationGroups = new List <MiniAnimGroup>(); for (index = 0; index <= maxindex; index++) { int subindex = 0; Console.WriteLine("Parsing Group " + index); MiniAnimGroup group = new MiniAnimGroup(index); while (File.Exists(miniAnimsBasepath + maxindex + "-" + subindex + "-0.bin")) { //MiniAnimation List MiniAnim animation = new MiniAnim(miniAnimsBasepath, index, subindex); group.MiniAnimations.Add(animation); subindex++; } MiniAnimationGroups.Add(group); } //Read OAM Data string[] oamListEntries = Directory.GetFiles(Directory.GetParent(filePath).FullName + "\\oamdatalists"); maxindex = 0; foreach (string file in oamListEntries) { string fname = Path.GetFileNameWithoutExtension(file); fname = fname.Substring(11); int dashIndex = fname.IndexOf('-'); fname = fname.Substring(0, dashIndex); maxindex = Math.Max(maxindex, Int32.Parse(fname)); } Console.WriteLine("Found " + (maxindex + 1) + " OAM Data List Groups"); OAMDataListGroups = new List <OAMDataListGroup>(); for (int i = 0; i <= maxindex; i++) { Console.WriteLine("Parsing OAM Data List Group " + i); OAMDataListGroup list = new OAMDataListGroup(oamDataListsBasepath, i); OAMDataListGroups.Add(list); } IsValid = true; }