Example #1
0
        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;
        }
Example #2
0
        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);
        }
Example #3
0
        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;
        }
Example #4
0
        // 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);
        }
Example #5
0
        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;
        }