コード例 #1
0
        public override void HandleMcpeBlockEntityData(McpeBlockEntityData message)
        {
            BlockCoordinates coordinates = message.coordinates;
            Nbt         nbt   = message.namedtag;
            ChunkColumn chunk = _worldProvider.GenerateChunkColumn((ChunkCoordinates)coordinates, true);

            if (chunk == null)
            {
                //Log.Warn($"Got block entity for non existing chunk at {coordinates}\n{nbt.NbtFile.RootTag}");
                _futureBlockEntities.TryAdd(coordinates, (NbtCompound)nbt.NbtFile.RootTag);
            }
            else
            {
                //Log.Warn($"Got block entity for existing chunk at {coordinates}\n{nbt.NbtFile.RootTag}");
                chunk.SetBlockEntity(coordinates, (NbtCompound)nbt.NbtFile.RootTag);
            }
        }
コード例 #2
0
        public ChunkColumn GetChunk(int X, int Z)
        {
            var width = 32;
            var depth = 32;

            var rx = X >> 5;
            var rz = Z >> 5;

            var filePath = Path.Combine(_basePath, string.Format(@"region\r.{0}.{1}.mca", rx, rz));

            if (!File.Exists(filePath))
            {
                return(_backEndGenerator.GenerateChunkColumn(new Vector2(X, Z)));
            }

            using (var regionFile = File.OpenRead(filePath))
            {
                var buffer = new byte[8192];

                regionFile.Read(buffer, 0, 8192);

                var xi = (X % width);
                if (xi < 0)
                {
                    xi += 32;
                }
                var zi = (Z % depth);
                if (zi < 0)
                {
                    zi += 32;
                }
                var tableOffset = (xi + zi * width) * 4;

                regionFile.Seek(tableOffset, SeekOrigin.Begin);

                var offsetBuffer = new byte[4];
                regionFile.Read(offsetBuffer, 0, 3);
                Array.Reverse(offsetBuffer);
                var offset = BitConverter.ToInt32(offsetBuffer, 0) << 4;

                var length = regionFile.ReadByte();

                //if (offset == 0 || length == 0) return _backEndGenerator.GenerateChunkColumn(new Vector2(X, Z));

                if (offset == 0 || length == 0)
                {
                    return(_backEndGenerator.GenerateChunkColumn(new Vector2(X, Z)));
                }

                regionFile.Seek(offset, SeekOrigin.Begin);
                var waste = new byte[4];
                regionFile.Read(waste, 0, 4);
                var compressionMode = regionFile.ReadByte();

                var nbt = new NbtFile();
                nbt.LoadFromStream(regionFile, NbtCompression.ZLib);

                var dataTag = nbt.RootTag["Level"];

                var sections = dataTag["Sections"] as NbtList;

                var chunk = new ChunkColumn
                {
                    X       = X,
                    Z       = Z,
                    BiomeId = dataTag["Biomes"].ByteArrayValue
                };

                for (var i = 0; i < chunk.BiomeId.Length; i++)
                {
                    if (chunk.BiomeId[i] > 22)
                    {
                        chunk.BiomeId[i] = 0;
                    }
                }
                if (chunk.BiomeId.Length > 256)
                {
                    throw new Exception();
                }

                // This will turn into a full chunk column
                foreach (var sectionTag in sections)
                {
                    var sy      = sectionTag["Y"].ByteValue * 16;
                    var blocks  = sectionTag["Blocks"].ByteArrayValue;
                    var data    = sectionTag["Data"].ByteArrayValue;
                    var addTag  = sectionTag["Add"];
                    var adddata = new byte[2048];
                    if (addTag != null)
                    {
                        adddata = addTag.ByteArrayValue;
                    }
                    var blockLight = sectionTag["BlockLight"].ByteArrayValue;
                    var skyLight   = sectionTag["SkyLight"].ByteArrayValue;

                    for (var x = 0; x < 16; x++)
                    {
                        for (var z = 0; z < 16; z++)
                        {
                            for (var y = 0; y < 16; y++)
                            {
                                var yi = sy + y - _waterOffsetY;
                                if (yi < 0 || yi >= 256)
                                {
                                    continue;
                                }

                                var anvilIndex = y * 16 * 16 + z * 16 + x;
                                var blockId    = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8);


                                var b = BlockFactory.GetBlockById((ushort)blockId);
                                b.Metadata = Nibble4(data, anvilIndex);
                                chunk.SetBlock(x, yi, z, b);
                                chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex));
                                chunk.SetSkylight(x, yi, z, Nibble4(skyLight, anvilIndex));
                            }
                        }
                    }
                }

                var entities     = dataTag["Entities"] as NbtList;
                var tileEntities = dataTag["TileEntities"] as NbtList;

                if (tileEntities != null)
                {
                    foreach (var nbtTag in tileEntities)
                    {
                        var    blockEntityTag = (NbtCompound)nbtTag;
                        string entityId       = blockEntityTag["id"].StringValue;
                        int    x = blockEntityTag["x"].IntValue;
                        int    y = blockEntityTag["y"].IntValue - _waterOffsetY;
                        int    z = blockEntityTag["z"].IntValue;
                        blockEntityTag["y"] = new NbtInt("y", y);

                        TileEntity blockEntity = TileEntityFactory.GetBlockEntityById(entityId);
                        if (blockEntity != null)
                        {
                            blockEntityTag.Name = string.Empty;
                            chunk.SetBlockEntity(new Vector3(x, y, z), blockEntityTag);
                        }
                    }
                }

                var tileTicks = dataTag["TileTicks"] as NbtList;

                chunk.IsDirty = false;
                return(chunk);
            }
        }
コード例 #3
0
ファイル: ClientUtils.cs プロジェクト: yungtechboy1/MiNET
        public static ChunkColumn DecodeChunkColumn(int subChunkCount, byte[] buffer, BlockPalette bedrockPalette = null, HashSet <BlockStateContainer> internalBlockPallet = null)
        {
            lock (_chunkRead)
            {
                var stream = new MemoryStream(buffer);
                {
                    var defStream = new NbtBinaryReader(stream, true);

                    if (subChunkCount < 1)
                    {
                        Log.Warn("Nothing to read");
                        return(null);
                    }

                    Log.Debug($"Reading {subChunkCount} sections");

                    var chunkColumn = new ChunkColumn(false);

                    for (int chunkIndex = 0; chunkIndex < subChunkCount; chunkIndex++)
                    {
                        int version     = defStream.ReadByte();
                        int storageSize = defStream.ReadByte();

                        var subChunk = chunkColumn[chunkIndex];

                        for (int storageIndex = 0; storageIndex < storageSize; storageIndex++)
                        {
                            int bitsPerBlock  = defStream.ReadByte() >> 1;
                            int blocksPerWord = (int)Math.Floor(32f / bitsPerBlock);
                            int wordsPerChunk = (int)Math.Ceiling(4096f / blocksPerWord);
                            Log.Debug($"New section {chunkIndex}, " +
                                      $"version={version}, " +
                                      $"storageSize={storageSize}, " +
                                      $"storageIndex={storageIndex}, " +
                                      $"bitsPerBlock={bitsPerBlock}, " +
                                      $"noBlocksPerWord={blocksPerWord}, " +
                                      $"wordCount={wordsPerChunk}, " +
                                      $"");


                            long jumpPos = stream.Position;
                            stream.Seek(wordsPerChunk * 4, SeekOrigin.Current);

                            int paletteCount = VarInt.ReadSInt32(stream);
                            var palette      = new int[paletteCount];
                            for (int j = 0; j < paletteCount; j++)
                            {
                                int runtimeId = VarInt.ReadSInt32(stream);
                                if (bedrockPalette == null || internalBlockPallet == null)
                                {
                                    continue;
                                }

                                palette[j] = GetServerRuntimeId(bedrockPalette, internalBlockPallet, runtimeId);
                            }

                            long afterPos = stream.Position;
                            stream.Position = jumpPos;
                            int position = 0;
                            for (int w = 0; w < wordsPerChunk; w++)
                            {
                                uint word = defStream.ReadUInt32();
                                for (int block = 0; block < blocksPerWord; block++)
                                {
                                    if (position >= 4096)
                                    {
                                        continue;
                                    }

                                    uint state = (uint)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1));

                                    int x = (position >> 8) & 0xF;
                                    int y = position & 0xF;
                                    int z = (position >> 4) & 0xF;

                                    int runtimeId = palette[state];

                                    if (storageIndex == 0)
                                    {
                                        subChunk.SetBlockByRuntimeId(x, y, z, (int)runtimeId);
                                    }
                                    else
                                    {
                                        subChunk.SetLoggedBlockByRuntimeId(x, y, z, (int)runtimeId);
                                    }

                                    position++;
                                }
                            }
                            stream.Position = afterPos;
                        }
                    }

                    if (defStream.Read(chunkColumn.biomeId, 0, 256) != 256)
                    {
                        Log.Error($"Out of data biomeId");
                    }
                    //Log.Debug($"biomeId:\n{Package.HexDump(chunk.biomeId)}");

                    //if (stream.Position >= stream.Length - 1) return chunkColumn;

                    int borderBlock = VarInt.ReadSInt32(stream);
                    if (borderBlock != 0)
                    {
                        byte[] buf = new byte[borderBlock];
                        int    len = defStream.Read(buf, 0, borderBlock);
                        Log.Warn($"??? Got borderblock {borderBlock}. Read {len} bytes");
                        Log.Debug($"{Packet.HexDump(buf)}");
                        for (int i = 0; i < borderBlock; i++)
                        {
                            int x = (buf[i] & 0xf0) >> 4;
                            int z = buf[i] & 0x0f;
                            Log.Debug($"x={x}, z={z}");
                        }
                    }

                    if (stream.Position < stream.Length - 1)
                    {
                        while (stream.Position < stream.Length)
                        {
                            NbtFile file = new NbtFile()
                            {
                                BigEndian = false,
                                UseVarInt = true
                            };

                            file.LoadFromStream(stream, NbtCompression.None);
                            var blockEntityTag = file.RootTag;
                            if (blockEntityTag.Name != "alex")
                            {
                                int x = blockEntityTag["x"].IntValue;
                                int y = blockEntityTag["y"].IntValue;
                                int z = blockEntityTag["z"].IntValue;

                                chunkColumn.SetBlockEntity(new BlockCoordinates(x, y, z), (NbtCompound)file.RootTag);

                                Log.Debug($"Blockentity:\n{file.RootTag}");
                            }
                        }
                    }
                    if (stream.Position < stream.Length - 1)
                    {
                        Log.Warn($"Still have data to read\n{Packet.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}");
                    }

                    return(chunkColumn);
                }
            }
        }
コード例 #4
0
        public static ChunkColumn GetChunk(ChunkCoordinates coordinates, string basePath, IWorldProvider generator, int yoffset)
        {
            int width = 32;
            int depth = 32;

            int rx = coordinates.X >> 5;
            int rz = coordinates.Z >> 5;

            string filePath = Path.Combine(basePath, string.Format(@"region\r.{0}.{1}.mca", rx, rz));

            if (!File.Exists(filePath)) return generator.GenerateChunkColumn(coordinates);

            using (var regionFile = File.OpenRead(filePath))
            {
                byte[] buffer = new byte[8192];

                regionFile.Read(buffer, 0, 8192);

                int xi = (coordinates.X%width);
                if (xi < 0) xi += 32;
                int zi = (coordinates.Z%depth);
                if (zi < 0) zi += 32;
                int tableOffset = (xi + zi*width)*4;

                regionFile.Seek(tableOffset, SeekOrigin.Begin);

                byte[] offsetBuffer = new byte[4];
                regionFile.Read(offsetBuffer, 0, 3);
                Array.Reverse(offsetBuffer);
                int offset = BitConverter.ToInt32(offsetBuffer, 0) << 4;

                int length = regionFile.ReadByte();

                if (offset == 0 || length == 0)
                {
                    return generator.GenerateChunkColumn(coordinates);
                }

                regionFile.Seek(offset, SeekOrigin.Begin);
                byte[] waste = new byte[4];
                regionFile.Read(waste, 0, 4);
                int compressionMode = regionFile.ReadByte();

                var nbt = new NbtFile();
                nbt.LoadFromStream(regionFile, NbtCompression.ZLib);

                NbtTag dataTag = nbt.RootTag["Level"];

                NbtList sections = dataTag["Sections"] as NbtList;

                ChunkColumn chunk = new ChunkColumn
                {
                    x = coordinates.X,
                    z = coordinates.Z,
                    biomeId = dataTag["Biomes"].ByteArrayValue
                };

                for (int i = 0; i < chunk.biomeId.Length; i++)
                {
                    if (chunk.biomeId[i] > 22) chunk.biomeId[i] = 0;
                }
                if (chunk.biomeId.Length > 256) throw new Exception();

                // This will turn into a full chunk column
                foreach (NbtTag sectionTag in sections)
                {
                    int sy = sectionTag["Y"].ByteValue*16;
                    byte[] blocks = sectionTag["Blocks"].ByteArrayValue;
                    byte[] data = sectionTag["Data"].ByteArrayValue;
                    NbtTag addTag = sectionTag["Add"];
                    byte[] adddata = new byte[2048];
                    if (addTag != null) adddata = addTag.ByteArrayValue;
                    byte[] blockLight = sectionTag["BlockLight"].ByteArrayValue;
                    byte[] skyLight = sectionTag["SkyLight"].ByteArrayValue;

                    for (int x = 0; x < 16; x++)
                    {
                        for (int z = 0; z < 16; z++)
                        {
                            for (int y = 0; y < 16; y++)
                            {
                                int yi = sy + y - yoffset;
                                if (yi < 0 || yi >= 128) continue;

                                int anvilIndex = y*16*16 + z*16 + x;
                                int blockId = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8);

                                // Anvil to PE friendly converstion
                                if (blockId == 125) blockId = 5;
                                else if (blockId == 126) blockId = 158;
                                else if (blockId == 75) blockId = 50;
                                else if (blockId == 76) blockId = 50;
                                else if (blockId == 123) blockId = 89;
                                else if (blockId == 124) blockId = 89;
                                else if (blockId == 152) blockId = 73;
                                else if (_ignore.BinarySearch(blockId) >= 0) blockId = 0;
                                else if (_gaps.BinarySearch(blockId) >= 0)
                                {
                                    Debug.WriteLine("Missing material: " + blockId);
                                    blockId = 133;
                                }

                                if (blockId > 255) blockId = 41;

                                if (yi == 127 && blockId != 0) blockId = 30;
                                if (yi == 0 && (blockId == 8 || blockId == 9 /*|| blockId == 0*/)) blockId = 7;

                                //if (blockId != 0) blockId = 41;

                                chunk.SetBlock(x, yi, z, (byte) blockId);
                                chunk.SetMetadata(x, yi, z, Nibble4(data, anvilIndex));
                                chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex));
                                chunk.SetSkylight(x, yi, z, Nibble4(skyLight, anvilIndex));
                            }
                        }
                    }
                }

                NbtList entities = dataTag["Entities"] as NbtList;
                NbtList blockEntities = dataTag["TileEntities"] as NbtList;
                if (blockEntities != null)
                {
                    foreach (var nbtTag in blockEntities)
                    {
                        var blockEntityTag = (NbtCompound) nbtTag;
                        string entityId = blockEntityTag["id"].StringValue;
                        int x = blockEntityTag["x"].IntValue;
                        int y = blockEntityTag["y"].IntValue - yoffset;
                        int z = blockEntityTag["z"].IntValue;
                        blockEntityTag["y"] = new NbtInt("y", y);

                        BlockEntity blockEntity = BlockEntityFactory.GetBlockEntityById(entityId);
                        if (blockEntity != null)
                        {
                            blockEntityTag.Name = string.Empty;
                            chunk.SetBlockEntity(new BlockCoordinates(x, y, z), blockEntityTag);
                        }
                    }
                }

                NbtList tileTicks = dataTag["TileTicks"] as NbtList;

                chunk.isDirty = false;
                return chunk;
            }
        }
コード例 #5
0
ファイル: AnvilWorldProvider.cs プロジェクト: LiveMC/SharpMC
        public ChunkColumn GetChunk(int X, int Z)
        {
            var width = 32;
            var depth = 32;

            var rx = X >> 5;
            var rz = Z >> 5;

            var filePath = Path.Combine(_basePath, string.Format(@"region\r.{0}.{1}.mca", rx, rz));

            if (!File.Exists(filePath)) return _backEndGenerator.GenerateChunkColumn(new Vector2(X, Z));

            using (var regionFile = File.OpenRead(filePath))
            {
                var buffer = new byte[8192];

                regionFile.Read(buffer, 0, 8192);

                var xi = (X%width);
                if (xi < 0) xi += 32;
                var zi = (Z%depth);
                if (zi < 0) zi += 32;
                var tableOffset = (xi + zi*width)*4;

                regionFile.Seek(tableOffset, SeekOrigin.Begin);

                var offsetBuffer = new byte[4];
                regionFile.Read(offsetBuffer, 0, 3);
                Array.Reverse(offsetBuffer);
                var offset = BitConverter.ToInt32(offsetBuffer, 0) << 4;

                var length = regionFile.ReadByte();

                //if (offset == 0 || length == 0) return _backEndGenerator.GenerateChunkColumn(new Vector2(X, Z));

                if (offset == 0 || length == 0)
                {
                    return _backEndGenerator.GenerateChunkColumn(new Vector2(X,Z));
                }

                regionFile.Seek(offset, SeekOrigin.Begin);
                var waste = new byte[4];
                regionFile.Read(waste, 0, 4);
                var compressionMode = regionFile.ReadByte();

                var nbt = new NbtFile();
                nbt.LoadFromStream(regionFile, NbtCompression.ZLib);

                var dataTag = nbt.RootTag["Level"];

                var sections = dataTag["Sections"] as NbtList;

                var chunk = new ChunkColumn
                {
                    X = X,
                    Z = Z,
                    BiomeId = dataTag["Biomes"].ByteArrayValue
                };

                for (var i = 0; i < chunk.BiomeId.Length; i++)
                {
                    if (chunk.BiomeId[i] > 22) chunk.BiomeId[i] = 0;
                }
                if (chunk.BiomeId.Length > 256) throw new Exception();

                // This will turn into a full chunk column
                foreach (var sectionTag in sections)
                {
                    var sy = sectionTag["Y"].ByteValue*16;
                    var blocks = sectionTag["Blocks"].ByteArrayValue;
                    var data = sectionTag["Data"].ByteArrayValue;
                    var addTag = sectionTag["Add"];
                    var adddata = new byte[2048];
                    if (addTag != null) adddata = addTag.ByteArrayValue;
                    var blockLight = sectionTag["BlockLight"].ByteArrayValue;
                    var skyLight = sectionTag["SkyLight"].ByteArrayValue;

                    for (var x = 0; x < 16; x++)
                    {
                        for (var z = 0; z < 16; z++)
                        {
                            for (var y = 0; y < 16; y++)
                            {
                                var yi = sy + y - _waterOffsetY;
                                if (yi < 0 || yi >= 256) continue;

                                var anvilIndex = y*16*16 + z*16 + x;
                                var blockId = blocks[anvilIndex] + (Nibble4(adddata, anvilIndex) << 8);

                                var b = BlockFactory.GetBlockById((ushort) blockId);
                                b.Metadata = Nibble4(data, anvilIndex);
                                chunk.SetBlock(x, yi, z, b);
                                chunk.SetBlocklight(x, yi, z, Nibble4(blockLight, anvilIndex));
                                chunk.SetSkylight(x, yi, z, Nibble4(skyLight, anvilIndex));
                            }
                        }
                    }
                }

                var entities = dataTag["Entities"] as NbtList;
                var tileEntities = dataTag["TileEntities"] as NbtList;

                if (tileEntities != null)
                {
                    foreach (var nbtTag in tileEntities)
                    {
                        var blockEntityTag = (NbtCompound)nbtTag;
                        string entityId = blockEntityTag["id"].StringValue;
                        int x = blockEntityTag["x"].IntValue;
                        int y = blockEntityTag["y"].IntValue - _waterOffsetY;
                        int z = blockEntityTag["z"].IntValue;
                        blockEntityTag["y"] = new NbtInt("y", y);

                        TileEntity blockEntity = TileEntityFactory.GetBlockEntityById(entityId);
                        if (blockEntity != null)
                        {
                            blockEntityTag.Name = string.Empty;
                            chunk.SetBlockEntity(new Vector3(x, y, z), blockEntityTag);
                        }
                    }
                }

                var tileTicks = dataTag["TileTicks"] as NbtList;

                chunk.IsDirty = false;
                return chunk;
            }
        }
コード例 #6
0
        public ChunkColumn GenerateChunkColumn(ChunkCoordinates chunkCoordinates)
        {
            lock (_chunkCache)
            {
                ChunkColumn cachedChunk;
                if (_chunkCache.TryGetValue(chunkCoordinates, out cachedChunk))
                {
                    return cachedChunk;
                }

                ChunkColumn chunk = new ChunkColumn();
                chunk.x = chunkCoordinates.X;
                chunk.z = chunkCoordinates.Z;

                int h = PopulateChunk(chunk);

                chunk.SetBlock(0, h + 1, 0, 7);
                chunk.SetBlock(1, h + 1, 0, 41);
                chunk.SetBlock(2, h + 1, 0, 41);
                chunk.SetBlock(3, h + 1, 0, 41);
                chunk.SetBlock(3, h + 1, 0, 41);

                //chunk.SetBlock(6, h + 1, 6, 57);

                chunk.SetBlock(6, h, 9, 63);
                chunk.SetMetadata(6, h, 9, 12);
                var blockEntity = GetBlockEntity((chunkCoordinates.X*16) + 6, h, (chunkCoordinates.Z*16) + 9);
                chunk.SetBlockEntity(blockEntity.Coordinates, blockEntity.GetCompound());

                if (chunkCoordinates.X == 1 && chunkCoordinates.Z == 1)
                {
                    for (int x = 0; x < 10; x++)
                    {
                        for (int z = 0; z < 10; z++)
                        {
                            for (int y = h - 2; y < h; y++)
                            {
                                chunk.SetBlock(x, y, z, 8);
                            }
                        }
                    }
                }

                if (chunkCoordinates.X == 3 && chunkCoordinates.Z == 1)
                {
                    for (int x = 0; x < 10; x++)
                    {
                        for (int z = 0; z < 10; z++)
                        {
                            for (int y = h - 1; y < h; y++)
                            {
                                chunk.SetBlock(x, y, z, 10);
                            }
                        }
                    }
                }

                for (int x = 0; x < 16; x++)
                {
                    for (int z = 0; z < 16; z++)
                    {
                        for (int y = 127; y != 0; y--)
                        {
                            if (chunk.GetBlock(x, y, z) == 0x00)
                            {
                                chunk.SetSkylight(x, y, z, 0xff);
                            }
                            else
                            {
                                chunk.SetSkylight(x, y, z, 0x00);
                            }
                        }
                    }
                }

                _chunkCache[chunkCoordinates] = chunk;

                return chunk;
            }
        }
コード例 #7
0
        public static ChunkColumn DecodeChunkColumn(int subChunkCount, byte[] buffer, BlockPalette bedrockPalette = null, HashSet <BlockStateContainer> internalBlockPallet = null)
        {
            //lock (_chunkRead)
            {
                var stream = new MemoryStream(buffer);
                {
                    var defStream = new BinaryReader(stream);

                    if (subChunkCount < 1)
                    {
                        Log.Warn("Nothing to read");
                        return(null);
                    }

                    //if (Log.IsTraceEnabled()) Log.Trace($"Reading {subChunkCount} sections");

                    var chunkColumn = new ChunkColumn(false);

                    for (int chunkIndex = 0; chunkIndex < subChunkCount; chunkIndex++)
                    {
                        int version     = stream.ReadByte();
                        int storageSize = stream.ReadByte();

                        var subChunk = chunkColumn[chunkIndex];

                        for (int storageIndex = 0; storageIndex < storageSize; storageIndex++)
                        {
                            int  flags         = stream.ReadByte();
                            bool isRuntime     = (flags & 1) != 0;
                            int  bitsPerBlock  = flags >> 1;
                            int  blocksPerWord = (int)Math.Floor(32f / bitsPerBlock);
                            int  wordsPerChunk = (int)Math.Ceiling(4096f / blocksPerWord);
                            if (Log.IsTraceEnabled())
                            {
                                Log.Trace($"New section {chunkIndex}, " +
                                          $"version={version}, " +
                                          $"storageSize={storageSize}, " +
                                          $"storageIndex={storageIndex}, " +
                                          $"bitsPerBlock={bitsPerBlock}, " +
                                          $"isRuntime={isRuntime}, " +
                                          $"noBlocksPerWord={blocksPerWord}, " +
                                          $"wordCount={wordsPerChunk}, " +
                                          $"");
                            }

                            long jumpPos = stream.Position;
                            stream.Seek(wordsPerChunk * 4, SeekOrigin.Current);

                            int paletteCount = VarInt.ReadSInt32(stream);
                            var palette      = new int[paletteCount];
                            for (int j = 0; j < paletteCount; j++)
                            {
                                if (!isRuntime)
                                {
                                    var file = new NbtFile
                                    {
                                        BigEndian = false,
                                        UseVarInt = true
                                    };
                                    file.LoadFromStream(stream, NbtCompression.None);
                                    var tag = (NbtCompound)file.RootTag;

                                    Block block = BlockFactory.GetBlockByName(tag["name"].StringValue);
                                    if (block != null && block.GetType() != typeof(Block) && !(block is Air))
                                    {
                                        List <IBlockState> blockState = ReadBlockState(tag);
                                        block.SetState(blockState);
                                    }
                                    else
                                    {
                                        block = new Air();
                                    }

                                    palette[j] = block.GetRuntimeId();
                                }
                                else
                                {
                                    int runtimeId = VarInt.ReadSInt32(stream);
                                    if (bedrockPalette == null || internalBlockPallet == null)
                                    {
                                        continue;
                                    }

                                    palette[j] = GetServerRuntimeId(bedrockPalette, internalBlockPallet, runtimeId);
                                }
                            }

                            long afterPos = stream.Position;
                            stream.Position = jumpPos;
                            int position = 0;
                            for (int w = 0; w < wordsPerChunk; w++)
                            {
                                uint word = defStream.ReadUInt32();
                                for (int block = 0; block < blocksPerWord; block++)
                                {
                                    if (position >= 4096)
                                    {
                                        continue;
                                    }

                                    uint state = (uint)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1));

                                    int x = (position >> 8) & 0xF;
                                    int y = position & 0xF;
                                    int z = (position >> 4) & 0xF;

                                    int runtimeId = palette[state];

                                    if (storageIndex == 0)
                                    {
                                        subChunk.SetBlockByRuntimeId(x, y, z, (int)runtimeId);
                                    }
                                    else
                                    {
                                        subChunk.SetLoggedBlockByRuntimeId(x, y, z, (int)runtimeId);
                                    }

                                    position++;
                                }
                            }
                            stream.Position = afterPos;
                        }
                    }

                    if (stream.Read(chunkColumn.biomeId, 0, 256) != 256)
                    {
                        return(chunkColumn);
                    }
                    //Log.Debug($"biomeId:\n{Package.HexDump(chunk.biomeId)}");

                    if (stream.Position >= stream.Length - 1)
                    {
                        return(chunkColumn);
                    }

                    int borderBlock = VarInt.ReadSInt32(stream);
                    if (borderBlock != 0)
                    {
                        Log.Warn($"??? Got borderblock with value {borderBlock}.");

                        int len   = (int)(stream.Length - stream.Position);
                        var bytes = new byte[len];
                        stream.Read(bytes, 0, len);
                        Log.Warn($"Data to read for border blocks\n{Packet.HexDump(new ReadOnlyMemory<byte>(bytes))}");

                        //byte[] buf = new byte[borderBlock];
                        //int len = stream.Read(buf, 0, borderBlock);
                        //Log.Warn($"??? Got borderblock {borderBlock}. Read {len} bytes");
                        //Log.Debug($"{Packet.HexDump(buf)}");
                        //for (int i = 0; i < borderBlock; i++)
                        //{
                        //	int x = (buf[i] & 0xf0) >> 4;
                        //	int z = buf[i] & 0x0f;
                        //	Log.Debug($"x={x}, z={z}");
                        //}
                    }

                    if (stream.Position < stream.Length - 1)
                    {
                        while (stream.Position < stream.Length)
                        {
                            NbtFile file = new NbtFile()
                            {
                                BigEndian = false,
                                UseVarInt = true
                            };

                            file.LoadFromStream(stream, NbtCompression.None);
                            var blockEntityTag = file.RootTag;
                            if (blockEntityTag.Name != "alex")
                            {
                                int x = blockEntityTag["x"].IntValue;
                                int y = blockEntityTag["y"].IntValue;
                                int z = blockEntityTag["z"].IntValue;

                                chunkColumn.SetBlockEntity(new BlockCoordinates(x, y, z), (NbtCompound)file.RootTag);

                                if (Log.IsTraceEnabled())
                                {
                                    Log.Trace($"Blockentity:\n{file.RootTag}");
                                }
                            }
                        }
                    }

                    if (stream.Position < stream.Length - 1)
                    {
                        int len   = (int)(stream.Length - stream.Position);
                        var bytes = new byte[len];
                        stream.Read(bytes, 0, len);
                        Log.Warn($"Still have data to read\n{Packet.HexDump(new ReadOnlyMemory<byte>(bytes))}");
                    }

                    return(chunkColumn);
                }
            }
        }