public byte[] Rebuild() { FileOutput o = new FileOutput(); FileOutput data = new FileOutput(); //We always want BE for the first six bytes o.Endian = Endianness.Big; data.Endian = Endianness.Big; if (Endian == Endianness.Big) { o.writeUInt(0x4E545033); //NTP3 } else if (Endian == Endianness.Little) { o.writeUInt(0x4E545744); //NTWD } //Most NTWU NUTs are 0x020E, which isn't valid for NTP3/NTWD if (Version > 0x0200) { Version = 0x0200; } o.writeUShort(Version); //After that, endian is used appropriately o.Endian = Endian; data.Endian = Endian; o.writeUShort((ushort)Textures.Count); o.writeInt(0); o.writeInt(0); //calculate total header size uint headerLength = 0; foreach (NutTexture texture in Textures) { byte surfaceCount = (byte)texture.surfaces.Count; bool isCubemap = surfaceCount == 6; if (surfaceCount < 1 || surfaceCount > 6) { throw new NotImplementedException($"Unsupported surface amount {surfaceCount} for texture with hash 0x{texture.HashId:X}. 1 to 6 faces are required."); } else if (surfaceCount > 1 && surfaceCount < 6) { throw new NotImplementedException($"Unsupported cubemap face amount for texture with hash 0x{texture.HashId:X}. Six faces are required."); } byte mipmapCount = (byte)texture.surfaces[0].mipmaps.Count; ushort headerSize = 0x50; if (isCubemap) { headerSize += 0x10; } if (mipmapCount > 1) { headerSize += (ushort)(mipmapCount * 4); while (headerSize % 0x10 != 0) { headerSize += 1; } } headerLength += headerSize; } // write headers+data foreach (NutTexture texture in Textures) { byte surfaceCount = (byte)texture.surfaces.Count; bool isCubemap = surfaceCount == 6; byte mipmapCount = (byte)texture.surfaces[0].mipmaps.Count; uint dataSize = 0; foreach (var mip in texture.GetAllMipmaps()) { dataSize += (uint)mip.Length; while (dataSize % 0x10 != 0) { dataSize += 1; } } ushort headerSize = 0x50; if (isCubemap) { headerSize += 0x10; } if (mipmapCount > 1) { headerSize += (ushort)(mipmapCount * 4); while (headerSize % 0x10 != 0) { headerSize += 1; } } o.writeUInt(dataSize + headerSize); o.writeUInt(0); o.writeUInt(dataSize); o.writeUShort(headerSize); o.writeUShort(0); o.writeByte(0); o.writeByte(mipmapCount); o.writeByte(0); o.writeByte(texture.getNutFormat()); o.writeShort(texture.Width); o.writeShort(texture.Height); o.writeInt(0); o.writeUInt(texture.DdsCaps2); if (Version < 0x0200) { o.writeUInt(0); } else if (Version >= 0x0200) { o.writeUInt((uint)(headerLength + data.size())); } headerLength -= headerSize; o.writeInt(0); o.writeInt(0); o.writeInt(0); if (isCubemap) { o.writeInt(texture.surfaces[0].mipmaps[0].Length); o.writeInt(texture.surfaces[0].mipmaps[0].Length); o.writeInt(0); o.writeInt(0); } if (texture.getNutFormat() == 14 || texture.getNutFormat() == 17) { texture.SwapChannelOrderDown(); } for (byte surfaceLevel = 0; surfaceLevel < surfaceCount; ++surfaceLevel) { for (byte mipLevel = 0; mipLevel < mipmapCount; ++mipLevel) { int ds = data.size(); data.writeBytes(texture.surfaces[surfaceLevel].mipmaps[mipLevel]); data.align(0x10); if (mipmapCount > 1 && surfaceLevel == 0) { o.writeInt(data.size() - ds); } } } o.align(0x10); if (texture.getNutFormat() == 14 || texture.getNutFormat() == 17) { texture.SwapChannelOrderUp(); } o.writeBytes(new byte[] { 0x65, 0x58, 0x74, 0x00 }); // "eXt\0" o.writeInt(0x20); o.writeInt(0x10); o.writeInt(0x00); o.writeBytes(new byte[] { 0x47, 0x49, 0x44, 0x58 }); // "GIDX" o.writeInt(0x10); o.writeInt(texture.HashId); o.writeInt(0); if (Version < 0x0200) { o.writeOutput(data); data = new FileOutput(); } } if (Version >= 0x0200) { o.writeOutput(data); } return(o.getBytes()); }
public void SaveAs(object sender, EventArgs args) { using (var sfd = new SaveFileDialog()) { sfd.Filter = "HAL DAT|*.dat|" + "All Files (*.*)|*.*"; sfd.DefaultExt = "dat"; if (sfd.ShowDialog() == DialogResult.OK) { if (DatFile.Roots.Length > 0) { if (DatFile.Roots[0].FighterData.Count > 0) { //MessageBox.Show("Cannot save this dat type yet"); // gonna have to inject this one for now FileData d = new FileData(fileName); d.Endian = Endianness.Big; FileOutput o = new FileOutput(); if (DatFile.Roots.Length > 1) { foreach (DatAnimation a in DatFile.Roots[1].Animations) { DatFighterScript script = null; foreach (DatFighterScript s in DatFile.Roots[0].FighterData[0].Scripts) { if (s.Text.Equals(a.Text)) { script = s; break; } } // Create Animation MeleeJointAnimationNode n = new MeleeJointAnimationNode(a); Compiler.Compile(n.GetAsDATFile(), "temp.dat"); if (script != null) { script.AnimationOffset = o.size(); } o.writeBytes(File.ReadAllBytes("temp.dat")); if (script != null) { script.AnimationSize = o.size() - script.AnimationOffset; } o.align(0x20, 0xFF); } } if (File.Exists("temp.dat")) { File.Delete("temp.dat"); } bool CanExpand = false; foreach (DatFighterScript s in DatFile.Roots[0].FighterData[0].Scripts) { if (DatFile.Roots.Length > 1) { d.writeInt(s.Offset + 4, s.AnimationOffset); d.writeInt(s.Offset + 8, s.AnimationSize); } List <byte> newSection = new List <byte>(); foreach (SubAction sub in s.SubActions) { newSection.AddRange(sub.Data); if (MeleeCMD.GetActionName((byte)(sub.Data[0] >> 2)).Equals("Subroutine") || MeleeCMD.GetActionName((byte)(sub.Data[0] >> 2)).Equals("Goto")) { newSection[newSection.Count - 1] -= 0x20; } } newSection.AddRange(new byte[] { 0, 0, 0, 0 }); if (newSection.Count > s.SubActionSize && !CanExpand) { DialogResult dialogResult = MessageBox.Show("Expand the file?\n(Warning incomplete)", "Error: Not enough space", MessageBoxButtons.YesNo); if (dialogResult != DialogResult.Yes) { CanExpand = true; } else { MessageBox.Show("Failed saving the file"); return; } } else if (newSection.Count > s.SubActionSize && CanExpand) { d.writeInt(s.Offset + 12, d.size() - 0x20); d.writeBytesAt(d.size(), newSection.ToArray()); } else { d.writeInt(s.Offset + 12, s.SubActionOffset - 0x20); d.writeBytesAt(s.SubActionOffset, newSection.ToArray()); } Console.WriteLine(s.SubActionOffset.ToString("x") + " " + s.SubActionSize.ToString("x") + " " + newSection.Count.ToString("x")); } if (DatFile.Roots.Length > 1) { o.save(sfd.FileName.Replace(".dat", "AJ.dat")); } d.writeInt(0, d.size()); File.WriteAllBytes(sfd.FileName, d.getSection(0, d.eof())); return; } } Compiler.Compile(DatFile, sfd.FileName); } } }