Beispiel #1
0
 public void Load(string adtFileName, string wdtFileName)
 {
     WdtFile = new WDT.WDT();
     WdtFile.Load(wdtFileName);
     using (var reader = new BinaryReader(File.OpenRead(adtFileName)))
     {
         while (reader.BaseStream.Position < reader.BaseStream.Length)
         {
             var chunkName = new string(reader.ReadChars(4).Reverse().ToArray());
             var chunkSize = reader.ReadInt32();
             var chunkType = Type.GetType(chunkName);
             if (chunkType != null)
             {
                 // If chunkType is an array, it can only be MCNK
                 if (chunkType.IsArray)
                 {
                     MCNK[MCNK.Count(c => c != null)] = (MCNK)Activator.CreateInstance(typeof(MCNK), reader.ReadBytes(chunkSize), WdtFile);
                 }
                 else
                 {
                     GetType().GetProperty(chunkName)?.SetValue(this, Activator.CreateInstance(chunkType, reader.ReadBytes(chunkSize)));
                 }
             }
         }
     }
 }
Beispiel #2
0
 public MCLQ(byte[] chunkBytes, MCNK parentChunk) : base(chunkBytes)
 {
     MinHeight = ReadSingle();
     MaxHeight = ReadSingle();
     for (int i = 0; i < 81; i++)
     {
         if (parentChunk.Flags.HasFlag(MCNKFlags.LiquidMagma))
         {
             Vertices[i] = new Magma();
         }
         else if (parentChunk.Flags.HasFlag(MCNKFlags.LiquidOcean))
         {
             Vertices[i] = new Ocean();
         }
         else
         {
             Vertices[i] = new Water();
         }
         Vertices[i].Read(this);
     }
     for (int i = 0; i < 9; i++)
     {
         for (int j = 0; j < 9; j++)
         {
             Tiles[i, j] = ReadByte();
         }
     }
     NumberFlowvs = ReadUInt32();
     for (int i = 0; i < 3; i++)
     {
         Flowvs[i].Read(this);
     }
     Close();
 }
Beispiel #3
0
        private MCNK Read335MCNKChunk(uint size, BinaryReader bin)
        {
            var mapchunk = new MCNK()
            {
                header = bin.Read <MCNKheader>()
            };

            using (var stream = new MemoryStream(bin.ReadBytes((int)size - 128)))
                using (var subbin = new BinaryReader(stream))
                {
                    long subpos = 0;
                    while (subpos < stream.Length)
                    {
                        subbin.BaseStream.Position = subpos;

                        var subChunkName = new string(subbin.ReadChars(4).Reverse().ToArray());
                        var subChunkSize = subbin.ReadUInt32();

                        subpos = stream.Position + subChunkSize;

                        switch (subChunkName)
                        {
                        case "MCVT":
                            mapchunk.vertices = ReadMCVTSubChunk(subbin);
                            break;

                        case "MCNR":
                            mapchunk.normals = ReadMCNRSubChunk(subbin);
                            subpos           = subpos + 13; //The weird data that the wiki speaks about [Thanks Marl!]
                            break;

                        case "MCLY":
                            adtfile.texChunks[currentChunk].layers = ReadMCLYSubChunk(subChunkSize, subbin); //very ghetto, much wow
                            break;

                        case "MCRF":
                            break;

                        case "MCSH":
                            break;

                        case "MCAL":
                            adtfile.texChunks[currentChunk].alphaLayer = ReadMCALSubChunk(subChunkSize, subbin, adtfile.texChunks[currentChunk]); //very ghetto, much wow
                            break;

                        case "MCLQ": //FIND PROPER PLACE IN STACK (not that it matters)

                        case "MCSE":
                            mapchunk.soundEmitters = ReadMCSESubChunk(subChunkSize, subbin);
                            break;

                        default:
                            throw new Exception(string.Format("Found unknown header at offset {1} \"{0}\" while we should've already read them all! (Total size: {2})", subChunkName, subpos.ToString(), size));
                        }
                    }
                }

            return(mapchunk);
        }
Beispiel #4
0
 public MCSE(byte[] chunkBytes, MCNK parentChunk) : base(chunkBytes)
 {
     for (int i = 0; i < parentChunk.NumberSoundEmitters; i++)
     {
         SoundEmitters[i] = new SoundEmitter(this);
     }
     Close();
 }
Beispiel #5
0
        // Read in an MCNK chunk at supplied offset.
        private MCNK parseMapChunk(FileStream ms, uint offset, uint size)
        {
            BinaryReader bin = new BinaryReader(ms);

            ms.Position = offset;

            BlizChunkHeader tempHeader = new BlizChunkHeader(bin.ReadChars(4), bin.ReadUInt32());

            tempHeader.Flip();

            if (!tempHeader.Is("MCNK"))
            {
                throw new Exception("This was supposed to be an MCNK chunk. Wtf?");
            }

            long lastpos = ms.Position + tempHeader.Size;

            MCNK mapChunk = new MCNK();

            mapChunk.flags          = bin.ReadUInt32();
            mapChunk.ix             = bin.ReadUInt32();
            mapChunk.iy             = bin.ReadUInt32();
            mapChunk.nLayers        = bin.ReadUInt32();
            mapChunk.nDoodadRefs    = bin.ReadUInt32();
            mapChunk.ofsHeight      = bin.ReadUInt32();
            mapChunk.ofsNormal      = bin.ReadUInt32();
            mapChunk.ofsLayer       = bin.ReadUInt32();
            mapChunk.ofsRefs        = bin.ReadUInt32();
            mapChunk.ofsAlpha       = bin.ReadUInt32();
            mapChunk.sizeAlpha      = bin.ReadUInt32();
            mapChunk.ofsShadow      = bin.ReadUInt32();
            mapChunk.sizeShadow     = bin.ReadUInt32();
            mapChunk.areaid         = bin.ReadUInt32();
            mapChunk.nMapObjRefs    = bin.ReadUInt32();
            mapChunk.holes          = bin.ReadUInt32();
            mapChunk.s1             = bin.ReadUInt16();
            mapChunk.s2             = bin.ReadUInt16();
            mapChunk.d1             = bin.ReadUInt32();
            mapChunk.d2             = bin.ReadUInt32();
            mapChunk.d3             = bin.ReadUInt32();
            mapChunk.predTex        = bin.ReadUInt32();
            mapChunk.nEffectDoodad  = bin.ReadUInt32();
            mapChunk.ofsSndEmitters = bin.ReadUInt32();
            mapChunk.nSndEmitters   = bin.ReadUInt32();
            mapChunk.ofsLiquid      = bin.ReadUInt32();
            mapChunk.sizeLiquid     = bin.ReadUInt32();
            mapChunk.zpos           = bin.ReadSingle();
            mapChunk.xpos           = bin.ReadSingle();
            mapChunk.ypos           = bin.ReadSingle();
            mapChunk.textureId      = bin.ReadUInt32();
            mapChunk.props          = bin.ReadUInt32();
            mapChunk.effectId       = bin.ReadUInt32();

            // Parse this MapChunk's SubChunks!
            parseMapChunkSubChunks(ref mapChunk, ms, lastpos);

            return(mapChunk);
        }
Beispiel #6
0
 public MCAL(byte[] chunkBytes, MCNK parentChunk, WDT.WDT wdt) : base(chunkBytes)
 {
     AlphaMaps = new MCALAlphaMap[parentChunk.MCLY.Layers.Length];
     for (int i = 0; i < parentChunk.MCLY.Layers.Length; i++)
     {
         AlphaMaps[i] = new MCALAlphaMap(this, parentChunk, wdt, i);
     }
     Close();
 }
Beispiel #7
0
        public MCNK ReadMCNKChunk(BlizzHeader chunk, BinaryReader bin)
        {
            //256 of these chunks per file
            MCNK mapchunk = new MCNK();

            mapchunk.header = bin.Read <MCNKheader>();

            MemoryStream stream = new MemoryStream(bin.ReadBytes((int)chunk.Size - 128));

            var subbin = new BinaryReader(stream);

            BlizzHeader subchunk;

            long subpos = 0;

            while (subpos < stream.Length)
            {
                subbin.BaseStream.Position = subpos;
                subchunk = new BlizzHeader(subbin.ReadChars(4), subbin.ReadUInt32());
                subchunk.Flip();
                subpos = stream.Position + subchunk.Size;

                switch (subchunk.ToString())
                {
                case "MCVT":
                    mapchunk.vertices = ReadMCVTSubChunk(subchunk, subbin);
                    break;

                case "MCCV":
                    mapchunk.vertexShading = ReadMCCVSubChunk(subchunk, subbin);
                    break;

                case "MCNR":
                    mapchunk.normals = ReadMCNRSubChunk(subchunk, subbin);
                    break;

                case "MCSE":
                    mapchunk.soundEmitters = ReadMCSESubChunk(subchunk, subbin);
                    break;

                case "MCBB":
                    mapchunk.blendBatches = ReadMCBBSubChunk(subchunk, subbin);
                    break;

                case "MCLQ":
                case "MCLV":
                    continue;

                default:
                    throw new Exception(String.Format("Found unknown header at offset {1} \"{0}\" while we should've already read them all!", subchunk.ToString(), subpos.ToString()));
                }
            }
            return(mapchunk);
        }
Beispiel #8
0
        private MCNK ReadMCNKChunk(uint size, BinaryReader bin)
        {
            MCNK mapchunk = new MCNK()
            {
                header = bin.Read <MCNKheader>()
            };

            using (var stream = new MemoryStream(bin.ReadBytes((int)size - 128)))
                using (var subbin = new BinaryReader(stream))
                {
                    long subpos = 0;
                    while (subpos < stream.Length)
                    {
                        subbin.BaseStream.Position = subpos;

                        var subChunkName = new string(subbin.ReadChars(4).Reverse().ToArray());
                        var subChunkSize = subbin.ReadUInt32();

                        subpos = stream.Position + subChunkSize;

                        switch (subChunkName)
                        {
                        case "MCVT":
                            mapchunk.vertices = ReadMCVTSubChunk(subbin);
                            break;

                        case "MCCV":
                            mapchunk.vertexShading = ReadMCCVSubChunk(subbin);
                            break;

                        case "MCNR":
                            mapchunk.normals = ReadMCNRSubChunk(subbin);
                            break;

                        case "MCSE":
                            mapchunk.soundEmitters = ReadMCSESubChunk(subChunkSize, subbin);
                            break;

                        case "MCBB":
                            mapchunk.blendBatches = ReadMCBBSubChunk(subChunkSize, subbin);
                            break;

                        case "MCLQ":
                        case "MCLV":
                            continue;

                        default:
                            throw new Exception(String.Format("Found unknown header at offset {1} \"{0}\" while we should've already read them all!", subChunkName, subpos.ToString()));
                        }
                    }
                }

            return(mapchunk);
        }
Beispiel #9
0
        public MapChunk(ADT adt, Chunk chunk, bool isObj0 = false)
        {
            ADT   = adt;
            Chunk = chunk;

            MCNK  = new MCNK(chunk);
            Holes = MCNK.Flags.HasFlag(MCNK.MCNKFlags.HighResolutionHoles) ? HighResHoles : TransformToHighRes(MCNK.Holes);

            var stream = chunk.GetStream();

            stream.Seek(chunk.Offset + MCNK.ChunkHeaderSize, SeekOrigin.Begin);

            Read(new ChunkData(stream, chunk.Size - MCNK.ChunkHeaderSize));
        }
Beispiel #10
0
 public byte[] GetChunkBytes(MCNK parentChunk, WDT.WDT wdt)
 {
     using (var stream = new MemoryStream())
     {
         using (var writer = new BinaryWriter(stream))
         {
             for (int i = 0; i < AlphaMaps.Length; i++)
             {
                 AlphaMaps[i].Write(writer, parentChunk, wdt, i);
             }
         }
         return(stream.ToArray());
     }
 }
Beispiel #11
0
        /// <summary>
        /// Parse all MCNK element from file stream
        /// </summary>
        public override MCNK[,] Parse()
        {
            var MCNK  = new MCNK[16, 16];
            int count = 0;

            for (int y = 0; y < 16; y++)
            {
                for (int x = 0; x < 16; x++)
                {
                    MCNK[x, y] = processMCNK(_mcins[count].Offset);
                    count++;
                }
            }
            return(MCNK);            // processMH2Os();
        }
Beispiel #12
0
        public MCRF(byte[] chunkBytes, MCNK parentChunk) : base(chunkBytes)
        {
            DoodadReferences = new uint[parentChunk.NumberDoodadRefs];
            ObjectReferences = new uint[parentChunk.NumberMapObjectRefs];

            for (int i = 0; i < DoodadReferences.Length; i++)
            {
                DoodadReferences[i] = ReadUInt32();
            }
            for (int i = 0; i < ObjectReferences.Length; i++)
            {
                ObjectReferences[i] = ReadUInt32();
            }
            Close();
        }
Beispiel #13
0
        /// <summary>
        /// Processes an individual MCNK Chunk
        /// </summary>
        /// <param name="offset">Offset to the MCNK Chunk</param>
        /// <returns>MCNK Filled with information</returns>
        private MCNK processMCNK(UInt32 offset)
        {
            Reader.BaseStream.Position = offset + 12;             // Get off the header
            //br.ReadBytes(4); // Data that's not needed
            var index_x = (int)Reader.ReadUInt32();
            var index_y = (int)Reader.ReadUInt32();

            Reader.BaseStream.Position = offset + 0x08 + 0x03C;             // Get off the header
            uint holes = Reader.ReadUInt32() & 0x00FF;

            if (holes > 0)
            {
                Console.WriteLine(Convert.ToString(holes, 2));
            }


            Reader.BaseStream.Position = offset + 0x08 + 0x068;
            //br.BaseStream.Position += 28; // Get past the data we don't want
            //UInt32 offsLiquid = br.ReadUInt32(); // Offset to the liquid information
            //UInt32 sizeLiquid = br.ReadUInt32(); // If there's no liquid information it will be 8

            float z           = Reader.ReadSingle();
            float x           = Reader.ReadSingle();
            float y           = Reader.ReadSingle();
            var   currentMCNK = new MCNK(x, y, z, (UInt16)holes);

            Reader.ReadBytes(20);             // Read the reaming 12 bytes of data and 8 for the next header which is a MCVT chunk
            for (int i = 0; i < 145; i++)
            {
                currentMCNK._MCVT.heights[i] = Reader.ReadSingle();
            }
            Reader.ReadBytes(8);             // We're going to read past the next header which is for the normals

            sbyte normalZ = 0;
            sbyte normalX = 0;
            sbyte normalY = 0;

            for (int i = 0; i < 145; i++)
            {
                normalZ = Reader.ReadSByte();
                normalX = Reader.ReadSByte();
                normalY = Reader.ReadSByte();
                currentMCNK._MCNR.normals[i] = new Vector3(-(float)normalX / 127.0f, normalY / 127.0f, -(float)normalZ / 127.0f);
            }
            return(currentMCNK);
        }
Beispiel #14
0
        public static bool ConvertADT(ChunkedFile adt, string mapName, string outputPath, int gx, int gy, uint build, bool ignoreDeepWater)
        {
            // Prepare map header
            MapFileHeader map;

            map.mapMagic     = SharedConst.MAP_MAGIC;
            map.versionMagic = SharedConst.MAP_VERSION_MAGIC;
            map.buildMagic   = build;

            // Get area flags data
            for (var x = 0; x < SharedConst.ADT_CELLS_PER_GRID; ++x)
            {
                for (var y = 0; y < SharedConst.ADT_CELLS_PER_GRID; ++y)
                {
                    AreaIDs[x][y]       = 0;
                    LiquidEntries[x][y] = 0;
                    LiquidFlags[x][y]   = 0;
                }
            }

            for (var x = 0; x < SharedConst.ADT_GRID_SIZE; ++x)
            {
                for (var y = 0; y < SharedConst.ADT_GRID_SIZE; ++y)
                {
                    V8[x][y]         = 0;
                    LiquidSnow[x][y] = false;
                }
            }

            for (var x = 0; x < SharedConst.ADT_GRID_SIZE + 1; ++x)
            {
                for (var y = 0; y < SharedConst.ADT_GRID_SIZE + 1; ++y)
                {
                    V9[x][y] = 0;
                }
            }

            for (var x = 0; x < SharedConst.ADT_CELLS_PER_GRID; ++x)
            {
                for (var y = 0; y < SharedConst.ADT_CELLS_PER_GRID; ++y)
                {
                    for (var z = 0; z < 8; ++z)
                    {
                        Holes[x][y][z] = 0;
                    }
                }
            }

            bool hasHoles     = false;
            bool hasFlightBox = false;

            foreach (var fileChunk in adt.chunks.LookupByKey("MCNK"))
            {
                MCNK mcnk = fileChunk.As <MCNK>();

                // Area data
                AreaIDs[mcnk.IndexY][mcnk.IndexX] = (ushort)mcnk.AreaID;

                // Height
                // Height values for triangles stored in order:
                // 1     2     3     4     5     6     7     8     9
                //    10    11    12    13    14    15    16    17
                // 18    19    20    21    22    23    24    25    26
                //    27    28    29    30    31    32    33    34
                // . . . . . . . .
                // For better get height values merge it to V9 and V8 map
                // V9 height map:
                // 1     2     3     4     5     6     7     8     9
                // 18    19    20    21    22    23    24    25    26
                // . . . . . . . .
                // V8 height map:
                //    10    11    12    13    14    15    16    17
                //    27    28    29    30    31    32    33    34
                // . . . . . . . .

                // Set map height as grid height
                for (int y = 0; y <= SharedConst.ADT_CELL_SIZE; y++)
                {
                    int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                    for (int x = 0; x <= SharedConst.ADT_CELL_SIZE; x++)
                    {
                        int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                        V9[cy][cx] = mcnk.ypos;
                    }
                }

                for (int y = 0; y < SharedConst.ADT_CELL_SIZE; y++)
                {
                    int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                    for (int x = 0; x < SharedConst.ADT_CELL_SIZE; x++)
                    {
                        int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                        V8[cy][cx] = mcnk.ypos;
                    }
                }

                // Get custom height
                FileChunk chunk = fileChunk.GetSubChunk("MCVT");
                if (chunk != null)
                {
                    MCVT mcvt = chunk.As <MCVT>();

                    // get V9 height map
                    for (int y = 0; y <= SharedConst.ADT_CELL_SIZE; y++)
                    {
                        int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                        for (int x = 0; x <= SharedConst.ADT_CELL_SIZE; x++)
                        {
                            int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                            V9[cy][cx] += mcvt.HeightMap[y * (SharedConst.ADT_CELL_SIZE * 2 + 1) + x];
                        }
                    }
                    // get V8 height map
                    for (int y = 0; y < SharedConst.ADT_CELL_SIZE; y++)
                    {
                        int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                        for (int x = 0; x < SharedConst.ADT_CELL_SIZE; x++)
                        {
                            int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                            V8[cy][cx] += mcvt.HeightMap[y * (SharedConst.ADT_CELL_SIZE * 2 + 1) + SharedConst.ADT_CELL_SIZE + 1 + x];
                        }
                    }
                }

                // Liquid data
                if (mcnk.MCLQCount > 8)
                {
                    FileChunk lquidChunk = fileChunk.GetSubChunk("MCLQ");
                    if (lquidChunk != null)
                    {
                        MCLQ liquid = lquidChunk.As <MCLQ>();
                        int  count  = 0;
                        for (int y = 0; y < SharedConst.ADT_CELL_SIZE; ++y)
                        {
                            int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                            for (int x = 0; x < SharedConst.ADT_CELL_SIZE; ++x)
                            {
                                int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                                if (liquid.Flags[y][x] != 0x0F)
                                {
                                    LiquidSnow[cy][cx] = true;
                                    if (!ignoreDeepWater && Convert.ToBoolean(liquid.Flags[y][x] & (1 << 7)))
                                    {
                                        LiquidFlags[mcnk.IndexY][mcnk.IndexX] |= LiquidHeaderTypeFlags.DarkWater;
                                    }
                                    ++count;
                                }
                            }
                        }

                        if (mcnk.Flags.HasAnyFlag(MCNKFlags.LiquidRiver))
                        {
                            LiquidEntries[mcnk.IndexY][mcnk.IndexX] = 1;
                            LiquidFlags[mcnk.IndexY][mcnk.IndexX]  |= LiquidHeaderTypeFlags.Water;           // water
                        }
                        if (mcnk.Flags.HasAnyFlag(MCNKFlags.LiquidOcean))
                        {
                            LiquidEntries[mcnk.IndexY][mcnk.IndexX] = 2;
                            LiquidFlags[mcnk.IndexY][mcnk.IndexX]  |= LiquidHeaderTypeFlags.Ocean;           // ocean
                        }
                        if (mcnk.Flags.HasAnyFlag(MCNKFlags.LiquidMagma))
                        {
                            LiquidEntries[mcnk.IndexY][mcnk.IndexX] = 3;
                            LiquidFlags[mcnk.IndexY][mcnk.IndexX]  |= LiquidHeaderTypeFlags.Magma;           // magma
                        }
                        if (mcnk.Flags.HasAnyFlag(MCNKFlags.LiquidSlime))
                        {
                            LiquidEntries[mcnk.IndexY][mcnk.IndexX] = 4;
                            LiquidFlags[mcnk.IndexY][mcnk.IndexX]  |= LiquidHeaderTypeFlags.Slime;           // slime
                        }

                        if (count == 0 && LiquidFlags[mcnk.IndexY][mcnk.IndexX] != 0)
                        {
                            Console.WriteLine("Wrong liquid detect in MCLQ chunk");
                        }

                        for (int y = 0; y <= SharedConst.ADT_CELL_SIZE; ++y)
                        {
                            int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                            for (int x = 0; x <= SharedConst.ADT_CELL_SIZE; ++x)
                            {
                                int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                                LiquidHeight[cy][cx] = liquid.Liquid[y][x].Height;
                            }
                        }
                    }
                }

                // Hole data
                if (!mcnk.Flags.HasAnyFlag(MCNKFlags.HighResHoles))
                {
                    uint hole = mcnk.HolesLowRes;
                    if (hole != 0)
                    {
                        if (TransformToHighRes((ushort)hole, Holes[mcnk.IndexY][mcnk.IndexX]))
                        {
                            hasHoles = true;
                        }
                    }
                }
                else
                {
                    Buffer.BlockCopy(mcnk.HighResHoles, 0, Holes[mcnk.IndexY][mcnk.IndexX], 0, 8);
                    if (BitConverter.ToUInt64(Holes[mcnk.IndexY][mcnk.IndexX], 0) != 0)
                    {
                        hasHoles = true;
                    }
                }
            }

            // Get liquid map for grid (in WOTLK used MH2O chunk)
            FileChunk chunkMH2O = adt.GetChunk("MH2O");

            if (chunkMH2O != null)
            {
                MH2O h2o = chunkMH2O.As <MH2O>();
                for (int i = 0; i < SharedConst.ADT_CELLS_PER_GRID; i++)
                {
                    for (int j = 0; j < SharedConst.ADT_CELLS_PER_GRID; j++)
                    {
                        MH2OInstance?h = h2o.GetLiquidInstance(i, j);
                        if (!h.HasValue)
                        {
                            continue;
                        }

                        MH2OInstance       adtLiquidHeader = h.Value;
                        MH2OChunkAttribute?attrs           = h2o.GetLiquidAttributes(i, j);

                        int   count      = 0;
                        ulong existsMask = h2o.GetLiquidExistsBitmap(adtLiquidHeader);
                        for (int y = 0; y < adtLiquidHeader.GetHeight(); y++)
                        {
                            int cy = i * SharedConst.ADT_CELL_SIZE + y + adtLiquidHeader.GetOffsetY();
                            for (int x = 0; x < adtLiquidHeader.GetWidth(); x++)
                            {
                                int cx = j * SharedConst.ADT_CELL_SIZE + x + adtLiquidHeader.GetOffsetX();
                                if (Convert.ToBoolean(existsMask & 1))
                                {
                                    LiquidSnow[cy][cx] = true;
                                    ++count;
                                }
                                existsMask >>= 1;
                            }
                        }

                        LiquidEntries[i][j] = h2o.GetLiquidType(adtLiquidHeader);
                        if (LiquidEntries[i][j] != 0)
                        {
                            var liquidTypeRecord = LiquidTypeStorage[LiquidEntries[i][j]];
                            switch ((LiquidType)liquidTypeRecord.SoundBank)
                            {
                            case LiquidType.Water:
                                LiquidFlags[i][j] |= LiquidHeaderTypeFlags.Water;
                                break;

                            case LiquidType.Ocean:
                                LiquidFlags[i][j] |= LiquidHeaderTypeFlags.Ocean;
                                if (!ignoreDeepWater && attrs.Value.Deep != 0)
                                {
                                    LiquidFlags[i][j] |= LiquidHeaderTypeFlags.DarkWater;
                                }
                                break;

                            case LiquidType.Magma:
                                LiquidFlags[i][j] |= LiquidHeaderTypeFlags.Magma;
                                break;

                            case LiquidType.Slime:
                                LiquidFlags[i][j] |= LiquidHeaderTypeFlags.Slime;
                                break;

                            default:
                                Console.WriteLine($"\nCan't find Liquid type {adtLiquidHeader.LiquidType} for map {mapName}\nchunk {i},{j}\n");
                                break;
                            }

                            if (count == 0 && LiquidFlags[i][j] != 0)
                            {
                                Console.WriteLine("Wrong liquid detect in MH2O chunk");
                            }
                        }
                        else
                        {
                            Console.WriteLine($"LiquidEntries is 0 for [{i}][{j}] ({i * j})");
                        }

                        int pos = 0;
                        for (int y = 0; y <= adtLiquidHeader.GetHeight(); y++)
                        {
                            int cy = i * SharedConst.ADT_CELL_SIZE + y + adtLiquidHeader.GetOffsetY();
                            for (int x = 0; x <= adtLiquidHeader.GetWidth(); x++)
                            {
                                int cx = j * SharedConst.ADT_CELL_SIZE + x + adtLiquidHeader.GetOffsetX();

                                LiquidHeight[cy][cx] = h2o.GetLiquidHeight(adtLiquidHeader, i, j, pos);

                                pos++;
                            }
                        }
                    }
                }
            }

            FileChunk chunkMFBO = adt.GetChunk("MFBO");

            if (chunkMFBO != null)
            {
                MFBO mfbo = chunkMFBO.As <MFBO>();
                for (var i = 0; i < 3; ++i)
                {
                    FlightBoxMax[i][0] = mfbo.Max.coords[0 + i * 3];
                    FlightBoxMax[i][1] = mfbo.Max.coords[1 + i * 3];
                    FlightBoxMax[i][2] = mfbo.Max.coords[2 + i * 3];

                    FlightBoxMin[i][0] = mfbo.Min.coords[0 + i * 3];
                    FlightBoxMin[i][1] = mfbo.Min.coords[1 + i * 3];
                    FlightBoxMin[i][2] = mfbo.Min.coords[2 + i * 3];
                }
                hasFlightBox = true;
            }

            //============================================
            // Try pack area data
            //============================================
            bool fullAreaData = false;
            uint areaId       = AreaIDs[0][0];

            for (int y = 0; y < SharedConst.ADT_CELLS_PER_GRID; ++y)
            {
                for (int x = 0; x < SharedConst.ADT_CELLS_PER_GRID; ++x)
                {
                    if (AreaIDs[y][x] != areaId)
                    {
                        fullAreaData = true;
                        break;
                    }
                }
            }

            map.areaMapOffset = 44;
            map.areaMapSize   = 8;

            MapAreaHeader areaHeader;

            areaHeader.fourcc = SharedConst.MAP_AREA_MAGIC;
            areaHeader.flags  = 0;
            if (fullAreaData)
            {
                areaHeader.gridArea = 0;
                map.areaMapSize    += 512;
            }
            else
            {
                areaHeader.flags   |= AreaHeaderFlags.NoArea;
                areaHeader.gridArea = (ushort)areaId;
            }

            //============================================
            // Try pack height data
            //============================================
            float maxHeight = -20000;
            float minHeight = 20000;

            for (int y = 0; y < SharedConst.ADT_GRID_SIZE; y++)
            {
                for (int x = 0; x < SharedConst.ADT_GRID_SIZE; x++)
                {
                    float h = V8[y][x];
                    if (maxHeight < h)
                    {
                        maxHeight = h;
                    }
                    if (minHeight > h)
                    {
                        minHeight = h;
                    }
                }
            }
            for (int y = 0; y <= SharedConst.ADT_GRID_SIZE; y++)
            {
                for (int x = 0; x <= SharedConst.ADT_GRID_SIZE; x++)
                {
                    float h = V9[y][x];
                    if (maxHeight < h)
                    {
                        maxHeight = h;
                    }
                    if (minHeight > h)
                    {
                        minHeight = h;
                    }
                }
            }

            // Check for allow limit minimum height (not store height in deep ochean - allow save some memory)
            if (minHeight < -2000.0f)
            {
                for (int y = 0; y < SharedConst.ADT_GRID_SIZE; y++)
                {
                    for (int x = 0; x < SharedConst.ADT_GRID_SIZE; x++)
                    {
                        if (V8[y][x] < -2000.0f)
                        {
                            V8[y][x] = -2000.0f;
                        }
                    }
                }
                for (int y = 0; y <= SharedConst.ADT_GRID_SIZE; y++)
                {
                    for (int x = 0; x <= SharedConst.ADT_GRID_SIZE; x++)
                    {
                        if (V9[y][x] < -2000.0f)
                        {
                            V9[y][x] = -2000.0f;
                        }
                    }
                }

                if (minHeight < -2000.0f)
                {
                    minHeight = -2000.0f;
                }
                if (maxHeight < -2000.0f)
                {
                    maxHeight = -2000.0f;
                }
            }

            map.heightMapOffset = map.areaMapOffset + map.areaMapSize;
            map.heightMapSize   = (uint)Marshal.SizeOf <MapHeightHeader>();

            MapHeightHeader heightHeader;

            heightHeader.fourcc        = SharedConst.MAP_HEIGHT_MAGIC;
            heightHeader.flags         = 0;
            heightHeader.gridHeight    = minHeight;
            heightHeader.gridMaxHeight = maxHeight;

            if (maxHeight == minHeight)
            {
                heightHeader.flags |= HeightHeaderFlags.NoHeight;
            }

            // Not need store if flat surface
            if ((maxHeight - minHeight) < 0.005f)
            {
                heightHeader.flags |= HeightHeaderFlags.NoHeight;
            }

            if (hasFlightBox)
            {
                heightHeader.flags |= HeightHeaderFlags.HasFlightBounds;
                map.heightMapSize  += 18 + 18;
            }

            // Try store as packed in uint16 or uint8 values
            if (!heightHeader.flags.HasFlag(HeightHeaderFlags.NoHeight))
            {
                float step = 0;
                // Try Store as uint values
                if (true)//CONF_allow_float_to_int
                {
                    float diff = maxHeight - minHeight;
                    if (diff < 2.0f)      // As uint8 (max accuracy = CONF_float_to_int8_limit/256)
                    {
                        heightHeader.flags |= HeightHeaderFlags.AsInt8;
                        step = 255 / diff;
                    }
                    else if (diff < 2048.0f)  // As uint16 (max accuracy = CONF_float_to_int16_limit/65536)
                    {
                        heightHeader.flags |= HeightHeaderFlags.AsInt16;
                        step = 65535 / diff;
                    }
                }

                // Pack it to int values if need
                if (heightHeader.flags.HasFlag(HeightHeaderFlags.AsInt8))
                {
                    for (int y = 0; y < SharedConst.ADT_GRID_SIZE; y++)
                    {
                        for (int x = 0; x < SharedConst.ADT_GRID_SIZE; x++)
                        {
                            UInt8_V8[y][x] = (byte)((V8[y][x] - minHeight) * step + 0.5f);
                        }
                    }
                    for (int y = 0; y <= SharedConst.ADT_GRID_SIZE; y++)
                    {
                        for (int x = 0; x <= SharedConst.ADT_GRID_SIZE; x++)
                        {
                            UInt8_V9[y][x] = (byte)((V9[y][x] - minHeight) * step + 0.5f);
                        }
                    }
                    map.heightMapSize += 16641 + 16384;
                }
                else if (heightHeader.flags.HasFlag(HeightHeaderFlags.AsInt16))
                {
                    for (int y = 0; y < SharedConst.ADT_GRID_SIZE; y++)
                    {
                        for (int x = 0; x < SharedConst.ADT_GRID_SIZE; x++)
                        {
                            UInt16_V8[y][x] = (ushort)((V8[y][x] - minHeight) * step + 0.5f);
                        }
                    }

                    for (int y = 0; y <= SharedConst.ADT_GRID_SIZE; y++)
                    {
                        for (int x = 0; x <= SharedConst.ADT_GRID_SIZE; x++)
                        {
                            UInt16_V9[y][x] = (ushort)((V9[y][x] - minHeight) * step + 0.5f);
                        }
                    }

                    map.heightMapSize += 33282 + 32768;
                }
                else
                {
                    map.heightMapSize += 66564 + 65536;
                }
            }

            //============================================
            // Pack liquid data
            //============================================
            ushort firstLiquidType = LiquidEntries[0][0];
            LiquidHeaderTypeFlags firstLiquidFlag = LiquidFlags[0][0];
            bool fullType = false;

            for (int y = 0; y < SharedConst.ADT_CELLS_PER_GRID; y++)
            {
                for (int x = 0; x < SharedConst.ADT_CELLS_PER_GRID; x++)
                {
                    if (LiquidEntries[y][x] != firstLiquidType || LiquidFlags[y][x] != firstLiquidFlag)
                    {
                        fullType = true;
                        y        = SharedConst.ADT_CELLS_PER_GRID;
                        break;
                    }
                }
            }

            MapLiquidHeader mapLiquidHeader = new();

            // no water data (if all grid have 0 liquid type)
            if (firstLiquidFlag == 0 && !fullType)
            {
                // No liquid data
                map.liquidMapOffset = 0;
                map.liquidMapSize   = 0;
            }
            else
            {
                int minX = 255, minY = 255;
                int maxX = 0, maxY = 0;
                maxHeight = -20000;
                minHeight = 20000;
                for (int y = 0; y < SharedConst.ADT_GRID_SIZE; y++)
                {
                    for (int x = 0; x < SharedConst.ADT_GRID_SIZE; x++)
                    {
                        if (LiquidSnow[y][x])
                        {
                            if (minX > x)
                            {
                                minX = x;
                            }
                            if (maxX < x)
                            {
                                maxX = x;
                            }
                            if (minY > y)
                            {
                                minY = y;
                            }
                            if (maxY < y)
                            {
                                maxY = y;
                            }
                            float h = LiquidHeight[y][x];
                            if (maxHeight < h)
                            {
                                maxHeight = h;
                            }
                            if (minHeight > h)
                            {
                                minHeight = h;
                            }
                        }
                        else
                        {
                            LiquidHeight[y][x] = -2000.0f;
                        }
                    }
                }
                map.liquidMapOffset = map.heightMapOffset + map.heightMapSize;
                map.liquidMapSize   = (uint)Marshal.SizeOf <MapLiquidHeader>();

                mapLiquidHeader.fourcc      = SharedConst.MAP_LIQUID_MAGIC;
                mapLiquidHeader.flags       = LiquidHeaderFlags.None;
                mapLiquidHeader.liquidType  = 0;
                mapLiquidHeader.offsetX     = (byte)minX;
                mapLiquidHeader.offsetY     = (byte)minY;
                mapLiquidHeader.width       = (byte)(maxX - minX + 1 + 1);
                mapLiquidHeader.height      = (byte)(maxY - minY + 1 + 1);
                mapLiquidHeader.liquidLevel = minHeight;

                if (maxHeight == minHeight)
                {
                    mapLiquidHeader.flags |= LiquidHeaderFlags.NoHeight;
                }

                // Not need store if flat surface
                if ((maxHeight - minHeight) < 0.001f)
                {
                    mapLiquidHeader.flags |= LiquidHeaderFlags.NoHeight;
                }

                if (!fullType)
                {
                    mapLiquidHeader.flags |= LiquidHeaderFlags.NoType;
                }

                if (mapLiquidHeader.flags.HasFlag(LiquidHeaderFlags.NoType))
                {
                    mapLiquidHeader.liquidFlags = firstLiquidFlag;
                    mapLiquidHeader.liquidType  = firstLiquidType;
                }
                else
                {
                    map.liquidMapSize += 512 + 256;
                }

                if (!mapLiquidHeader.flags.HasFlag(LiquidHeaderFlags.NoHeight))
                {
                    map.liquidMapSize += (uint)(sizeof(float) * mapLiquidHeader.width * mapLiquidHeader.height);
                }
            }

            if (hasHoles)
            {
                if (map.liquidMapOffset != 0)
                {
                    map.holesOffset = map.liquidMapOffset + map.liquidMapSize;
                }
                else
                {
                    map.holesOffset = map.heightMapOffset + map.heightMapSize;
                }

                map.holesSize = 2048;
            }
            else
            {
                map.holesOffset = 0;
                map.holesSize   = 0;
            }

            // Ok all data prepared - store it
            using (BinaryWriter binaryWriter = new(File.Open(outputPath, FileMode.Create, FileAccess.Write)))
            {
                binaryWriter.WriteStruct(map);
                // Store area data
                binaryWriter.WriteStruct(areaHeader);
                if (!areaHeader.flags.HasFlag(AreaHeaderFlags.NoArea))
                {
                    for (var x = 0; x < AreaIDs.Length; ++x)
                    {
                        for (var y = 0; y < AreaIDs[x].Length; ++y)
                        {
                            binaryWriter.Write(AreaIDs[x][y]);
                        }
                    }
                }

                // Store height data
                binaryWriter.WriteStruct(heightHeader);
                if (!heightHeader.flags.HasFlag(HeightHeaderFlags.NoHeight))
                {
                    if (heightHeader.flags.HasFlag(HeightHeaderFlags.AsInt16))
                    {
                        for (var x = 0; x < UInt16_V9.Length; ++x)
                        {
                            for (var y = 0; y < UInt16_V9[x].Length; ++y)
                            {
                                binaryWriter.Write(UInt16_V9[x][y]);
                            }
                        }

                        for (var x = 0; x < UInt16_V8.Length; ++x)
                        {
                            for (var y = 0; y < UInt16_V8[x].Length; ++y)
                            {
                                binaryWriter.Write(UInt16_V8[x][y]);
                            }
                        }
                    }
                    else if (heightHeader.flags.HasFlag(HeightHeaderFlags.AsInt8))
                    {
                        for (var x = 0; x < UInt8_V9.Length; ++x)
                        {
                            for (var y = 0; y < UInt8_V9[x].Length; ++y)
                            {
                                binaryWriter.Write(UInt8_V9[x][y]);
                            }
                        }

                        for (var x = 0; x < UInt8_V8.Length; ++x)
                        {
                            for (var y = 0; y < UInt8_V8[x].Length; ++y)
                            {
                                binaryWriter.Write(UInt8_V8[x][y]);
                            }
                        }
                    }
                    else
                    {
                        for (var x = 0; x < V9.Length; ++x)
                        {
                            for (var y = 0; y < V9[x].Length; ++y)
                            {
                                binaryWriter.Write(V9[x][y]);
                            }
                        }

                        for (var x = 0; x < V8.Length; ++x)
                        {
                            for (var y = 0; y < V8[x].Length; ++y)
                            {
                                binaryWriter.Write(V8[x][y]);
                            }
                        }
                    }
                }

                if (heightHeader.flags.HasFlag(HeightHeaderFlags.HasFlightBounds))
                {
                    for (var x = 0; x < 3; ++x)
                    {
                        for (var y = 0; y < 3; ++y)
                        {
                            binaryWriter.Write(FlightBoxMax[x][y]);
                        }
                    }

                    for (var x = 0; x < 3; ++x)
                    {
                        for (var y = 0; y < 3; ++y)
                        {
                            binaryWriter.Write(FlightBoxMin[x][y]);
                        }
                    }
                }

                // Store liquid data if need
                if (map.liquidMapOffset != 0)
                {
                    binaryWriter.WriteStruct(mapLiquidHeader);
                    if (!mapLiquidHeader.flags.HasFlag(LiquidHeaderFlags.NoType))
                    {
                        for (var x = 0; x < LiquidEntries.Length; ++x)
                        {
                            for (var y = 0; y < LiquidEntries[x].Length; ++y)
                            {
                                binaryWriter.Write(LiquidEntries[x][y]);
                            }
                        }

                        for (var x = 0; x < LiquidFlags.Length; ++x)
                        {
                            for (var y = 0; y < LiquidFlags[x].Length; ++y)
                            {
                                binaryWriter.Write((byte)LiquidFlags[x][y]);
                            }
                        }
                    }

                    if (!mapLiquidHeader.flags.HasFlag(LiquidHeaderFlags.NoHeight))
                    {
                        for (int y = 0; y < mapLiquidHeader.height; y++)
                        {
                            for (int x = 0; x < mapLiquidHeader.width; x++)
                            {
                                binaryWriter.Write(LiquidHeight[y + mapLiquidHeader.offsetY][x + mapLiquidHeader.offsetX]);
                            }
                        }
                    }
                }

                // store hole data
                if (hasHoles)
                {
                    for (var x = 0; x < Holes.Length; ++x)
                    {
                        for (var y = 0; y < Holes[x].Length; ++y)
                        {
                            for (var z = 0; z < Holes[x][y].Length; ++z)
                            {
                                binaryWriter.Write(Holes[x][y][z]);
                            }
                        }
                    }
                }
            }

            return(true);
        }
Beispiel #15
0
        private void parseMapChunkSubChunks(ref MCNK mapChunk, FileStream ms, long lastpos)
        {
            BinaryReader bin = new BinaryReader(ms);

            BlizChunkHeader tempHeader;
            long            pos = ms.Position;

            // Read bytes from the stream until we run out
            while (pos < lastpos)
            {
                // Advance to the next Chunk
                ms.Position = pos;

                // Read in Chunk Header Name
                tempHeader = new BlizChunkHeader(bin.ReadChars(4), bin.ReadUInt32());
                tempHeader.Flip();

                // Set pos to the location of the next Chunk
                pos = ms.Position + tempHeader.Size;

                if (tempHeader.Is("MCVT"))  // These are the actual height values for the 9x9+8x8 vertices.
                {
                    mapChunk.VerticesOuter = new float[9][];
                    mapChunk.VerticesInner = new float[8][];

                    for (int i = 0; i < 9; i++)
                    {
                        mapChunk.VerticesOuter[i] = new float[9];

                        for (int j = 0; j < 9; j++)
                        {
                            mapChunk.VerticesOuter[i][j] = bin.ReadSingle();
                        }

                        if (i == 8)
                        {
                            continue;
                        }

                        mapChunk.VerticesInner[i] = new float[8];

                        for (int j = 0; j < 8; j++)
                        {
                            mapChunk.VerticesInner[i][j] = bin.ReadSingle();
                        }
                    }

                    continue;
                }

                if (tempHeader.Is("MCNR"))     // Normal vectors for each vertex.
                {
                    pos = ms.Position + 0x1C0; // sizefix?
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MCLY"))  // Texture layer definitions for this map chunk.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MCRF"))  // Unknown. List of integers.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MCSH"))  // Shadow map for static shadows on the terrain.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MCAL"))  // Alpha maps for additional texture layers.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MCLQ"))  // Water levels for this map chunk.
                {
                    mapChunk.Liquid = new MCLQ();

                    // I dunno. MCLQ header size lies. If MCSE is immidiately following, there's no water.
                    tempHeader = new BlizChunkHeader(bin.ReadChars(4), 0);
                    tempHeader.Flip();

                    if (tempHeader.Is("MCSE"))
                    {
                        mapChunk.Liquid.waterLevel = float.NaN;
                    }
                    else
                    {
                        // After reading water, we stop. I do NOT like this solution, but
                        // 1) We don't know much about MCLQ chunks.
                        // 2) The size field lies, saying its always 0. (no idea why)
                        // 3) I can't kludge this with a size fix, BECAUSE THE LENGTH VARIES?! Its in the area of 0x320, or 0x31F or 0x31E.
                        // 4) So stopping after this chunk is the best we can do; this is what wowmapview does in any case.
                        pos = lastpos;
                        ms.Seek(-4, SeekOrigin.Current); // Go back! Re-read the last 4 bytes as its actually a float not char[4].
                        mapChunk.Liquid.waterLevel = bin.ReadSingle();
                    }

                    continue;
                }

                if (tempHeader.Is("MCSE"))  // Sound emitters.
                {
                    // Not needed.
                    continue;
                }

                // If we're still down here, we got a problem
                throw new Exception(String.Format("ADTFile: Woah. Got a header of Sub-{0}. Don't know how to deal with this, bailing out.", tempHeader.ToString()));
            }
        }
Beispiel #16
0
        private void parseFile()
        {
            FileStream ms = adtStream;

            if (ms == null)
            {
                throw new Exception("Stream null!");
            }
            BinaryReader bin = new BinaryReader(ms);

            BlizChunkHeader tempHeader;
            long            pos = 0;

            // Read bytes from the stream until we run out
            while (pos < ms.Length)
            {
                // Advance to the next Chunk
                ms.Position = pos;

                // Read in Chunk Header Name
                tempHeader = new BlizChunkHeader(bin.ReadChars(4), bin.ReadUInt32());
                tempHeader.Flip();

                // Set pos to the location of the next Chunk
                pos = ms.Position + tempHeader.Size;

                if (tempHeader.Is("MVER"))   // ADT File Version
                {
                    mver         = new MVER();
                    mver.version = bin.ReadUInt32();

                    continue;
                }

                if (tempHeader.Is("MHDR"))  // ADT File Header
                {
                    mhdr                   = new MHDR();
                    mhdr.pad               = bin.ReadUInt32();
                    mhdr.offsInfo          = bin.ReadUInt32();
                    mhdr.offsTex           = bin.ReadUInt32();
                    mhdr.offsModels        = bin.ReadUInt32();
                    mhdr.offsModelsIds     = bin.ReadUInt32();
                    mhdr.offsMapObejcts    = bin.ReadUInt32();
                    mhdr.offsMapObejctsIds = bin.ReadUInt32();
                    mhdr.offsDoodsDef      = bin.ReadUInt32();
                    mhdr.offsObjectsDef    = bin.ReadUInt32();
                    mhdr.pad1              = bin.ReadUInt32();
                    mhdr.pad2              = bin.ReadUInt32();
                    mhdr.pad3              = bin.ReadUInt32();
                    mhdr.pad4              = bin.ReadUInt32();
                    mhdr.pad5              = bin.ReadUInt32();
                    mhdr.pad6              = bin.ReadUInt32();
                    mhdr.pad7              = bin.ReadUInt32();

                    continue;
                }

                if (tempHeader.Is("MCIN"))  // Index for MCNK chunks.
                {
                    if (tempHeader.Size != 256 * 16)
                    {
                        throw new Exception("MCIN Chunk is short??");
                    }

                    mcin_array = new MCIN[256];

                    // Read in the 256 records
                    for (int i = 0; i < 256; i++)
                    {
                        mcin_array[i].MCNK_offset = bin.ReadUInt32();
                        mcin_array[i].MCNK_size   = bin.ReadUInt32();
                        mcin_array[i].flags       = bin.ReadUInt32();
                        mcin_array[i].asyncID     = bin.ReadUInt32();
                    }

                    continue;
                }

                if (tempHeader.Is("MTEX"))  // List of texture filenames used by the terrain in this map tile.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MMDX")) // List of filenames for M2 models that appear in this map tile.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MMID"))  // Lists the relative offsets of string beginnings in the above MMDX chunk.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MWMO"))  // List of filenames for WMOs (world map objects) that appear in this map tile.
                {
                    byte[] wmoFilesChunk = bin.ReadBytes((int)tempHeader.Size);

                    wmoFiles = new List <String>();

                    StringBuilder str = new StringBuilder();

                    // Convert szString's to a List<String>.
                    for (int i = 0; i < wmoFilesChunk.Length; i++)
                    {
                        if (wmoFilesChunk[i] == '\0')
                        {
                            if (str.Length > 1)
                            {
                                wmoFiles.Add(str.ToString());
                            }
                            str = new StringBuilder();
                        }
                        else
                        {
                            str.Append((char)wmoFilesChunk[i]);
                        }
                    }

                    continue;
                }

                if (tempHeader.Is("MWID"))  // Lists the relative offsets of string beginnings in the above MWWO chunk.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MDDF"))  // Placement information for doodads (M2 models).
                {
                    uint num = tempHeader.Size / 32;

                    doodadLocations = new MDDF[num];

                    for (int i = 0; i < num; i++)
                    {
                        doodadLocations[i].nameId   = bin.ReadUInt32();
                        doodadLocations[i].uniqueId = bin.ReadUInt32();
                        doodadLocations[i].coord    = new Coordinate(bin.ReadSingle(), bin.ReadSingle(), bin.ReadSingle());
                    }

                    continue;
                }

                if (tempHeader.Is("MODF"))  // Placement information for WMOs.
                {
                    uint num = tempHeader.Size / 64;

                    wmoLocations = new MODF[num];

                    for (int i = 0; i < num; i++)
                    {
                        wmoLocations[i].nameId      = bin.ReadUInt32();
                        wmoLocations[i].uniqueId    = bin.ReadUInt32();
                        wmoLocations[i].coord       = new Coordinate(bin.ReadSingle(), bin.ReadSingle(), bin.ReadSingle());
                        wmoLocations[i].orientation = new Vect3D(bin.ReadSingle(), bin.ReadSingle(), bin.ReadSingle());
                        wmoLocations[i].coord2      = new Coordinate(bin.ReadSingle(), bin.ReadSingle(), bin.ReadSingle());
                        wmoLocations[i].coord3      = new Coordinate(bin.ReadSingle(), bin.ReadSingle(), bin.ReadSingle());
                        wmoLocations[i].flags       = bin.ReadUInt32();
                        wmoLocations[i].doodadSet   = bin.ReadUInt16();
                        wmoLocations[i].nameSet     = bin.ReadUInt16();
                    }

                    continue;
                }

                if (tempHeader.Is("MCNK")) // || tempHeader.Is("MCVT") || tempHeader.Is("MCNR") || tempHeader.Is("MCLY") || tempHeader.Is("MCRF") || tempHeader.Is("MCSH") || tempHeader.Is("MCAL") || tempHeader.Is("MCLQ") || tempHeader.Is("MCSE"))
                {
                    // Skip these. They are read in afterwards.
                    continue;
                }

                // If we're still down here, we got a problem
                throw new Exception(String.Format("ADTFile: Woah. Got a header of {0}. Don't know how to deal with this, bailing out.", tempHeader.ToString()));
            }

            // Read in Map Chunks
            mapChunkTable = new MCNK[16][];

            for (int i = 0; i < 16; i++)
            {
                mapChunkTable[i] = new MCNK[16];

                for (int j = 0; j < 16; j++)
                {
                    int index = i * 16 + j;
                    Log.WriteLine(LogType.Terrain, "Parsing MCNK Chunk #{0} [{1}, {2}]", index, i, j);
                    mapChunkTable[i][j] = parseMapChunk(ms, mcin_array[index].MCNK_offset, mcin_array[index].MCNK_size);
                }
            }
        }
Beispiel #17
0
        public void Write(BinaryWriter writer, MCNK parentChunk, WDT.WDT wdt, int currentLayer)
        {
            if (parentChunk.MCLY.Layers[currentLayer].Flags.HasFlag(MCLYFlags.CompressedAlphaMap) &&
                (wdt.MPHD.Flags.HasFlag(MPHDFlags.HasBigAlpha) || wdt.MPHD.Flags.HasFlag(MPHDFlags.MCALSize4096)))
            {
                // Compressed
                var positionInAlphaMap = 0;
                var tempAlphaMap       = new byte[4096];

                while (positionInAlphaMap < 4096)
                {
                    var info = AlphaMap[positionInAlphaMap % 64, positionInAlphaMap / 64];
                    tempAlphaMap[positionInAlphaMap] = info;
                    positionInAlphaMap += 1;
                    var mode  = (info & 0x80) >> 7;
                    var count = info & 0x7F;

                    // Copy mode
                    if (mode == 0)
                    {
                        for (int j = 0; j < count - 1; j++)
                        {
                            tempAlphaMap[positionInAlphaMap + j] = AlphaMap[positionInAlphaMap % 64 + j, positionInAlphaMap / 64 + j];
                        }
                    }
                    else // Fill mode
                    {
                        var data = AlphaMap[positionInAlphaMap % 64, positionInAlphaMap / 64];
                        for (int j = 0; j < count; j++)
                        {
                            tempAlphaMap[positionInAlphaMap + j] = data;
                        }
                    }
                    positionInAlphaMap += count;
                }
                writer.Write(tempAlphaMap);
            }
            else if (wdt.MPHD.Flags.HasFlag(MPHDFlags.HasBigAlpha) || wdt.MPHD.Flags.HasFlag(MPHDFlags.MCALSize4096))
            {
                // Uncompressed (4096)
                for (int y = 0; y < 64; y++)
                {
                    for (int x = 0; x < 64; x++)
                    {
                        writer.Write(AlphaMap[x, y]);
                    }
                }
            }
            else
            {
                // Uncompressed (2048) - TODO build in FLAG_DO_NOT_FIX_ALPHA_MAP
                if (parentChunk.Flags.HasFlag(MCNKFlags.DoNotFixAlphaMap))
                {
                    for (int y = 0; y < 63; y++)
                    {
                        for (int x = 0; x < 63; x += 2)
                        {
                            var  byte1    = AlphaMap[x, y];
                            var  byte2    = AlphaMap[x + 1, y];
                            byte fullByte = 0;
                            fullByte = (byte)(fullByte | byte1 << 4);
                            fullByte = (byte)(fullByte | byte2);
                            writer.Write(fullByte);
                        }

                        if (y == 62)
                        {
                            var byte1 = AlphaMap[]
                        }
                    }
                }
                else
                {
                    for (int y = 0; y < 64; y++)
                    {
                        for (int x = 0; x < 64; x += 2)
                        {
                            var  byte1    = AlphaMap[x, y];
                            var  byte2    = AlphaMap[x + 1, y];
                            byte fullByte = 0;
                            fullByte = (byte)(fullByte | byte1 << 4);
                            fullByte = (byte)(fullByte | byte2);
                            writer.Write(fullByte);
                        }
                    }
                }
            }
        }
Beispiel #18
0
        private TriangleList GenerateVertexAndIndices()
        {
            var vertices = new List <VertexPositionNormalColored>();
            var indices  = new List <int>();


            for (int My = 0; My < 16; My++)
            {
                for (int Mx = 0; Mx < 16; Mx++)
                {
                    MCNK lMCNK = MCNKArray[Mx, My];

                    var HolesMap = new bool[4, 4];
                    if (lMCNK.holes > 0)
                    {
                        HolesMap = lMCNK.GetHolesMap();
                    }

                    #region indexing

                    for (int row = 0; row < 8; row++)
                    {
                        for (int col = 0; col < 8; col++)
                        {
                            if (!HolesMap[row / 2, col / 2])
                            {
                                /* The order metter*/

                                /*This 3 index add the up triangle
                                 *
                                 * 0--1--2
                                 *| /| /
                                 *|/ |/
                                 * 9  10 11
                                 */

                                indices.Add(vertices.Count + ((row + 1) * (8 + 1) + col));                           //9 ... 10
                                indices.Add(vertices.Count + (row * (8 + 1) + col));                                 //0 ... 1
                                indices.Add(vertices.Count + (row * (8 + 1) + col + 1));                             //1 ... 2

                                /*This 3 index add the low triangle
                                 *
                                 * 0  1   2
                                 *  /|  /|
                                 * / | / |
                                 * 9--10--11
                                 */

                                indices.Add(vertices.Count + ((row + 1) * (8 + 1) + col + 1));
                                indices.Add(vertices.Count + ((row + 1) * (8 + 1) + col));
                                indices.Add(vertices.Count + (row * (8 + 1) + col + 1));
                            }

                            #endregion
                        }
                    }

                    //this.Indices.AddRange(triangleListIndices);
                    const float offset_x = (533.33333f / 16) / 8;
                    const float offset_z = (533.33333f / 16) / 8;

                    var LowResMap    = lMCNK._MCVT.GetLowResMapMatrix();
                    var LowResNormal = lMCNK._MCNR.GetLowResNormalMatrix();

                    for (int r = 0; r < 9; r++)
                    {
                        for (int c = 0; c < 9; c++)
                        {
                            float x_pos = lMCNK.x - (c * offset_x);
                            float z_pos = lMCNK.z - (r * offset_z);
                            float y_pos = LowResMap[r, c] + lMCNK.y;


                            var   normal   = LowResNormal[r, c];
                            float cosAngle = Vector3.Dot(Vector3.Up, normal);
                            float angle    = MathHelper.ToDegrees((float)Math.Acos(cosAngle));

                            var position = new Vector3(x_pos, y_pos, z_pos);
                            vertices.Add(new VertexPositionNormalColored(position, angle > 50.0 ? Color.Brown : Color.Green, normal));
                        }
                    }
                }
            }
            return(new TriangleList(indices, vertices));
        }
Beispiel #19
0
        public MCALAlphaMap(BinaryReader reader, MCNK parentChunk, WDT.WDT wdt, int currentLayer)
        {
            if (parentChunk.MCLY.Layers[currentLayer].Flags.HasFlag(MCLYFlags.CompressedAlphaMap) &&
                (wdt.MPHD.Flags.HasFlag(MPHDFlags.HasBigAlpha) || wdt.MPHD.Flags.HasFlag(MPHDFlags.MCALSize4096)))
            {
                // Compressed
                var positionInAlphaMap = 0;
                var tempAlphaMap       = new byte[4096];

                while (positionInAlphaMap < 4096)
                {
                    var info  = reader.ReadByte();
                    var mode  = (info & 0x80) >> 7;
                    var count = info & 0x7F;

                    // Copy mode
                    if (mode == 0)
                    {
                        for (int j = 0; j < count; j++)
                        {
                            tempAlphaMap[positionInAlphaMap + j] = reader.ReadByte();
                        }
                    }
                    else // Fill mode
                    {
                        var data = reader.ReadByte();
                        for (int j = 0; j < count; j++)
                        {
                            tempAlphaMap[positionInAlphaMap + j] = data;
                        }
                    }
                    positionInAlphaMap += count;
                }

                for (int y = 0; y < 64; y++)
                {
                    for (int x = 0; x < 64; x++)
                    {
                        AlphaMap[x, y] = tempAlphaMap[x * 64 + y];
                    }
                }
            }
            else if (wdt.MPHD.Flags.HasFlag(MPHDFlags.HasBigAlpha) || wdt.MPHD.Flags.HasFlag(MPHDFlags.MCALSize4096))
            {
                // Uncompressed (4096)
                for (int y = 0; y < 64; y++)
                {
                    for (int x = 0; x < 64; x++)
                    {
                        AlphaMap[x, y] = reader.ReadByte();
                    }
                }
            }
            else
            {
                // Uncompressed (2048) - TODO: build in FLAG_DO_NOT_FIX_ALPHA_MAP
                for (int y = 0; y < 64; y++)
                {
                    for (int x = 0; x < 64; x += 2)
                    {
                        var  fullByte = reader.ReadByte();
                        byte lowBits  = (byte)(fullByte & 0x0F);
                        byte highBits = (byte)(fullByte >> 4);
                        AlphaMap[x, y]     = highBits;
                        AlphaMap[x + 1, y] = lowBits;
                    }
                }
            }
        }
Beispiel #20
0
		static MCNK ProcessChunk(BinaryReader fileReader, uint mcnkOffset)
		{
			var mcnk = new MCNK();

			fileReader.BaseStream.Position = mcnkOffset;

			var sig = fileReader.ReadUInt32();
			if (sig != Signatures.MCNK)
			{
				Console.WriteLine("Invalid Chunk offset found.");
			}

			var mcnkSize = fileReader.ReadUInt32();

			mcnk.Flags = fileReader.ReadInt32();
			mcnk.IndexX = fileReader.ReadInt32();
			mcnk.IndexY = fileReader.ReadInt32();
			mcnk.nLayers = fileReader.ReadUInt32(); //0xC
			mcnk.nDoodadRefs = fileReader.ReadUInt32(); //0x10
			mcnk.ofsHeight = fileReader.ReadUInt32(); //0x14
			mcnk.ofsNormal = fileReader.ReadUInt32(); //0x18
			mcnk.ofsLayer = fileReader.ReadUInt32(); //0x1C
			mcnk.ofsRefs = fileReader.ReadUInt32(); //0x20
			mcnk.ofsAlpha = fileReader.ReadUInt32(); //0x24
			mcnk.sizeAlpha = fileReader.ReadUInt32(); //0x28
			mcnk.ofsShadow = fileReader.ReadUInt32(); //0x2C
			mcnk.sizeShadow = fileReader.ReadUInt32(); //0x30
			mcnk.AreaId = fileReader.ReadUInt32(); //0x34
			mcnk.nMapObjRefs = fileReader.ReadUInt32(); //0x38

			mcnk.Holes = fileReader.ReadUInt16();
			fileReader.ReadUInt16(); // pad

			mcnk.predTex = new ushort[8];
			for (var i = 0; i < 8; i++)
			{
				mcnk.predTex[i] = fileReader.ReadUInt16();
			}

			mcnk.nEffectDoodad = new byte[8];
			for (var i = 0; i < 8; i++)
			{
				mcnk.nEffectDoodad[i] = fileReader.ReadByte();
			}
			mcnk.ofsSndEmitters = fileReader.ReadUInt32(); //0x58
			mcnk.nSndEmitters = fileReader.ReadUInt32(); //0x5C
			mcnk.ofsLiquid = fileReader.ReadUInt32(); //0x60
			mcnk.sizeLiquid = fileReader.ReadUInt32(); //0x64
			mcnk.Z = fileReader.ReadSingle();
			mcnk.X = fileReader.ReadSingle();
			mcnk.Y = fileReader.ReadSingle();
			mcnk.offsColorValues = fileReader.ReadInt32();
			mcnk.props = fileReader.ReadInt32();
			mcnk.effectId = fileReader.ReadInt32();

			return mcnk;
		}
Beispiel #21
0
        // Read in an MCNK chunk at supplied offset.
        private MCNK parseMapChunk(FileStream ms, uint offset, uint size)
        {
            BinaryReader bin = new BinaryReader(ms);
            ms.Position = offset;

            BlizChunkHeader tempHeader = new BlizChunkHeader(bin.ReadChars(4), bin.ReadUInt32());
            tempHeader.Flip();

            if (!tempHeader.Is("MCNK"))
                throw new Exception("This was supposed to be an MCNK chunk. Wtf?");

            long lastpos = ms.Position + tempHeader.Size;

            MCNK mapChunk = new MCNK();

            mapChunk.flags = bin.ReadUInt32();
            mapChunk.ix = bin.ReadUInt32();
            mapChunk.iy = bin.ReadUInt32();
            mapChunk.nLayers = bin.ReadUInt32();
            mapChunk.nDoodadRefs = bin.ReadUInt32();
            mapChunk.ofsHeight = bin.ReadUInt32();
            mapChunk.ofsNormal = bin.ReadUInt32();
            mapChunk.ofsLayer = bin.ReadUInt32();
            mapChunk.ofsRefs = bin.ReadUInt32();
            mapChunk.ofsAlpha = bin.ReadUInt32();
            mapChunk.sizeAlpha = bin.ReadUInt32();
            mapChunk.ofsShadow = bin.ReadUInt32();
            mapChunk.sizeShadow = bin.ReadUInt32();
            mapChunk.areaid = bin.ReadUInt32();
            mapChunk.nMapObjRefs = bin.ReadUInt32();
            mapChunk.holes = bin.ReadUInt32();
            mapChunk.s1 = bin.ReadUInt16();
            mapChunk.s2 = bin.ReadUInt16();
            mapChunk.d1 = bin.ReadUInt32();
            mapChunk.d2 = bin.ReadUInt32();
            mapChunk.d3 = bin.ReadUInt32();
            mapChunk.predTex = bin.ReadUInt32();
            mapChunk.nEffectDoodad = bin.ReadUInt32();
            mapChunk.ofsSndEmitters = bin.ReadUInt32();
            mapChunk.nSndEmitters = bin.ReadUInt32();
            mapChunk.ofsLiquid = bin.ReadUInt32();
            mapChunk.sizeLiquid = bin.ReadUInt32();
            mapChunk.zpos = bin.ReadSingle();
            mapChunk.xpos = bin.ReadSingle();
            mapChunk.ypos = bin.ReadSingle();
            mapChunk.textureId = bin.ReadUInt32();
            mapChunk.props = bin.ReadUInt32();
            mapChunk.effectId = bin.ReadUInt32();

            // Parse this MapChunk's SubChunks!
            parseMapChunkSubChunks(ref mapChunk, ms, lastpos);

            return mapChunk;
        }
Beispiel #22
0
        private void parseMapChunkSubChunks(ref MCNK mapChunk, FileStream ms, long lastpos)
        {
            BinaryReader bin = new BinaryReader(ms);

            BlizChunkHeader tempHeader;
            long pos = ms.Position;

            // Read bytes from the stream until we run out
            while (pos < lastpos)
            {
                // Advance to the next Chunk
                ms.Position = pos;

                // Read in Chunk Header Name
                tempHeader = new BlizChunkHeader(bin.ReadChars(4), bin.ReadUInt32());
                tempHeader.Flip();

                // Set pos to the location of the next Chunk
                pos = ms.Position + tempHeader.Size;

                if (tempHeader.Is("MCVT"))  // These are the actual height values for the 9x9+8x8 vertices.
                {
                    mapChunk.VerticesOuter = new float[9][];
                    mapChunk.VerticesInner = new float[8][];

                    for (int i = 0; i < 9; i++)
                    {
                        mapChunk.VerticesOuter[i] = new float[9];

                        for (int j = 0; j < 9; j++)
                        {
                            mapChunk.VerticesOuter[i][j] = bin.ReadSingle();
                        }

                        if (i == 8) continue;

                        mapChunk.VerticesInner[i] = new float[8];

                        for (int j = 0; j < 8; j++)
                        {
                            mapChunk.VerticesInner[i][j] = bin.ReadSingle();
                        }
                    }

                    continue;
                }

                if (tempHeader.Is("MCNR"))  // Normal vectors for each vertex.
                {
                    pos = ms.Position + 0x1C0; // sizefix?
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MCLY"))  // Texture layer definitions for this map chunk.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MCRF"))  // Unknown. List of integers.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MCSH"))  // Shadow map for static shadows on the terrain.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MCAL"))  // Alpha maps for additional texture layers.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MCLQ"))  // Water levels for this map chunk.
                {
                    mapChunk.Liquid = new MCLQ();

                    // I dunno. MCLQ header size lies. If MCSE is immidiately following, there's no water.
                    tempHeader = new BlizChunkHeader(bin.ReadChars(4), 0);
                    tempHeader.Flip();

                    if (tempHeader.Is("MCSE"))
                    {
                        mapChunk.Liquid.waterLevel = float.NaN;
                    }
                    else
                    {
                        // After reading water, we stop. I do NOT like this solution, but
                        // 1) We don't know much about MCLQ chunks.
                        // 2) The size field lies, saying its always 0. (no idea why)
                        // 3) I can't kludge this with a size fix, BECAUSE THE LENGTH VARIES?! Its in the area of 0x320, or 0x31F or 0x31E.
                        // 4) So stopping after this chunk is the best we can do; this is what wowmapview does in any case.
                        pos = lastpos;
                        ms.Seek(-4, SeekOrigin.Current); // Go back! Re-read the last 4 bytes as its actually a float not char[4].
                        mapChunk.Liquid.waterLevel = bin.ReadSingle();
                    }

                    continue;
                }

                if (tempHeader.Is("MCSE"))  // Sound emitters.
                {
                    // Not needed.
                    continue;
                }

                // If we're still down here, we got a problem
                throw new Exception(String.Format("ADTFile: Woah. Got a header of Sub-{0}. Don't know how to deal with this, bailing out.", tempHeader.ToString()));
            }
        }
Beispiel #23
0
        private void parseFile()
        {
            FileStream ms = adtStream;
            if (ms == null)
            {
                throw new Exception("Stream null!");
            }
            BinaryReader bin = new BinaryReader(ms);

            BlizChunkHeader tempHeader;
            long pos = 0;

            // Read bytes from the stream until we run out
            while (pos < ms.Length)
            {
                // Advance to the next Chunk
                ms.Position = pos;

                // Read in Chunk Header Name
                tempHeader = new BlizChunkHeader(bin.ReadChars(4), bin.ReadUInt32());
                tempHeader.Flip();

                // Set pos to the location of the next Chunk
                pos = ms.Position + tempHeader.Size;

                if (tempHeader.Is("MVER"))   // ADT File Version
                {
                    mver = new MVER();
                    mver.version = bin.ReadUInt32();

                    continue;
                }

                if (tempHeader.Is("MHDR"))  // ADT File Header
                {
                    mhdr = new MHDR();
                    mhdr.pad = bin.ReadUInt32();
                    mhdr.offsInfo = bin.ReadUInt32();
                    mhdr.offsTex = bin.ReadUInt32();
                    mhdr.offsModels = bin.ReadUInt32();
                    mhdr.offsModelsIds = bin.ReadUInt32();
                    mhdr.offsMapObejcts = bin.ReadUInt32();
                    mhdr.offsMapObejctsIds = bin.ReadUInt32();
                    mhdr.offsDoodsDef = bin.ReadUInt32();
                    mhdr.offsObjectsDef = bin.ReadUInt32();
                    mhdr.pad1 = bin.ReadUInt32();
                    mhdr.pad2 = bin.ReadUInt32();
                    mhdr.pad3 = bin.ReadUInt32();
                    mhdr.pad4 = bin.ReadUInt32();
                    mhdr.pad5 = bin.ReadUInt32();
                    mhdr.pad6 = bin.ReadUInt32();
                    mhdr.pad7 = bin.ReadUInt32();

                    continue;
                }

                if (tempHeader.Is("MCIN"))  // Index for MCNK chunks.
                {
                    if (tempHeader.Size != 256 * 16)
                        throw new Exception("MCIN Chunk is short??");

                    mcin_array = new MCIN[256];

                    // Read in the 256 records
                    for (int i = 0; i < 256; i++)
                    {
                        mcin_array[i].MCNK_offset = bin.ReadUInt32();
                        mcin_array[i].MCNK_size = bin.ReadUInt32();
                        mcin_array[i].flags = bin.ReadUInt32();
                        mcin_array[i].asyncID = bin.ReadUInt32();
                    }

                    continue;
                }

                if (tempHeader.Is("MTEX"))  // List of texture filenames used by the terrain in this map tile.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MMDX")) // List of filenames for M2 models that appear in this map tile.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MMID"))  // Lists the relative offsets of string beginnings in the above MMDX chunk.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MWMO"))  // List of filenames for WMOs (world map objects) that appear in this map tile.
                {
                    byte[] wmoFilesChunk = bin.ReadBytes((int)tempHeader.Size);

                    wmoFiles = new List<String>();

                    StringBuilder str = new StringBuilder();

                    // Convert szString's to a List<String>.
                    for (int i = 0; i < wmoFilesChunk.Length; i++)
                    {
                        if (wmoFilesChunk[i] == '\0')
                        {
                            if (str.Length > 1)
                                wmoFiles.Add(str.ToString());
                            str = new StringBuilder();
                        }
                        else
                            str.Append((char)wmoFilesChunk[i]);
                    }

                    continue;
                }

                if (tempHeader.Is("MWID"))  // Lists the relative offsets of string beginnings in the above MWWO chunk.
                {
                    // Not needed.
                    continue;
                }

                if (tempHeader.Is("MDDF"))  // Placement information for doodads (M2 models).
                {
                    uint num = tempHeader.Size / 32;

                    doodadLocations = new MDDF[num];

                    for (int i = 0; i < num; i++)
                    {
                        doodadLocations[i].nameId = bin.ReadUInt32();
                        doodadLocations[i].uniqueId = bin.ReadUInt32();
                        doodadLocations[i].coord = new Coordinate(bin.ReadSingle(), bin.ReadSingle(), bin.ReadSingle());
                    }

                    continue;
                }

                if (tempHeader.Is("MODF"))  // Placement information for WMOs.
                {
                    uint num = tempHeader.Size / 64;

                    wmoLocations = new MODF[num];

                    for (int i = 0; i < num; i++)
                    {
                        wmoLocations[i].nameId = bin.ReadUInt32();
                        wmoLocations[i].uniqueId = bin.ReadUInt32();
                        wmoLocations[i].coord = new Coordinate(bin.ReadSingle(), bin.ReadSingle(), bin.ReadSingle());
                        wmoLocations[i].orientation = new Vect3D(bin.ReadSingle(), bin.ReadSingle(), bin.ReadSingle());
                        wmoLocations[i].coord2 = new Coordinate(bin.ReadSingle(), bin.ReadSingle(), bin.ReadSingle());
                        wmoLocations[i].coord3 = new Coordinate(bin.ReadSingle(), bin.ReadSingle(), bin.ReadSingle());
                        wmoLocations[i].flags = bin.ReadUInt32();
                        wmoLocations[i].doodadSet = bin.ReadUInt16();
                        wmoLocations[i].nameSet = bin.ReadUInt16();
                    }

                    continue;
                }

                if (tempHeader.Is("MCNK")) // || tempHeader.Is("MCVT") || tempHeader.Is("MCNR") || tempHeader.Is("MCLY") || tempHeader.Is("MCRF") || tempHeader.Is("MCSH") || tempHeader.Is("MCAL") || tempHeader.Is("MCLQ") || tempHeader.Is("MCSE"))
                {
                    // Skip these. They are read in afterwards.
                    continue;
                }

                // If we're still down here, we got a problem
                throw new Exception(String.Format("ADTFile: Woah. Got a header of {0}. Don't know how to deal with this, bailing out.", tempHeader.ToString()));
            }

            // Read in Map Chunks
            mapChunkTable = new MCNK[16][];

            for (int i = 0; i < 16; i++)
            {
                mapChunkTable[i] = new MCNK[16];

                for (int j = 0; j < 16; j++)
                {
                    int index = i * 16 + j;
                    Log.WriteLine(LogType.Terrain,  "Parsing MCNK Chunk #{0} [{1}, {2}]", index, i, j);
                    mapChunkTable[i][j] = parseMapChunk(ms, mcin_array[index].MCNK_offset, mcin_array[index].MCNK_size);
                }
            }
        }