Ejemplo n.º 1
0
        //WARNING: Imminent Recursion
        /// <summary>
        /// Prints out a list of all tags in the file, those without a name
        /// will have the name "None"
        /// </summary>
        /// <param name="nbtChunk">The nbt formatted binary file</param>
        /// <param name="currentIndex">the current position</param>
        /// <param name="parentStruct">Non-null only when an immediate child of a list or compound,
        /// allows a compilation of sub tags to be made in a structure similar to a tree or
        /// directory</param>
        /// <param name="parsingList">Indicates whether we currently parsing specifically a list or not;
        /// necessary to avoid checking names that don't exist</param>
        /// <returns>the position ended upon</returns>
        private static int GetTagList(byte[] nbtChunk, int currentIndex, NamedBinaryTag parentStruct = null, bool parsingList = false, TagType listIDTag = TagType.TAG_End)
        {
            //Our new tag, but we'll need its tag type first
            NamedBinaryTag newNBT;

            //Let's read in the tag where we're at
            TagType currentTag;

            if (!parsingList)
            {
                //Reading the current tag
                currentTag = (TagType)nbtChunk[currentIndex];

                //And of course we'll increment our currentIndex
                //We don't want to do this if we're in a list
                //because we're not actually reading the data
                currentIndex++;
            }
            else
            {
                currentTag = listIDTag;
            }

            //Now we can initialize our new tag
            newNBT = new NamedBinaryTag(currentTag);

            /**************************/
            /*  Searching For a Name  */
            /**************************/

            //Lets first check for a name, since most tags have one
            //We'll need to make sure its not an End or that we're in a List first
            if (currentTag != TagType.TAG_End && !parsingList)
            {
                //Then we need to find the name length
                short nameLength = CorrectEndian(BitConverter.ToInt16(nbtChunk, currentIndex));
                currentIndex += 2; //We read 2 bytes, so lets take care of it before we forget

                //Not outta the woods yet, gotta see if the name is actually there
                if (nameLength > 0)
                {
                    //Alright, so we've got a name, now we can decode it and get outta dere
                    newNBT.Name = Encoding.UTF8.GetString(nbtChunk, currentIndex, nameLength);

                    //And can't forget to keep on crawling
                    currentIndex += nameLength;
                }
            }

            /**************************/
            /*       Parsing Tag      */
            /**************************/

            //Next we need to figure out what to do
            //So let's have a look at that tag
            switch (currentTag)
            {
            // ID Type = Payload

            // 0 TAG_End = None [No name]
            case TagType.TAG_End:

                //Not too much to worry about here, just need
                // to move on back up the recursive chain
                currentIndex++;

                break;

            // 1 TAG_Byte = 1 byte signed
            case TagType.TAG_Byte:

                //Pretty straightforward, just a byte
                newNBT.Payload = nbtChunk[currentIndex];

                //And crawling along
                currentIndex++;

                break;

            // 2 TAG_Short = 2 bytes, signed, big endian
            case TagType.TAG_Short:

                //Similar as before
                newNBT.Payload = CorrectEndian(BitConverter.ToInt16(nbtChunk, currentIndex));

                //Still moving along
                currentIndex += 2;

                break;

            // 3 TAG_Int = 4 bytes, signed, big endian
            case TagType.TAG_Int:

                //Same old drill
                newNBT.Payload = CorrectEndian(BitConverter.ToInt32(nbtChunk, currentIndex));

                //Crawling along
                currentIndex += 4;

                break;

            // 4 TAG_Long = 8 bytes, signed, big endian
            case TagType.TAG_Long:

                //Getting a little bigger
                newNBT.Payload = CorrectEndian(BitConverter.ToInt64(nbtChunk, currentIndex));

                //8 more bytes down the road
                currentIndex += 8;

                break;

            // 5 TAG_Float = 4 bytes, signed, big endian
            case TagType.TAG_Float:

                //TODO: Check the endianness of this
                //Floats now, a bit different though, had to make a separate array, thanks
                //to this system being little-endian
                newNBT.Payload = BitConverter.ToSingle(new byte[4]
                {
                    nbtChunk[currentIndex],
                    nbtChunk[currentIndex + 1],
                    nbtChunk[currentIndex + 2],
                    nbtChunk[currentIndex + 3]
                }, 0);
                //Still counting here though
                currentIndex += 4;

                break;

            // 6 TAG_Double = 8 bytes, signed, big endian
            case TagType.TAG_Double:

                //We will have to do things the same here as for TAG_Float
                newNBT.Payload = BitConverter.ToDouble(new byte[8]
                {
                    nbtChunk[currentIndex],
                    nbtChunk[currentIndex + 1],
                    nbtChunk[currentIndex + 2],
                    nbtChunk[currentIndex + 3],
                    nbtChunk[currentIndex + 4],
                    nbtChunk[currentIndex + 5],
                    nbtChunk[currentIndex + 6],
                    nbtChunk[currentIndex + 7]
                }, 0);

                //Can't forget this wonderful counting
                currentIndex += 8;
                break;

            // 7 TAG_Byte_Array = [Int] size for size # of [Byte] payloads
            case TagType.TAG_Byte_Array:
            {
                //Alright, switching things up a bit (every. pun. intended.)

                //First we need the size of the array, it'll be in the next 4 bytes
                int size = CorrectEndian(BitConverter.ToInt32(nbtChunk, currentIndex));

                //Tick
                currentIndex += 4;

                //Lets first make sure that our Payload can contain the bytes
                newNBT.Payload = new byte[size];

                //Now we can apply it and get all of that glorious information
                Array.Copy(nbtChunk, currentIndex, (byte[])newNBT.Payload, 0, size);

                //And finally we can increment our count
                currentIndex += size;

                break;
            }

            // 8 TAG_String = [Short] size for size # of [UTF-8] characters
            case TagType.TAG_String:
            {
                //So lets start with the size
                int size = CorrectEndian(BitConverter.ToInt16(nbtChunk, currentIndex));

                //Increment
                currentIndex += 2;

                //Then we can populate our payload
                newNBT.Payload = Encoding.UTF8.GetString(nbtChunk, currentIndex, size);

                //And increment yet again
                currentIndex += size;

                break;
            }

            // 9 TAG_List = [Byte] for tagID, [Int] for size, size # of payloads of type tagID. [contains unnamed tags]
            case TagType.TAG_List:
            {
                //First we need to know the kind of data we'll be looking at
                TagType tagID = (TagType)nbtChunk[currentIndex];

                //Then we'll do some bookeeping
                currentIndex++;

                //Next we need our size
                int size = CorrectEndian(BitConverter.ToInt32(nbtChunk, currentIndex));

                //And Increment once again
                currentIndex += 4;

                //It's probably a good idea here to initialize our payload
                newNBT.Payload = new List <NamedBinaryTag>();

                //Finally we need to actually parse the remaining tags
                //And so we come across our first tree-like structure
                for (int i = 0; i < size; i++)
                {
                    currentIndex = GetTagList(nbtChunk, currentIndex, newNBT, true, tagID);
                }

                //That should take care of things and auto-increment our index due
                //to the magic that is recursion

                break;
            }

            // 10 TAG_Compound = Any number of fully formed named binary tags, terminates with a TAG_End
            case TagType.TAG_Compound:
            {
                //First we'll make the variable we'll need for our loop
                bool foundEnd = false;

                //Since the Coumpounds has an indeterminant payload size
                //we run the risk of hitting an infinite loop so we'll use a
                //sanity check variable
                int infiniteGuard = 0;

                //Next we'll want to be able to peek at the tag that we're on
                //after each iteration, so we need keep track of it
                TagType tagID;

                //It's probably a good idea here to initialize our payload
                newNBT.Payload = new List <NamedBinaryTag>();

                //Finally we're ready for our loop, nothing complicated, we just need to be careful
                while (!foundEnd)
                {
                    //First we peek at our current position
                    tagID = (TagType)nbtChunk[currentIndex];

                    //And then do some more sanity checks
                    if (tagID < Enum.GetValues(typeof(TagType)).Cast <TagType>().Min() ||
                        tagID > Enum.GetValues(typeof(TagType)).Cast <TagType>().Max())
                    {
                        throw new IndexOutOfRangeException("Non-Existent tag detected");
                    }

                    if ((TagType)tagID == TagType.TAG_End)
                    {
                        foundEnd = true;
                        //Since we don't actually parse this tag, we need to increment past it
                        currentIndex++;
                        break;
                    }

                    //Then we can actually start diving into the recursion
                    currentIndex = GetTagList(nbtChunk, currentIndex, newNBT);

                    //TODO:Change the Status route, throw an error
                    //Here we need to check our guard (and increment it)
                    if (infiniteGuard++ > int.MaxValue - 4)
                    {
                        UpdateStatus("Woah! Infinite Loop Dected, pulling out"); break;
                    }
                }

                break;
            }

            // 11 TAG_Int_Array = [Int] size for size # of [Int] payloads
            case TagType.TAG_Int_Array:
            {
                //And back to something simple with a size:
                int size = CorrectEndian(BitConverter.ToInt32(nbtChunk, currentIndex));

                //The Incrementing
                currentIndex += 4;

                //The making sure the payload can hold it
                newNBT.Payload = new int[size];

                //The temp array that we'll be populating...oh wait that's new
                int[] tempArray = new int[size];

                //The Populating
                for (int i = 0; i < size; i++)
                {
                    //With the Converting
                    tempArray[i] = CorrectEndian(BitConverter.ToInt32(nbtChunk, currentIndex));

                    //And more Incrementing
                    currentIndex += 4;
                }

                //The Copying
                tempArray.CopyTo((Array)newNBT.Payload, 0);


                break;
            }

            default:
                throw new IndexOutOfRangeException("A non-existent tag was found");
            }

            //Now we need to handle the actual payload of the tree tags
            if (parentStruct != null)
            {
                //First we need a temp list
                List <NamedBinaryTag> tempList = (List <NamedBinaryTag>)parentStruct.Payload;
                tempList.Add(newNBT);
            }

            //Now that we're done here, we can let everyone else know where we stopped
            return(currentIndex);
        }
Ejemplo n.º 2
0
 public Chunk(Vector2 pos, NamedBinaryTag nbt)
 {
     Position  = pos;
     ByteArray = nbt;
 }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
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;
        }
Ejemplo n.º 5
0
        private static NamedBinaryTag FindTag(string tagName, NamedBinaryTag currentTag)
        {
            switch (currentTag.Type)
            {
            // ID Type = Payload

            // 0 TAG_End = None [No name]
            case TagType.TAG_End:
                return(null);

            // 1 TAG_Byte = 1 byte signed
            case TagType.TAG_Byte:
            // 2 TAG_Short = 2 bytes, signed, big endian
            case TagType.TAG_Short:
            // 3 TAG_Int = 4 bytes, signed, big endian
            case TagType.TAG_Int:
            // 4 TAG_Long = 8 bytes, signed, big endian
            case TagType.TAG_Long:
            // 5 TAG_Float = 4 bytes, signed, big endian
            case TagType.TAG_Float:
            // 6 TAG_Double = 8 bytes, signed, big endian
            case TagType.TAG_Double:
            // 7 TAG_Byte_Array = [Int] size for size # of [Byte] payloads
            case TagType.TAG_Byte_Array:
            // 8 TAG_String = [Short] size for size # of [UTF-8] characters
            case TagType.TAG_String:
            // 11 TAG_Int_Array = [Int] size for size # of [Int] payloads
            case TagType.TAG_Int_Array:
                if (currentTag.Name == tagName)
                {
                    return(currentTag);
                }
                else
                {
                    return(null);
                }


            // 9 TAG_List = [Byte] for tagID, [Int] for size, size # of payloads of type tagID. [contains unnamed tags]
            case TagType.TAG_List:
            // 10 TAG_Compound = Any number of fully formed named binary tags, terminates with a TAG_End
            case TagType.TAG_Compound:
            {
                if (currentTag.Name == tagName)
                {
                    return(currentTag);
                }

                List <NamedBinaryTag> children = (List <NamedBinaryTag>)currentTag.Payload;

                NamedBinaryTag result = null;

                foreach (NamedBinaryTag nbt in children)
                {
                    result = FindTag(tagName, nbt);
                    if (result != null)
                    {
                        return(result);
                    }
                }

                return(null);
            }

            default:
                throw new IndexOutOfRangeException("A non-existent tag was found");
            }
        }
Ejemplo n.º 6
0
 public Chunk(Vector2 pos, NamedBinaryTag nbt)
 {
     Position = pos;
     ByteArray = nbt;
 }
Ejemplo n.º 7
0
        //WARNING: Imminent Recursion
        /// <summary>
        /// Prints out a list of all tags in the file, those without a name
        /// will have the name "None"
        /// </summary>
        /// <param name="nbtChunk">The nbt formatted binary file</param>
        /// <param name="currentIndex">the current position</param>
        /// <param name="parentStruct">Non-null only when an immediate child of a list or compound, 
        /// allows a compilation of sub tags to be made in a structure similar to a tree or 
        /// directory</param>
        /// <param name="parsingList">Indicates whether we currently parsing specifically a list or not;
        /// necessary to avoid checking names that don't exist</param>
        /// <returns>the position ended upon</returns>
        private static int GetTagList(byte[] nbtChunk, int currentIndex, NamedBinaryTag parentStruct = null, bool parsingList = false, TagType listIDTag = TagType.TAG_End)
        {
            //Our new tag, but we'll need its tag type first
            NamedBinaryTag newNBT;

            //Let's read in the tag where we're at
            TagType currentTag;

            if (!parsingList)
            {
                //Reading the current tag
                currentTag = (TagType)nbtChunk[currentIndex];

                //And of course we'll increment our currentIndex
                //We don't want to do this if we're in a list
                //because we're not actually reading the data
                currentIndex++;
            }
            else
                currentTag = listIDTag;

            //Now we can initialize our new tag
            newNBT = new NamedBinaryTag(currentTag);

            /**************************/
            /*  Searching For a Name  */
            /**************************/

            //Lets first check for a name, since most tags have one
            //We'll need to make sure its not an End or that we're in a List first
            if (currentTag != TagType.TAG_End && !parsingList)
            {
                //Then we need to find the name length
                short nameLength = CorrectEndian(BitConverter.ToInt16(nbtChunk, currentIndex));
                currentIndex += 2; //We read 2 bytes, so lets take care of it before we forget

                //Not outta the woods yet, gotta see if the name is actually there
                if (nameLength > 0)
                {
                    //Alright, so we've got a name, now we can decode it and get outta dere
                    newNBT.Name = Encoding.UTF8.GetString(nbtChunk, currentIndex, nameLength);

                    //And can't forget to keep on crawling
                    currentIndex += nameLength;
                }
            }

            /**************************/
            /*       Parsing Tag      */
            /**************************/

            //Next we need to figure out what to do
            //So let's have a look at that tag
            switch (currentTag)
            {
                // ID Type = Payload

                // 0 TAG_End = None [No name]
                case TagType.TAG_End:

                    //Not too much to worry about here, just need
                    // to move on back up the recursive chain
                    currentIndex++;

                    break;

                // 1 TAG_Byte = 1 byte signed
                case TagType.TAG_Byte:

                    //Pretty straightforward, just a byte
                    newNBT.Payload = nbtChunk[currentIndex];

                    //And crawling along
                    currentIndex++;

                    break;

                // 2 TAG_Short = 2 bytes, signed, big endian
                case TagType.TAG_Short:

                    //Similar as before
                    newNBT.Payload = CorrectEndian(BitConverter.ToInt16(nbtChunk, currentIndex));

                    //Still moving along
                    currentIndex += 2;

                    break;

                // 3 TAG_Int = 4 bytes, signed, big endian
                case TagType.TAG_Int:

                    //Same old drill
                    newNBT.Payload = CorrectEndian(BitConverter.ToInt32(nbtChunk, currentIndex));

                    //Crawling along
                    currentIndex += 4;

                    break;

                // 4 TAG_Long = 8 bytes, signed, big endian
                case TagType.TAG_Long:

                    //Getting a little bigger
                    newNBT.Payload = CorrectEndian(BitConverter.ToInt64(nbtChunk, currentIndex));

                    //8 more bytes down the road
                    currentIndex += 8;

                    break;

                // 5 TAG_Float = 4 bytes, signed, big endian
                case TagType.TAG_Float:

                    //TODO: Check the endianness of this
                    //Floats now, a bit different though, had to make a separate array, thanks
                    //to this system being little-endian
                    newNBT.Payload = BitConverter.ToSingle(new byte[4]
                                                                    {
                                                                        nbtChunk[currentIndex],
                                                                        nbtChunk[currentIndex + 1],
                                                                        nbtChunk[currentIndex + 2],
                                                                        nbtChunk[currentIndex + 3]
                                                                    }, 0);
                    //Still counting here though
                    currentIndex += 4;

                    break;

                // 6 TAG_Double = 8 bytes, signed, big endian
                case TagType.TAG_Double:

                    //We will have to do things the same here as for TAG_Float
                    newNBT.Payload = BitConverter.ToDouble(new byte[8]
                                                                    {
                                                                        nbtChunk[currentIndex],
                                                                        nbtChunk[currentIndex + 1],
                                                                        nbtChunk[currentIndex + 2],
                                                                        nbtChunk[currentIndex + 3],
                                                                        nbtChunk[currentIndex + 4],
                                                                        nbtChunk[currentIndex + 5],
                                                                        nbtChunk[currentIndex + 6],
                                                                        nbtChunk[currentIndex + 7]
                                                                    }, 0);

                    //Can't forget this wonderful counting
                    currentIndex += 8;
                    break;

                // 7 TAG_Byte_Array = [Int] size for size # of [Byte] payloads
                case TagType.TAG_Byte_Array:
                    {
                        //Alright, switching things up a bit (every. pun. intended.)

                        //First we need the size of the array, it'll be in the next 4 bytes
                        int size = CorrectEndian(BitConverter.ToInt32(nbtChunk, currentIndex));

                        //Tick
                        currentIndex += 4;

                        //Lets first make sure that our Payload can contain the bytes
                        newNBT.Payload = new byte[size];

                        //Now we can apply it and get all of that glorious information
                        Array.Copy(nbtChunk, currentIndex, (byte[])newNBT.Payload, 0, size);

                        //And finally we can increment our count
                        currentIndex += size;

                        break;
                    }

                // 8 TAG_String = [Short] size for size # of [UTF-8] characters
                case TagType.TAG_String:
                    {
                        //So lets start with the size
                        int size = CorrectEndian(BitConverter.ToInt16(nbtChunk, currentIndex));

                        //Increment
                        currentIndex += 2;

                        //Then we can populate our payload
                        newNBT.Payload = Encoding.UTF8.GetString(nbtChunk, currentIndex, size);

                        //And increment yet again
                        currentIndex += size;

                        break;
                    }

                // 9 TAG_List = [Byte] for tagID, [Int] for size, size # of payloads of type tagID. [contains unnamed tags]
                case TagType.TAG_List:
                    {
                        //First we need to know the kind of data we'll be looking at
                        TagType tagID = (TagType)nbtChunk[currentIndex];

                        //Then we'll do some bookeeping
                        currentIndex++;

                        //Next we need our size
                        int size = CorrectEndian(BitConverter.ToInt32(nbtChunk, currentIndex));

                        //And Increment once again
                        currentIndex += 4;

                        //It's probably a good idea here to initialize our payload
                        newNBT.Payload = new List<NamedBinaryTag>();

                        //Finally we need to actually parse the remaining tags
                        //And so we come across our first tree-like structure
                        for (int i = 0; i < size; i++)
                        {
                            currentIndex = GetTagList(nbtChunk, currentIndex, newNBT, true, tagID);
                        }

                        //That should take care of things and auto-increment our index due
                        //to the magic that is recursion

                        break;
                    }

                // 10 TAG_Compound = Any number of fully formed named binary tags, terminates with a TAG_End
                case TagType.TAG_Compound:
                    {
                        //First we'll make the variable we'll need for our loop
                        bool foundEnd = false;

                        //Since the Coumpounds has an indeterminant payload size
                        //we run the risk of hitting an infinite loop so we'll use a
                        //sanity check variable
                        int infiniteGuard = 0;

                        //Next we'll want to be able to peek at the tag that we're on
                        //after each iteration, so we need keep track of it
                        TagType tagID;

                        //It's probably a good idea here to initialize our payload
                        newNBT.Payload = new List<NamedBinaryTag>();

                        //Finally we're ready for our loop, nothing complicated, we just need to be careful
                        while (!foundEnd)
                        {
                            //First we peek at our current position
                            tagID = (TagType)nbtChunk[currentIndex];

                            //And then do some more sanity checks
                            if (tagID < Enum.GetValues(typeof(TagType)).Cast<TagType>().Min() ||
                                tagID > Enum.GetValues(typeof(TagType)).Cast<TagType>().Max()) throw new IndexOutOfRangeException("Non-Existent tag detected");

                            if ((TagType)tagID == TagType.TAG_End)
                            {
                                foundEnd = true;
                                //Since we don't actually parse this tag, we need to increment past it
                                currentIndex++;
                                break;
                            }

                            //Then we can actually start diving into the recursion
                            currentIndex = GetTagList(nbtChunk, currentIndex, newNBT);

                            //TODO:Change the Status route, throw an error
                            //Here we need to check our guard (and increment it)
                            if (infiniteGuard++ > int.MaxValue - 4) { UpdateStatus("Woah! Infinite Loop Dected, pulling out"); break; }
                        }

                        break;
                    }

                // 11 TAG_Int_Array = [Int] size for size # of [Int] payloads
                case TagType.TAG_Int_Array:
                    {
                        //And back to something simple with a size:
                        int size = CorrectEndian(BitConverter.ToInt32(nbtChunk, currentIndex));

                        //The Incrementing
                        currentIndex += 4;

                        //The making sure the payload can hold it
                        newNBT.Payload = new int[size];

                        //The temp array that we'll be populating...oh wait that's new
                        int[] tempArray = new int[size];

                        //The Populating
                        for (int i = 0; i < size; i++)
                        {
                            //With the Converting
                            tempArray[i] = CorrectEndian(BitConverter.ToInt32(nbtChunk, currentIndex));

                            //And more Incrementing
                            currentIndex += 4;
                        }

                        //The Copying
                        tempArray.CopyTo((Array)newNBT.Payload, 0);

                        break;
                    }

                default:
                    throw new IndexOutOfRangeException("A non-existent tag was found");
            }

            //Now we need to handle the actual payload of the tree tags
            if (parentStruct != null)
            {
                //First we need a temp list
                List<NamedBinaryTag> tempList = (List<NamedBinaryTag>)parentStruct.Payload;
                tempList.Add(newNBT);
            }

            //Now that we're done here, we can let everyone else know where we stopped
            return currentIndex;
        }
Ejemplo n.º 8
0
        private static NamedBinaryTag FindTag(string tagName, NamedBinaryTag currentTag)
        {
            switch (currentTag.Type)
            {
                // ID Type = Payload

                // 0 TAG_End = None [No name]
                case TagType.TAG_End:
                    return null;

                // 1 TAG_Byte = 1 byte signed
                case TagType.TAG_Byte:
                // 2 TAG_Short = 2 bytes, signed, big endian
                case TagType.TAG_Short:
                // 3 TAG_Int = 4 bytes, signed, big endian
                case TagType.TAG_Int:
                // 4 TAG_Long = 8 bytes, signed, big endian
                case TagType.TAG_Long:
                // 5 TAG_Float = 4 bytes, signed, big endian
                case TagType.TAG_Float:
                // 6 TAG_Double = 8 bytes, signed, big endian
                case TagType.TAG_Double:
                // 7 TAG_Byte_Array = [Int] size for size # of [Byte] payloads
                case TagType.TAG_Byte_Array:
                // 8 TAG_String = [Short] size for size # of [UTF-8] characters
                case TagType.TAG_String:
                // 11 TAG_Int_Array = [Int] size for size # of [Int] payloads
                case TagType.TAG_Int_Array:
                    if (currentTag.Name == tagName)
                        return currentTag;
                    else
                        return null;

                // 9 TAG_List = [Byte] for tagID, [Int] for size, size # of payloads of type tagID. [contains unnamed tags]
                case TagType.TAG_List:
                // 10 TAG_Compound = Any number of fully formed named binary tags, terminates with a TAG_End
                case TagType.TAG_Compound:
                    {
                        if (currentTag.Name == tagName)
                            return currentTag;

                        List<NamedBinaryTag> children = (List<NamedBinaryTag>)currentTag.Payload;

                        NamedBinaryTag result = null;

                        foreach (NamedBinaryTag nbt in children)
                        {
                            result = FindTag(tagName, nbt);
                            if (result != null) return result;
                        }

                        return null;
                    }

                default:
                    throw new IndexOutOfRangeException("A non-existent tag was found");
            }
        }
Ejemplo n.º 9
0
        private static void PrintTag(NamedBinaryTag currentTag)
        {
            string tag = "";
            statusIndention++;
            switch (currentTag.Type)
            {
                // ID Type = Payload

                // 0 TAG_End = None [No name]
                case TagType.TAG_End:
                    tag = "End";
            UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));
                    break;

                // 1 TAG_Byte = 1 byte signed
                case TagType.TAG_Byte:
                    tag = "Byte";
            UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));
                    break;
                // 2 TAG_Short = 2 bytes, signed, big endian
                case TagType.TAG_Short:
                    tag = "Short";
            UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));
                    break;
                // 3 TAG_Int = 4 bytes, signed, big endian
                case TagType.TAG_Int:
                    tag = "Int";
            UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));
                    break;
                // 4 TAG_Long = 8 bytes, signed, big endian
                case TagType.TAG_Long:
                    tag = "Long";
            UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));
                    break;
                // 5 TAG_Float = 4 bytes, signed, big endian
                case TagType.TAG_Float:
                    tag = "Float";
            UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));
                    break;
                // 6 TAG_Double = 8 bytes, signed, big endian
                case TagType.TAG_Double:
                    tag = "Double";
            UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));
                    break;
                // 7 TAG_Byte_Array = [Int] size for size # of [Byte] payloads
                case TagType.TAG_Byte_Array:
                    tag = "Byte Array";
            UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));
                    break;
                // 8 TAG_String = [Short] size for size # of [UTF-8] characters
                case TagType.TAG_String:
                    tag = "String";
            UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));
                    break;
                // 11 TAG_Int_Array = [Int] size for size # of [Int] payloads
                case TagType.TAG_Int_Array:
                    tag = "Int Array";
            UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));
                    break;

                // 9 TAG_List = [Byte] for tagID, [Int] for size, size # of payloads of type tagID. [contains unnamed tags]
                case TagType.TAG_List:
                    {
                        tag = "List";
                        UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));

                        List<NamedBinaryTag> children = currentTag.GetList();

                        foreach (NamedBinaryTag nbt in children)
                        {
                            PrintTag(nbt);
                        }

                        break;
                    }
                // 10 TAG_Compound = Any number of fully formed named binary tags, terminates with a TAG_End
                case TagType.TAG_Compound:
                    {
                        tag = "Compound";
                        UpdateStatus(String.Format("{0}:{1}", tag, currentTag.Name));

                        List<NamedBinaryTag> children = currentTag.GetList();

                        foreach (NamedBinaryTag nbt in children)
                        {
                            PrintTag(nbt);
                        }

                        break;
                    }

                default:
                    throw new IndexOutOfRangeException("A non-existent tag was found");
            }

            statusIndention--;
        }
Ejemplo n.º 10
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 (FindTag("Sections", topLevel) == null)
                    {
                        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));
                            //terrain.ConvertChunkToBlocks(xPos.GetInt(), zPos.GetInt(), Blocks.GetByteArray(), 128);
                        }
                    }
                    else
                    {
                        Debug.WriteLine("FOUND A SECTION");
                    }

                }
            }

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

            return chunkList;
        }