Ejemplo n.º 1
0
        private static List <Chunk> ParseChunks(string filePath, ChunkInformation[] chunkInfo)
        {
            int offsetIndex, currentIndex;

            byte[] readBlock, compressedBlock, decompressedBlock;

            List <Chunk> chunkList = new List <Chunk>();
            //VoxelTerrain terrain = new VoxelTerrain();

            FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);

            for (int i = 0; i < chunkInfo.Length; i++)
            {
                //We don't care if the chunk doesn't exist, as is indicated by a 0 for offset and length
                if (chunkInfo[i].Offset == 0 && chunkInfo[i].Size == 0)
                {
                    continue;
                }

                //Calculating offset, which is set in 4096 byte sections
                offsetIndex  = chunkInfo[i].Offset * 4096;
                currentIndex = 0;

                // We know the size of our chunk data, which is also in 4096 byte sections
                readBlock = new byte[chunkInfo[i].Size * 4096];

                //Now we can populate our block
                fs.Seek(offsetIndex, SeekOrigin.Begin);
                fs.Read(readBlock, 0, chunkInfo[i].Size * 4096);

                //Now that we have our chunk data read in, we can parse it

                //First is the length in bytes of the data
                chunkInfo[i].ByteLength = CorrectEndian(BitConverter.ToInt32(readBlock, currentIndex));

                //That was 4 bytes of data, so we can push our index in further
                currentIndex += 4;

                //We should probably set up the size of our compressed array as well
                compressedBlock = new byte[chunkInfo[i].ByteLength - 1];

                //The next byte should be our compression type
                chunkInfo[i].Compression = (CompressionType)readBlock[currentIndex];

                //Only 1 byte forward this time
                currentIndex++;

                if (chunkInfo[i].Compression == CompressionType.GZip)
                {
                    //Now we can just grab our compressed chunk data
                    Array.Copy(readBlock, currentIndex, compressedBlock, 0, chunkInfo[i].ByteLength - 1);

                    //and of course decompress it
                    decompressedBlock = DecompressGZip(compressedBlock);
                }
                else
                {
                    //Here we're snagging the compressed chunk data
                    //Since we're decompressing with Deflate, rather than Zlib, we need to cut off the
                    //header tags. To do this we remove the first 2 (index + 2) and last 4 bytes (length - 4)
                    Array.Copy(readBlock, currentIndex + 2, compressedBlock, 0, chunkInfo[i].ByteLength - 1 - 4);

                    //Now we can finally decompress
                    decompressedBlock = DecompressZLib(compressedBlock);
                }

                //now the decompressed data and the chunk Info are ready to port out to an NBT parser
                if (chunkInfo[i].Offset != 0 && chunkInfo[i].Size != 0)
                {
                    NamedBinaryTag topLevel = new NamedBinaryTag();

                    GetTagList(decompressedBlock, 0, topLevel);

                    if (fileType == FileType.FILE_MCR)
                    {
                        NamedBinaryTag xPos   = FindTag("xPos", topLevel);
                        NamedBinaryTag zPos   = FindTag("zPos", topLevel);
                        NamedBinaryTag Blocks = FindTag("Blocks", topLevel);

                        if (xPos == null || zPos == null || Blocks == null)
                        {
                            throw new NullReferenceException("One or more tags not found");
                        }
                        else
                        {
                            chunkList.Add(new Chunk(new Vector2((float)xPos.GetInt(), (float)zPos.GetInt()), Blocks));
                        }
                    }
                    else
                    {
                        NamedBinaryTag xPos = FindTag("xPos", topLevel);
                        NamedBinaryTag zPos = FindTag("zPos", topLevel);
                        NamedBinaryTag Blocks;
                        NamedBinaryTag sectionsTag = FindTag("Sections", topLevel); //this finds a tag, but the value is always 0 even though nbt viewer shows 0,1,2,etc.

                        if (xPos == null || zPos == null || sectionsTag == null)
                        {
                            throw new NullReferenceException("One or more tags not found");
                        }
                        else
                        {
                            List <NamedBinaryTag> sections = sectionsTag.GetList();
                            byte[] sectionBlockArray       = new byte[16 * 16 * 16];
                            byte[, ,] chunkBlockArray = new byte[16, 256, 16]; //start by populating with [x,y,z] since its easier to understand
                            int yOffset;

                            foreach (NamedBinaryTag section in sections)
                            {
                                yOffset           = FindTag("Y", section).GetByte() * 16;
                                sectionBlockArray = FindTag("Blocks", section).GetByteArray();

                                for (int y = 0; y < 16; y++)
                                {
                                    for (int z = 0; z < 16; z++)
                                    {
                                        for (int x = 0; x < 16; x++)
                                        {
                                            chunkBlockArray[x, y + yOffset, z] = sectionBlockArray[(y * 16 + z) * 16 + x];
                                        }
                                    }
                                }
                            }

                            //chunkBlockArray contains all blocks from its sections in [x,y,z] coordinates/locations
                            //now convert to a flattened array ordered XZY so that it matches the mcr style that this importer is set up for

                            /*
                             * byte[] flattenedChunkBlockArray = new byte[16 * 16 * 256];
                             *
                             * for (int y = 0; y < 256; y++)
                             *  for (int z = 0; z < 16; z++)
                             *      for (int x = 0; x < 16; x++)
                             *          flattenedChunkBlockArray[(x * 16 + z) * 16 + y] = chunkBlockArray[x, y, z];
                             *
                             * //horribly inefficient conversion complete, now load it like an mcr file.
                             */

                            //cheat and just send 3d array, process differently in generateBlocks
                            Blocks = new NamedBinaryTag(TagType.TAG_Byte_Array, chunkBlockArray);
                            chunkList.Add(new Chunk(new Vector2((float)xPos.GetInt(), (float)zPos.GetInt()), Blocks));
                        }
                    }
                }
            }

            fs.Close();
            UpdateStatus("Done!");

            return(chunkList);
        }