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); }
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--; }