public static void CreateFile(string filename, NJS_OBJECT model, string[] animationFiles, string[] morphFiles, string author, string description, string tool, Dictionary <uint, byte[]> metadata, ModelFormat format) { bool be = ByteConverter.BigEndian; ByteConverter.BigEndian = false; if (format == ModelFormat.BasicDX) { format = ModelFormat.Basic; } List <byte> file = new List <byte>(); ulong magic; switch (format) { case ModelFormat.Basic: case ModelFormat.BasicDX: magic = SA1MDLVer; break; case ModelFormat.Chunk: magic = SA2MDLVer; break; default: throw new ArgumentException("Cannot save " + format.ToString() + " format models to file!", "format"); } file.AddRange(ByteConverter.GetBytes(magic)); Dictionary <string, uint> labels = new Dictionary <string, uint>(); byte[] mdl = model.GetBytes(0x10, false, labels, out uint addr); file.AddRange(ByteConverter.GetBytes(addr + 0x10)); file.AddRange(ByteConverter.GetBytes(mdl.Length + 0x10)); file.AddRange(mdl); if (labels.Count > 0) { List <byte> chunk = new List <byte>((labels.Count * 8) + 8); int straddr = (labels.Count * 8) + 8; List <byte> strbytes = new List <byte>(); foreach (KeyValuePair <string, uint> label in labels) { chunk.AddRange(ByteConverter.GetBytes(label.Value)); chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count)); strbytes.AddRange(Encoding.UTF8.GetBytes(label.Key)); strbytes.Add(0); strbytes.Align(4); } chunk.AddRange(ByteConverter.GetBytes(-1L)); chunk.AddRange(strbytes); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Label)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (animationFiles != null && animationFiles.Length > 0) { List <byte> chunk = new List <byte>((animationFiles.Length + 1) * 4); int straddr = (animationFiles.Length + 1) * 4; List <byte> strbytes = new List <byte>(); for (int i = 0; i < animationFiles.Length; i++) { chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count)); strbytes.AddRange(Encoding.UTF8.GetBytes(animationFiles[i])); strbytes.Add(0); strbytes.Align(4); } chunk.AddRange(ByteConverter.GetBytes(-1)); chunk.AddRange(strbytes); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Animation)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (morphFiles != null && morphFiles.Length > 0) { List <byte> chunk = new List <byte>((morphFiles.Length + 1) * 4); int straddr = (morphFiles.Length + 1) * 4; List <byte> strbytes = new List <byte>(); for (int i = 0; i < morphFiles.Length; i++) { chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count)); strbytes.AddRange(Encoding.UTF8.GetBytes(morphFiles[i])); strbytes.Add(0); strbytes.Align(4); } chunk.AddRange(ByteConverter.GetBytes(-1)); chunk.AddRange(strbytes); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Morph)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (!string.IsNullOrEmpty(author)) { List <byte> chunk = new List <byte>(author.Length + 1); chunk.AddRange(Encoding.UTF8.GetBytes(author)); chunk.Add(0); chunk.Align(4); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Author)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (!string.IsNullOrEmpty(description)) { List <byte> chunk = new List <byte>(description.Length + 1); chunk.AddRange(Encoding.UTF8.GetBytes(description)); chunk.Add(0); chunk.Align(4); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Description)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (!string.IsNullOrEmpty(tool)) { List <byte> chunk = new List <byte>(tool.Length + 1); chunk.AddRange(Encoding.UTF8.GetBytes(tool)); chunk.Add(0); chunk.Align(4); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Tool)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (metadata != null) { foreach (KeyValuePair <uint, byte[]> item in metadata) { file.AddRange(ByteConverter.GetBytes(item.Key)); file.AddRange(ByteConverter.GetBytes(item.Value.Length)); file.AddRange(item.Value); } } file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.End)); file.AddRange(new byte[4]); File.WriteAllBytes(filename, file.ToArray()); ByteConverter.BigEndian = be; }
static bool CheckModel(uint address, int numhierarchy, ModelFormat modelfmt, bool landtable = false) { //Console.WriteLine("Check: {0}", address.ToString("X")); ByteConverter.BigEndian = BigEndian; if (address > (uint)datafile.Length - 20) { return(false); } int flags = 0; uint vertlist = 0; uint polylist = 0; uint chunkend = 0; float radius = 0; int radiusChunk = 0; uint attach = 0; uint child = 0; uint sibling = 0; uint vertices = 0; uint normals = 0; uint vert_count = 0; uint meshlists = 0; short mesh_count = 0; short mat_count = 0; uint opaquepoly = 0; short opaquecount = 0; uint alphapoly = 0; short alphacount = 0; float center_x = 0; float center_y = 0; float center_z = 0; Vertex pos; Vertex scl; switch (modelfmt) { case ModelFormat.Basic: case ModelFormat.BasicDX: flags = ByteConverter.ToInt32(datafile, (int)address); if (flags > 0x3FFF || flags < 0) { return(false); } attach = ByteConverter.ToUInt32(datafile, (int)address + 4); pos = new Vertex(datafile, (int)address + 8); scl = new Vertex(datafile, (int)address + 0x20); child = ByteConverter.ToUInt32(datafile, (int)address + 0x2C); sibling = ByteConverter.ToUInt32(datafile, (int)address + 0x30); if (landtable && (child != 0 || sibling != 0)) { return(false); } if (child > address + ImageBase) { return(false); } if (sibling > address + ImageBase) { return(false); } if (child != 0 && child < ImageBase) { return(false); } if (child > datafile.Length - 52 + ImageBase) { return(false); } if (sibling > datafile.Length - 52 + ImageBase) { return(false); } if (sibling != 0 && sibling < ImageBase) { return(false); } if (SimpleSearch) { if (scl.X == 1.0f && scl.Y == 1.0f && scl.Z == 1.0f) { Console.WriteLine("Trying {0} model at {1}", modelfmt.ToString(), address.ToString("X")); return(true); } } if (attach != 0) { if (attach < ImageBase) { return(false); } if (attach > datafile.Length - 51 + ImageBase) { return(false); } vertices = ByteConverter.ToUInt32(datafile, ((int)(attach - ImageBase))); if (vertices < ImageBase) { return(false); } if (vertices > datafile.Length - 51 + ImageBase) { return(false); } normals = ByteConverter.ToUInt32(datafile, ((int)(attach - ImageBase) + 4)); if (normals != 0 && normals < ImageBase) { return(false); } if (normals > datafile.Length - 51 + ImageBase) { return(false); } vert_count = ByteConverter.ToUInt32(datafile, (int)(attach - ImageBase) + 8); if (vert_count > 2048 || vert_count == 0) { return(false); } meshlists = ByteConverter.ToUInt32(datafile, (int)(attach - ImageBase) + 0xC); if (meshlists != 0 && meshlists < ImageBase) { return(false); } if (meshlists > datafile.Length - 51 + ImageBase) { return(false); } mesh_count = ByteConverter.ToInt16(datafile, (int)(attach - ImageBase) + 0x14); if (mesh_count > 2048 || mesh_count < 0) { return(false); } mat_count = ByteConverter.ToInt16(datafile, (int)(attach - ImageBase) + 0x16); if (mat_count > 2048 || mat_count < 0) { return(false); } center_x = ByteConverter.ToSingle(datafile, (int)(attach - ImageBase) + 0x18); center_y = ByteConverter.ToSingle(datafile, (int)(attach - ImageBase) + 0x1C); center_z = ByteConverter.ToSingle(datafile, (int)(attach - ImageBase) + 0x20); radius = ByteConverter.ToSingle(datafile, (int)(attach - ImageBase) + 0x24); if (center_x < -100000.0f || center_x > 100000.0f) { return(false); } if (center_y < -100000.0f || center_y > 100000.0f) { return(false); } if (center_z < -100000.0f || center_z > 100000.0f) { return(false); } if (radius < 0.0f || radius > 100000.0f) { return(false); } } if (pos.X < -100000 || pos.X > 100000) { return(false); } if (pos.Y < -100000 || pos.Y > 100000) { return(false); } if (pos.Z < -100000 || pos.Z > 100000) { return(false); } if (scl.X <= 0 || scl.X > 10000) { return(false); } if (scl.Y <= 0 || scl.Y > 10000) { return(false); } if (scl.Z <= 0 || scl.Z > 10000) { return(false); } if (child == address + ImageBase || (attach != 0 && child == attach)) { return(false); } if (sibling == address + ImageBase || (attach != 0 && sibling == attach)) { return(false); } if (child != 0 && child == sibling) { return(false); } if (numhierarchy != -1 && child != 0) { if (numhierarchy < 3) { numhierarchy++; return(CheckModel(child - ImageBase, numhierarchy, modelfmt)); } else { return(CheckModel(child - ImageBase, -1, modelfmt)); } } if (numhierarchy != -1 && sibling != 0) { if (numhierarchy < 3) { numhierarchy++; return(CheckModel(sibling - ImageBase, numhierarchy, modelfmt)); } else { return(CheckModel(sibling - ImageBase, -1, modelfmt)); } } if (attach == 0 && flags == 0) { return(false); } //Console.WriteLine("Attach pointer {0}, Vertices count {1}, Mesh count {2}, Center {3} {4} {5}, Radius {6} at {7}", attach.ToString("X"), vert_count, mesh_count, center_x, center_y, center_z, radius, address.ToString("X")); break; case ModelFormat.Chunk: if ((int)address > datafile.Length - 20) { return(false); } flags = ByteConverter.ToInt32(datafile, (int)address); if (flags > 0x3FFF || flags < 0) { return(false); } attach = ByteConverter.ToUInt32(datafile, (int)address + 4); if (attach != 0) { if (attach < ImageBase) { return(false); } if (attach > datafile.Length - 51 + ImageBase) { return(false); } chunkend = ByteConverter.ToUInt32(datafile, (int)(attach - ImageBase) - 4); if (vertlist != 0 && chunkend != 0xFF) { return(false); } vertlist = ByteConverter.ToUInt32(datafile, (int)(attach - ImageBase)); if (vertlist > datafile.Length - 51 + ImageBase) { return(false); } if (vertlist != 0 && vertlist < ImageBase) { return(false); } polylist = ByteConverter.ToUInt32(datafile, (int)(attach - ImageBase) + 4); if (polylist != 0 && polylist < ImageBase) { return(false); } if (polylist > datafile.Length - 51 + ImageBase) { return(false); } radiusChunk = ByteConverter.ToInt32(datafile, (int)(attach - ImageBase) + 0x14); if (radiusChunk < 0) { return(false); } } pos = new Vertex(datafile, (int)address + 8); if (pos.X < -100000 || pos.X > 100000) { return(false); } if (pos.Y < -100000 || pos.Y > 100000) { return(false); } if (pos.Z < -100000 || pos.Z > 100000) { return(false); } scl = new Vertex(datafile, (int)address + 0x20); if (scl.X <= 0 || scl.X > 10000) { return(false); } if (scl.Y <= 0 || scl.Y > 10000) { return(false); } if (scl.Z <= 0 || scl.Z > 10000) { return(false); } child = ByteConverter.ToUInt32(datafile, (int)address + 0x2C); sibling = ByteConverter.ToUInt32(datafile, (int)address + 0x30); if (child > address + ImageBase) { return(false); } if (sibling > address + ImageBase) { return(false); } if (child > datafile.Length - 52 + ImageBase) { return(false); } if (sibling > datafile.Length - 52 + ImageBase) { return(false); } if (child != 0 && child < ImageBase) { return(false); } if (sibling != 0 && sibling < ImageBase) { return(false); } if (numhierarchy != 0 && child != 0 && !CheckModel(child - ImageBase, -1, modelfmt)) { return(false); } if (numhierarchy != 0 && sibling != 0 && !CheckModel(sibling - ImageBase, -1, modelfmt)) { return(false); } if (vertlist == 0 && child == 0 && sibling == 0) { return(false); } if (attach == 0 && flags == 0) { return(false); } if (attach == 0 && child == 0 && sibling == 0) { return(false); } if (child == address + ImageBase || child == attach) { return(false); } if (sibling == address + ImageBase || sibling == attach) { return(false); } if (child != 0 && child == sibling) { return(false); } if (numhierarchy != -1 && child != 0) { if (numhierarchy < 3) { numhierarchy++; return(CheckModel(child - ImageBase, numhierarchy, modelfmt)); } else { return(CheckModel(child - ImageBase, -1, modelfmt)); } } if (numhierarchy != -1 && sibling != 0) { if (numhierarchy < 3) { numhierarchy++; return(CheckModel(sibling - ImageBase, numhierarchy, modelfmt)); } else { return(CheckModel(sibling - ImageBase, -1, modelfmt)); } } if (attach == 0 && flags == 0) { return(false); } break; case ModelFormat.GC: if (address <= 0 || address > datafile.Length - 20) { return(false); } flags = ByteConverter.ToInt32(datafile, (int)address); if (flags > 0x3FFF || flags < 0) { return(false); } attach = ByteConverter.ToUInt32(datafile, (int)address + 4); if (attach != 0) { if (attach < ImageBase) { return(false); } if (attach > datafile.Length - 51 + ImageBase) { return(false); } vertlist = ByteConverter.ToUInt32(datafile, (int)(attach - ImageBase)); if (vertlist > datafile.Length - 51 + ImageBase) { return(false); } if (vertlist < ImageBase) { return(false); } opaquepoly = ByteConverter.ToUInt32(datafile, (int)(attach - ImageBase) + 8); if (opaquepoly != 0 && opaquepoly < ImageBase) { return(false); } if (opaquepoly > datafile.Length - 51 + ImageBase) { return(false); } alphapoly = ByteConverter.ToUInt32(datafile, (int)(attach - ImageBase) + 0xC); if (alphapoly != 0 && alphapoly < ImageBase) { return(false); } if (alphapoly > datafile.Length - 51 + ImageBase) { return(false); } opaquecount = ByteConverter.ToInt16(datafile, (int)(attach - ImageBase) + 0x10); if (opaquepoly != 0 && opaquecount < 0) { return(false); } if (opaquepoly == 0 && opaquecount > 0) { return(false); } alphacount = ByteConverter.ToInt16(datafile, (int)(attach - ImageBase) + 0x12); if (alphapoly != 0 && alphacount < 0) { return(false); } if (alphapoly == 0 && alphacount > 0) { return(false); } radius = ByteConverter.ToInt32(datafile, (int)(attach - ImageBase) + 0x20); if (radius < 0) { return(false); } } pos = new Vertex(datafile, (int)address + 8); if (pos.X < -100000 || pos.X > 100000) { return(false); } if (pos.Y < -100000 || pos.Y > 100000) { return(false); } if (pos.Z < -100000 || pos.Z > 100000) { return(false); } scl = new Vertex(datafile, (int)address + 0x20); if (scl.X <= 0 || scl.X > 10000) { return(false); } if (scl.Y <= 0 || scl.Y > 10000) { return(false); } if (scl.Z <= 0 || scl.Z > 10000) { return(false); } child = ByteConverter.ToUInt32(datafile, (int)address + 0x2C); sibling = ByteConverter.ToUInt32(datafile, (int)address + 0x30); if (child > (int)address + ImageBase) { return(false); } if (sibling > (int)address + ImageBase) { return(false); } if (child > datafile.Length - 52 + ImageBase) { return(false); } if (sibling > datafile.Length - 52 + ImageBase) { return(false); } if (child != 0 && child < ImageBase) { return(false); } if (sibling != 0 && sibling < ImageBase) { return(false); } if (numhierarchy != -1 && child != 0 && !CheckModel(child - ImageBase, -1, modelfmt)) { return(false); } if (numhierarchy != -1 && sibling != 0 && !CheckModel(sibling - ImageBase, -1, modelfmt)) { return(false); } if (attach == 0 && flags == 0) { return(false); } if (attach == 0 && child == 0 && sibling == 0) { return(false); } if (child == address + ImageBase || child == attach) { return(false); } if (sibling == address + ImageBase || sibling == attach) { return(false); } if (child != 0 && child == sibling) { return(false); } if (numhierarchy != -1 && child != 0) { if (numhierarchy < 3) { numhierarchy++; return(CheckModel(child - ImageBase, numhierarchy, modelfmt)); } else { return(CheckModel(child - ImageBase, -1, modelfmt)); } } if (numhierarchy != -1 && sibling != 0) { if (numhierarchy < 3) { numhierarchy++; return(CheckModel(sibling - ImageBase, numhierarchy, modelfmt)); } else { return(CheckModel(sibling - ImageBase, -1, modelfmt)); } } if (attach == 0 && flags == 0) { return(false); } break; } if (numhierarchy != -1) { Console.WriteLine("Trying {0} model at {1}", modelfmt.ToString(), address.ToString("X")); } return(true); }
public static void CreateFile(string filename, NJS_OBJECT model, string[] animationFiles, string author, string description, Dictionary <uint, byte[]> metadata, ModelFormat format, bool nometa = false, bool useNinjaMetaData = false) { uint ninjaMagic; uint imageBase = (uint)(useNinjaMetaData ? 0 : 0x10); bool be = ByteConverter.BigEndian; if (useNinjaMetaData == false) { ByteConverter.BigEndian = false; } if (format == ModelFormat.BasicDX) { format = ModelFormat.Basic; } List <byte> file = new List <byte>(); ulong magic; switch (format) { case ModelFormat.Basic: case ModelFormat.BasicDX: magic = SA1MDLVer; ninjaMagic = NJBMMagic; break; case ModelFormat.Chunk: magic = SA2MDLVer; ninjaMagic = NJCMMagic; break; case ModelFormat.GC: magic = SA2BMDLVer; ninjaMagic = GJCMMagic; break; case ModelFormat.XJ: magic = XJMDLVer; ninjaMagic = NJCMMagic; //XJ uses Chunk's magic break; default: throw new ArgumentException("Cannot save " + format.ToString() + " format models to file!", "format"); } Dictionary <string, uint> labels = new Dictionary <string, uint>(); List <uint> njOffsets = new List <uint>(); byte[] mdl; uint addr; if (useNinjaMetaData == true) { mdl = model.NJGetBytes(imageBase, false, labels, njOffsets, out addr); //***Ninja metadata should always be little endian!*** file.AddRange(BitConverter.GetBytes(ninjaMagic)); file.AddRange(BitConverter.GetBytes(mdl.Length)); //***Ninja metadata should always be little endian!*** } else { mdl = model.GetBytes(imageBase, false, labels, njOffsets, out addr); file.AddRange(ByteConverter.GetBytes(magic)); file.AddRange(ByteConverter.GetBytes(addr + 0x10)); file.AddRange(ByteConverter.GetBytes(mdl.Length + 0x10)); } file.AddRange(mdl); if (!nometa) { if (labels.Count > 0) { List <byte> chunk = new List <byte>((labels.Count * 8) + 8); int straddr = (labels.Count * 8) + 8; List <byte> strbytes = new List <byte>(); foreach (KeyValuePair <string, uint> label in labels) { chunk.AddRange(ByteConverter.GetBytes(label.Value)); chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count)); strbytes.AddRange(Encoding.UTF8.GetBytes(label.Key)); strbytes.Add(0); strbytes.Align(4); } chunk.AddRange(ByteConverter.GetBytes(-1L)); chunk.AddRange(strbytes); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Label)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (animationFiles != null && animationFiles.Length > 0) { using (TextWriter tw = File.CreateText(Path.ChangeExtension(filename, ".action"))) { for (int a = 0; a < animationFiles.Count(); a++) { tw.WriteLine(animationFiles[a]); } tw.Flush(); tw.Close(); } /* * //Old animation code * List<byte> chunk = new List<byte>((animationFiles.Length + 1) * 4); * int straddr = (animationFiles.Length + 1) * 4; * List<byte> strbytes = new List<byte>(); * for (int i = 0; i < animationFiles.Length; i++) * { * chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count)); * strbytes.AddRange(Encoding.UTF8.GetBytes(animationFiles[i])); * strbytes.Add(0); * strbytes.Align(4); * } * chunk.AddRange(ByteConverter.GetBytes(-1)); * chunk.AddRange(strbytes); * file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Animation)); * file.AddRange(ByteConverter.GetBytes(chunk.Count)); * file.AddRange(chunk); */ } if (!string.IsNullOrEmpty(author)) { List <byte> chunk = new List <byte>(author.Length + 1); chunk.AddRange(Encoding.UTF8.GetBytes(author)); chunk.Add(0); chunk.Align(4); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Author)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (!string.IsNullOrEmpty(description)) { List <byte> chunk = new List <byte>(description.Length + 1); chunk.AddRange(Encoding.UTF8.GetBytes(description)); chunk.Add(0); chunk.Align(4); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Description)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (metadata != null) { foreach (KeyValuePair <uint, byte[]> item in metadata) { file.AddRange(ByteConverter.GetBytes(item.Key)); file.AddRange(ByteConverter.GetBytes(item.Value.Length)); file.AddRange(item.Value); } } } if (useNinjaMetaData == true) { /* * List<uint> addresses = new List<uint>(); * foreach(var pair in labels) * { * if(pair.Value != 0) * { * addresses.Add(pair.Value); * } * } * addresses.Insert(0, 0x4); * addresses.Sort();*/ njOffsets = njOffsets.Distinct().ToList(); njOffsets.Sort(); List <byte> pof0 = new List <byte>(); pof0.Add(0x41); for (int i = 1; i < njOffsets.Count; i++) { pof0.AddRange(POF0Helper.calcPOF0Pointer(njOffsets[i - 1], njOffsets[i])); } POF0Helper.finalizePOF0(pof0); file.AddRange(pof0); if (metadata.Count != 0 && metadata.ContainsKey(uint.MaxValue)) { file.InsertRange(0, metadata[uint.MaxValue]); } } else { file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.End)); file.AddRange(new byte[4]); } File.WriteAllBytes(filename, file.ToArray()); ByteConverter.BigEndian = be; }
// Scan for models static void ScanModel(ModelFormat modelfmt) { CurrentStep++; CurrentScanData = "Models " + modelfmt.ToString(); uint scan_end = (EndAddress == 0) ? EndAddress : (uint)datafile.Length - 52; // 52 for NJS_OBJECT ByteConverter.BigEndian = BigEndian; Console.WriteLine("Step {0}: Scanning for {1} models", CurrentStep, modelfmt); string model_extension = ".sa1mdl"; string model_dir = "basicmodels"; string model_type = "NJS_OBJECT"; int count = 0; switch (modelfmt) { case ModelFormat.Basic: default: model_extension = ".sa1mdl"; model_dir = "basicmodels"; model_type = "NJS_OBJECT_OLD"; break; case ModelFormat.BasicDX: model_extension = ".sa1mdl"; model_dir = "basicmodels"; model_type = "NJS_OBJECT"; break; case ModelFormat.Chunk: model_extension = ".sa2mdl"; model_dir = "chunkmodels"; model_type = "NJS_CNK_OBJECT"; break; case ModelFormat.GC: model_extension = ".sa2bmdl"; model_dir = "gcmodels"; model_type = "NJS_GC_OBJECT"; break; } if (!SingleOutputFolder) { Directory.CreateDirectory(Path.Combine(OutputFolder, model_dir)); } for (uint address = StartAddress; address < scan_end; address += 1) { if (CancelScan) { break; } if (ConsoleMode && address % 1000 == 0) { Console.Write("\r{0} ", address.ToString("X8")); } CurrentAddress = address; string fileOutputPath = Path.Combine(OutputFolder, model_dir, address.ToString("X8")); if (SingleOutputFolder) { fileOutputPath = Path.Combine(OutputFolder, address.ToString("X8")); } try { if (!CheckModel(address, 0, modelfmt)) { //Console.WriteLine("Not found: {0}", address.ToString("X")); continue; } //else Console.WriteLine("found: {0}", address.ToString("X")); NJS_OBJECT mdl = new NJS_OBJECT(datafile, (int)address, ImageBase, modelfmt, new Dictionary <int, Attach>()); // Additional checks to prevent false positives with empty nodes if (CheckForModelData(mdl)) { ModelFile.CreateFile(fileOutputPath + model_extension, mdl, null, null, null, null, modelfmt, NoMeta); count++; switch (modelfmt) { case ModelFormat.Basic: case ModelFormat.BasicDX: FoundBasicModels++; break; case ModelFormat.Chunk: FoundChunkModels++; break; case ModelFormat.GC: FoundGCModels++; break; default: break; } addresslist.Add(address, model_type); if (!KeepChildModels) { DeleteChildModels(mdl, model_dir, model_extension); } } } catch (Exception ex) { Console.WriteLine("\rError adding model at {0}: {1}", address.ToString("X"), ex.Message.ToString()); continue; } } Console.WriteLine("\r{0} models found", count); }
public static void CreateFile(string filename, NJS_OBJECT model, string[] animationFiles, string[] morphFiles, string author, string description, string tool, Dictionary<uint, byte[]> metadata, ModelFormat format) { bool be = ByteConverter.BigEndian; ByteConverter.BigEndian = false; if (format == ModelFormat.BasicDX) format = ModelFormat.Basic; List<byte> file = new List<byte>(); ulong magic; switch (format) { case ModelFormat.Basic: case ModelFormat.BasicDX: magic = SA1MDLVer; break; case ModelFormat.Chunk: magic = SA2MDLVer; break; default: throw new ArgumentException("Cannot save " + format.ToString() + " format models to file!", "format"); } file.AddRange(ByteConverter.GetBytes(magic)); uint addr; Dictionary<string, uint> labels = new Dictionary<string, uint>(); byte[] mdl = model.GetBytes(0x10, false, labels, out addr); file.AddRange(ByteConverter.GetBytes(addr + 0x10)); file.AddRange(ByteConverter.GetBytes(mdl.Length + 0x10)); file.AddRange(mdl); if (labels.Count > 0) { List<byte> chunk = new List<byte>((labels.Count * 8) + 8); int straddr = (labels.Count * 8) + 8; List<byte> strbytes = new List<byte>(); foreach (KeyValuePair<string, uint> label in labels) { chunk.AddRange(ByteConverter.GetBytes(label.Value)); chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count)); strbytes.AddRange(Encoding.UTF8.GetBytes(label.Key)); strbytes.Add(0); strbytes.Align(4); } chunk.AddRange(ByteConverter.GetBytes(-1L)); chunk.AddRange(strbytes); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Label)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (animationFiles != null && animationFiles.Length > 0) { List<byte> chunk = new List<byte>((animationFiles.Length + 1) * 4); int straddr = (animationFiles.Length + 1) * 4; List<byte> strbytes = new List<byte>(); for (int i = 0; i < animationFiles.Length; i++) { chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count)); strbytes.AddRange(Encoding.UTF8.GetBytes(animationFiles[i])); strbytes.Add(0); strbytes.Align(4); } chunk.AddRange(ByteConverter.GetBytes(-1)); chunk.AddRange(strbytes); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Animation)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (morphFiles != null && morphFiles.Length > 0) { List<byte> chunk = new List<byte>((morphFiles.Length + 1) * 4); int straddr = (morphFiles.Length + 1) * 4; List<byte> strbytes = new List<byte>(); for (int i = 0; i < morphFiles.Length; i++) { chunk.AddRange(ByteConverter.GetBytes(straddr + strbytes.Count)); strbytes.AddRange(Encoding.UTF8.GetBytes(morphFiles[i])); strbytes.Add(0); strbytes.Align(4); } chunk.AddRange(ByteConverter.GetBytes(-1)); chunk.AddRange(strbytes); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Morph)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (!string.IsNullOrEmpty(author)) { List<byte> chunk = new List<byte>(author.Length + 1); chunk.AddRange(Encoding.UTF8.GetBytes(author)); chunk.Add(0); chunk.Align(4); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Author)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (!string.IsNullOrEmpty(description)) { List<byte> chunk = new List<byte>(description.Length + 1); chunk.AddRange(Encoding.UTF8.GetBytes(description)); chunk.Add(0); chunk.Align(4); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Description)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (!string.IsNullOrEmpty(tool)) { List<byte> chunk = new List<byte>(tool.Length + 1); chunk.AddRange(Encoding.UTF8.GetBytes(tool)); chunk.Add(0); chunk.Align(4); file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.Tool)); file.AddRange(ByteConverter.GetBytes(chunk.Count)); file.AddRange(chunk); } if (metadata != null) { foreach (KeyValuePair<uint, byte[]> item in metadata) { file.AddRange(ByteConverter.GetBytes(item.Key)); file.AddRange(ByteConverter.GetBytes(item.Value.Length)); file.AddRange(item.Value); } } file.AddRange(ByteConverter.GetBytes((uint)ChunkTypes.End)); file.AddRange(new byte[4]); File.WriteAllBytes(filename, file.ToArray()); ByteConverter.BigEndian = be; }