Exemple #1
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);
        }
Exemple #2
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);
                }
            }
        }
Exemple #3
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()));
            }
        }