public override void FromStream(BinaryReader reader)
        {
            Stream stream = reader.BaseStream;

            Value = new BlockCoordinates
            {
                X = VarInt.ReadSInt32(stream),
                Y = VarInt.ReadSInt32(stream),
                Z = VarInt.ReadSInt32(stream),
            };
        }
Example #2
0
        public static ChunkColumn DecocedChunkColumn(byte[] buffer)
        {
            lock (_chunkRead)
            {
                MemoryStream stream = new MemoryStream(buffer);
                {
                    NbtBinaryReader defStream = new NbtBinaryReader(stream, true);

                    Log.Debug("New chunk column");

                    int count = defStream.ReadByte();
                    if (count < 1)
                    {
                        Log.Warn("Nothing to read");
                        return(null);
                    }

                    if (count > 1)
                    {
                        Log.Debug($"Reading {count} sections");
                    }
                    else
                    {
                        Log.Debug($"Reading {count} sections");
                    }

                    ChunkColumn chunkColumn = new ChunkColumn();

                    for (int s = 0; s < count; s++)
                    {
                        int idx = defStream.ReadByte();

                        Log.Debug($"New section {s}, index={idx}");
                        Chunk chunk = chunkColumn.chunks[s];

                        int chunkSize = 16 * 16 * 16;
                        defStream.Read(chunk.blocks, 0, chunkSize);
                        //Log.Debug($"Blocks1:\n{Package.HexDump(chunk.blocks)}");

                        if (defStream.Read(chunk.metadata.Data, 0, chunkSize / 2) != chunkSize / 2)
                        {
                            Log.Error($"Out of data: metadata");
                        }

                        //Log.Debug($"metadata:\n{Package.HexDump(chunk.metadata.Data)}");

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

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

                        //Log.Debug($"skylight.Data:\n{Package.HexDump(chunk.skylight.Data, 64)}");
                        //Log.Debug($"blocklight.Data:\n{Package.HexDump(chunk.blocklight.Data)}");

                        //byte[] ints = new byte[256*4];
                        //var readLen = defStream.Read(ints, 0, ints.Length);
                        //if (readLen != ints.Length) Log.Error($"Out of data biomeColors, read lenght {readLen}");
                        //Log.Debug($"biomeColor (pre):\n{Package.HexDump(ints)}");

                        //return null;
                        //int j = 0;
                        //for (int i = 0; i < ints.Length; i = i + 4)
                        //{
                        //	chunk.biomeId[j] = ints[i];
                        //	chunk.biomeColor[j++] = BitConverter.ToInt32(new[] {(byte) 0, ints[i + 1], ints[i + 2], ints[i + 3]}, 0);
                        //}
                        //Log.Debug($"biomeId (post):\n{Package.HexDump(chunk.biomeId)}");

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

                        ////return chunk;

                        //return chunk;
                    }

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

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

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

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

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

                    int extraCount = VarInt.ReadSInt32(stream);
                    if (extraCount != 0)
                    {
                        //Log.Warn($"Got extradata\n{Package.HexDump(defStream.ReadBytes(extraCount*10))}");
                        for (int i = 0; i < extraCount; i++)
                        {
                            var hash      = VarInt.ReadSInt32(stream);
                            var blockData = defStream.ReadInt16();
                            Log.Warn($"Got extradata: hash=0x{hash:X2}, blockdata=0x{blockData:X2}");
                        }
                    }

                    if (stream.Position < stream.Length - 1)
                    {
                        //Log.Debug($"Got NBT data\n{Package.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}");

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

                            file.LoadFromStream(stream, NbtCompression.None);

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

                return(new ChunkColumn());
            }
        }
Example #3
0
 public int ReadSignedVarInt()
 {
     return(VarInt.ReadSInt32(_buffer));
 }
Example #4
0
        public static ChunkColumn DecocedChunkColumn(byte[] buffer)
        {
            lock (_chunkRead)
            {
                MemoryStream stream = new MemoryStream(buffer);
                {
                    NbtBinaryReader defStream = new NbtBinaryReader(stream, true);

                    Log.Debug("New chunk column");

                    int count = defStream.ReadByte();
                    if (count < 1)
                    {
                        Log.Warn("Nothing to read");
                        return(null);
                    }

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

                    ChunkColumn chunkColumn = new ChunkColumn();

                    for (int s = 0; s < count; s++)
                    {
                        int version     = defStream.ReadByte();
                        int storageSize = defStream.ReadByte();

                        for (int i = 0; i < storageSize; i++)
                        {
                            int bitsPerBlock    = defStream.ReadByte() >> 1;
                            int noBlocksPerWord = (int)Math.Floor(32f / bitsPerBlock);
                            int wordCount       = (int)Math.Ceiling(4096f / noBlocksPerWord);
                            Log.Warn($"New section {s}, " +
                                     $"version={version}, " +
                                     $"storageSize={storageSize}, " +
                                     $"bitsPerBlock={bitsPerBlock}, " +
                                     $"noBlocksPerWord={noBlocksPerWord}, " +
                                     $"wordCount={wordCount}, " +
                                     $"");
                            defStream.ReadBytes(wordCount * 4);
                            int paletteCount = VarInt.ReadSInt32(stream);
                            //Log.Warn($"New section {s}, " +
                            //		$"version={version}, " +
                            //		$"storageSize={storageSize}, " +
                            //		$"bitsPerBlock={bitsPerBlock}, " +
                            //		$"noBlocksPerWord={noBlocksPerWord}, " +
                            //		$"wordCount={wordCount}, " +
                            //		$"paletteCount={paletteCount}" +
                            //		$"");

                            for (int j = 0; j < paletteCount; j++)
                            {
                                VarInt.ReadSInt32(stream);
                            }
                        }
                    }

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

                    byte[] ba = new byte[512];
                    if (defStream.Read(ba, 0, 256 * 2) != 256 * 2)
                    {
                        Log.Error($"Out of data height");
                    }

                    Buffer.BlockCopy(ba, 0, chunkColumn.height, 0, 512);
                    //Log.Debug($"Heights:\n{Package.HexDump(ba)}");

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

                    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)
                    {
                        //Log.Debug($"Got NBT data\n{Package.HexDump(defStream.ReadBytes((int) (stream.Length - stream.Position)))}");

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

                            file.LoadFromStream(stream, NbtCompression.None);

                            Log.Debug($"Blockentity: {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);
                }
            }
        }
Example #5
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 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);
                }
            }
        }
Example #6
0
        private void HandleChunk(bool cacheEnabled, uint subChunkCount, byte[] chunkData, int cx, int cz, Action <ChunkColumn> callback)
        {
            if (cacheEnabled)
            {
                Log.Warn($"Unsupported cache enabled!");
            }

            bool gotLight = false;

            try
            {
                using (MemoryStream stream = new MemoryStream(chunkData))
                {
                    NbtBinaryReader defStream = new NbtBinaryReader(stream, true);

                    //int count = defStream.ReadByte();
                    if (subChunkCount < 1)
                    {
                        Log.Warn("Nothing to read");
                        return;
                    }

                    ChunkColumn chunkColumn = new ChunkColumn();
                    chunkColumn.IsDirty = true;
                    chunkColumn.X       = cx;
                    chunkColumn.Z       = cz;

                    for (int s = 0; s < subChunkCount; s++)
                    {
                        var section = chunkColumn.Sections[s] as ChunkSection;

                        int version = defStream.ReadByte();

                        if (version == 1 || version == 8)
                        {
                            int storageSize = defStream.ReadByte();

                            if (section == null)
                            {
                                section = new ChunkSection(chunkColumn, s, true, 2);
                            }

                            for (int storage = 0; storage < storageSize; storage++)
                            {
                                int  paletteAndFlag = defStream.ReadByte();
                                bool isRuntime      = (paletteAndFlag & 1) != 0;
                                int  bitsPerBlock   = paletteAndFlag >> 1;
                                int  blocksPerWord  = (int)Math.Floor(32f / bitsPerBlock);
                                int  wordCount      = (int)Math.Ceiling(4096.0f / blocksPerWord);

                                uint[] words = new uint[wordCount];
                                for (int w = 0; w < wordCount; w++)
                                {
                                    int word = defStream.ReadInt32();
                                    words[w] = SwapBytes((uint)word);
                                }

                                uint[] pallete = new uint[0];

                                if (isRuntime)
                                {
                                    int palleteSize = VarInt.ReadSInt32(stream);
                                    pallete = new uint[palleteSize];

                                    for (int pi = 0; pi < pallete.Length; pi++)
                                    {
                                        var ui = (uint)VarInt.ReadSInt32(stream);
                                        pallete[pi] = ui;
                                    }

                                    if (palleteSize == 0)
                                    {
                                        Log.Warn($"Pallete size is 0");
                                        continue;
                                    }
                                }

                                int position = 0;
                                for (int w = 0; w < wordCount; w++)
                                {
                                    uint word = words[w];
                                    for (int block = 0; block < blocksPerWord; block++)
                                    {
                                        if (position >= 4096)
                                        {
                                            break;                                                   // padding bytes
                                        }
                                        uint state =
                                            (uint)((word >> ((position % blocksPerWord) * bitsPerBlock)) &
                                                   ((1 << bitsPerBlock) - 1));
                                        int x = (position >> 8) & 0xF;
                                        int y = position & 0xF;
                                        int z = (position >> 4) & 0xF;

                                        if (state >= pallete.Length)
                                        {
                                            continue;
                                        }

                                        BlockState translated = GetBlockState(pallete[state]);

                                        if (translated != null)
                                        {
                                            if (translated.Block is Water)
                                            {
                                                string a = "";
                                            }
                                            section.Set(storage, x, y, z, translated);
                                        }

                                        position++;
                                    }

                                    if (position >= 4096)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            if (section == null)
                            {
                                section = new ChunkSection(chunkColumn, s, true, 1);
                            }

                            #region OldFormat

                            byte[] blockIds = new byte[4096];
                            defStream.Read(blockIds, 0, blockIds.Length);

                            NibbleArray data = new NibbleArray(4096);
                            defStream.Read(data.Data, 0, data.Data.Length);

                            for (int x = 0; x < 16; x++)
                            {
                                for (int z = 0; z < 16; z++)
                                {
                                    for (int y = 0; y < 16; y++)
                                    {
                                        int idx  = (x << 8) + (z << 4) + y;
                                        var id   = blockIds[idx];
                                        var meta = data[idx];

                                        var ruid = BlockFactory.GetBlockStateID(id, meta);

                                        BlockState result = null;

                                        if (!_convertedStates.TryGetValue(
                                                ruid, out result))
                                        {
                                            if (id == 124 || id == 123)
                                            {
                                                result = BlockFactory.GetBlockState("minecraft:redstone_lamp");

                                                if (id == 124)
                                                {
                                                    result = result.WithProperty("lit", "true");
                                                }
                                            }
                                            else if (id > 0 && result == null)
                                            {
                                                var reverseMap =
                                                    MiNET.Worlds.AnvilWorldProvider.Convert.FirstOrDefault(
                                                        map => map.Value.Item1 == id);

                                                if (reverseMap.Value != null)
                                                {
                                                    id = (byte)reverseMap.Key;
                                                }

                                                var res = BlockFactory.GetBlockStateID(id, meta);

                                                if (AnvilWorldProvider.BlockStateMapper.TryGetValue(res, out var res2))
                                                {
                                                    var t = BlockFactory.GetBlockState(res2);
                                                    t = TranslateBlockState(t, id, meta);

                                                    result = t;
                                                }
                                                else
                                                {
                                                    Log.Info($"Did not find anvil statemap: {result.Name}");

                                                    result = TranslateBlockState(
                                                        BlockFactory.GetBlockState(res), id, meta);
                                                }
                                            }

                                            if (result == null)
                                            {
                                                var results = BlockFactory.RuntimeIdTable.Where(xx => xx.Id == id)
                                                              .ToArray();

                                                if (results.Length > 0)
                                                {
                                                    var first = results.FirstOrDefault(xx => xx.Data == meta);

                                                    if (first == default)
                                                    {
                                                        first = results[0];
                                                    }

                                                    result = TranslateBlockState(
                                                        BlockFactory.GetBlockState((uint)first.RuntimeId), id, meta);
                                                }
                                            }

                                            if (result == null)
                                            {
                                                result = new BlockState()
                                                {
                                                    Name  = $"{id}:{meta.ToString()}",
                                                    Model = BlockFactory.UnknownBlockModel,
                                                    Block = new Block(0)
                                                    {
                                                    }
                                                };

                                                Log.Info($"Unknown block: {id}:{meta}");
                                            }

                                            if (result != null)
                                            {
                                                _convertedStates.TryAdd(ruid, result);
                                            }
                                        }

                                        if (result != null)
                                        {
                                            section.Set(x, y, z, result);
                                        }
                                        else
                                        {
                                            Log.Info($"Unknown block: {id}:{meta}");
                                        }
                                    }
                                }
                            }

                            #endregion
                        }

                        if (UseAlexChunks)
                        {
                            //  Log.Info($"Alex chunk!");

                            var rawSky = new API.Utils.NibbleArray(4096);
                            defStream.Read(rawSky.Data, 0, rawSky.Data.Length);

                            var rawBlock = new API.Utils.NibbleArray(4096);
                            defStream.Read(rawBlock.Data, 0, rawBlock.Data.Length);

                            for (int x = 0; x < 16; x++)
                            {
                                for (int y = 0; y < 16; y++)
                                {
                                    for (int z = 0; z < 16; z++)
                                    {
                                        var peIndex = (x * 256) + (z * 16) + y;
                                        var sky     = rawSky[peIndex];
                                        var block   = rawBlock[peIndex];

                                        var idx = y << 8 | z << 4 | x;

                                        section.SkyLight[idx]   = sky;
                                        section.BlockLight[idx] = block;
                                    }
                                }
                            }

                            gotLight = true;
                        }

                        section.RemoveInvalidBlocks();
                        section.IsDirty = true;

                        //Make sure the section is saved.
                        chunkColumn.Sections[s] = section;
                    }


                    /* byte[] ba = new byte[512];
                     * if (defStream.Read(ba, 0, 256 * 2) != 256 * 2) Log.Error($"Out of data height");
                     *
                     * Buffer.BlockCopy(ba, 0, chunkColumn.Height, 0, 512);*/

                    int[] biomeIds = new int[256];
                    for (int i = 0; i < biomeIds.Length; i++)
                    {
                        biomeIds[i] = defStream.ReadByte();
                    }

                    chunkColumn.BiomeId = biomeIds;

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

                    int borderBlock = VarInt.ReadSInt32(stream);
                    if (borderBlock > 0)
                    {
                        byte[] buf = new byte[borderBlock];
                        int    len = defStream.Read(buf, 0, borderBlock);
                    }


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

                                file.LoadFromStream(stream, NbtCompression.None);

                                if (file.RootTag.Name == "alex")
                                {
                                    NbtCompound alexCompound = (NbtCompound)file.RootTag;

                                    for (int ci = 0; ci < subChunkCount; ci++)
                                    {
                                        var section = (ChunkSection)chunkColumn.Sections[ci];

                                        var rawSky = new API.Utils.NibbleArray(4096);
                                        if (alexCompound.TryGet($"skylight-{ci}", out NbtByteArray skyData))
                                        {
                                            rawSky.Data = skyData.Value;
                                        }
                                        //defStream.Read(rawSky.Data, 0, rawSky.Data.Length);

                                        var rawBlock = new API.Utils.NibbleArray(4096);
                                        if (alexCompound.TryGet($"blocklight-{ci}", out NbtByteArray blockData))
                                        {
                                            rawBlock.Data = blockData.Value;
                                        }

                                        for (int x = 0; x < 16; x++)
                                        {
                                            for (int y = 0; y < 16; y++)
                                            {
                                                for (int z = 0; z < 16; z++)
                                                {
                                                    var peIndex = (x * 256) + (z * 16) + y;
                                                    var sky     = rawSky[peIndex];
                                                    var block   = rawBlock[peIndex];

                                                    var idx = y << 8 | z << 4 | x;

                                                    section.SkyLight[idx]   = sky;
                                                    section.BlockLight[idx] = block;
                                                }
                                            }
                                        }

                                        chunkColumn.Sections[ci] = section;
                                    }

                                    gotLight = true;
                                }

                                if (stream.Position < stream.Length - 1)
                                {
                                    //   pre = stream.ReadByte();
                                }
                            }
                            catch (Exception ex)
                            {
                                // Log.Warn(ex, $"Reading chunk extra data (Loop={loop})");
                            }

                            loop++;
                        }
                    }

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

                    if (gotLight)
                    {
                        chunkColumn.SkyLightDirty   = false;
                        chunkColumn.BlockLightDirty = false;
                    }

                    chunkColumn.CalculateHeight(!gotLight && ClientSideLighting);

                    //Done processing this chunk, send to world
                    callback?.Invoke(chunkColumn);
                }
            }
            catch (Exception ex)
            {
                Log.Error($"Exception in chunk loading: {ex.ToString()}");
            }
            finally
            {
            }
        }
Example #7
0
        private void HandleChunk(byte[] chunkData, int cx, int cz, Action <ChunkColumn> callback)
        {
            MeasureProfiler.StartCollectingData();
            var profiler = MiniProfiler.StartNew("BEToJavaColumn");

            try
            {
                using (MemoryStream stream = new MemoryStream(chunkData))
                {
                    NbtBinaryReader defStream = new NbtBinaryReader(stream, true);

                    int count = defStream.ReadByte();
                    if (count < 1)
                    {
                        Log.Warn("Nothing to read");
                        return;
                    }

                    ChunkColumn chunkColumn = new ChunkColumn();
                    chunkColumn.IsDirty = true;
                    chunkColumn.X       = cx;
                    chunkColumn.Z       = cz;

                    for (int s = 0; s < count; s++)
                    {
                        var section = chunkColumn.Sections[s] as ChunkSection;
                        if (section == null)
                        {
                            section = new ChunkSection(s, true);
                        }

                        int version = defStream.ReadByte();

                        if (version == 1 || version == 8)
                        {
                            int storageSize = defStream.ReadByte();

                            for (int storage = 0; storage < storageSize; storage++)
                            {
                                int  paletteAndFlag = defStream.ReadByte();
                                bool isRuntime      = (paletteAndFlag & 1) != 0;
                                int  bitsPerBlock   = paletteAndFlag >> 1;
                                int  blocksPerWord  = (int)Math.Floor(32f / bitsPerBlock);
                                int  wordCount      = (int)Math.Ceiling(4096.0f / blocksPerWord);

                                uint[] words = new uint[wordCount];
                                for (int w = 0; w < wordCount; w++)
                                {
                                    int word = defStream.ReadInt32();
                                    words[w] = SwapBytes((uint)word);
                                }

                                uint[] pallete = new uint[0];

                                if (isRuntime)
                                {
                                    int palleteSize = VarInt.ReadSInt32(stream);
                                    pallete = new uint[palleteSize];

                                    for (int pi = 0; pi < pallete.Length; pi++)
                                    {
                                        var ui = (uint)VarInt.ReadSInt32(stream);
                                        pallete[pi] = ui;
                                    }

                                    if (palleteSize == 0)
                                    {
                                        Log.Warn($"Pallete size is 0");
                                        continue;
                                    }
                                }

                                int position = 0;
                                for (int w = 0; w < wordCount; w++)
                                {
                                    uint word = words[w];
                                    for (int block = 0; block < blocksPerWord; block++)
                                    {
                                        if (position >= 4096)
                                        {
                                            break;                                                   // padding bytes
                                        }
                                        uint state =
                                            (uint)((word >> ((position % blocksPerWord) * bitsPerBlock)) &
                                                   ((1 << bitsPerBlock) - 1));
                                        int x = (position >> 8) & 0xF;
                                        int y = position & 0xF;
                                        int z = (position >> 4) & 0xF;

                                        if (storage == 0)
                                        {
                                            if (state >= pallete.Length)
                                            {
                                                continue;
                                            }

                                            IBlockState translated = _convertedStates.GetOrAdd(pallete[state],
                                                                                               u =>
                                            {
                                                if (_blockStateMap.TryGetValue(pallete[state], out var bs))
                                                {
                                                    var result =
                                                        BlockFactory.RuntimeIdTable.FirstOrDefault(xx =>
                                                                                                   xx.Name == bs.Name);

                                                    if (result != null && result.Id >= 0)
                                                    {
                                                        var reverseMap = MiNET.Worlds.AnvilWorldProvider.Convert.FirstOrDefault(map =>
                                                                                                                                map.Value.Item1 == result.Id);

                                                        var id = result.Id;
                                                        if (reverseMap.Value != null)
                                                        {
                                                            id = reverseMap.Key;
                                                        }

                                                        var res = BlockFactory.GetBlockStateID(
                                                            (int)id,
                                                            (byte)bs.Data);

                                                        if (AnvilWorldProvider.BlockStateMapper.TryGetValue(
                                                                res,
                                                                out var res2))
                                                        {
                                                            var t = BlockFactory.GetBlockState(res2);
                                                            t     = TranslateBlockState(t, id,
                                                                                        bs.Data);

                                                            return(t);
                                                        }
                                                        else
                                                        {
                                                            Log.Info(
                                                                $"Did not find anvil statemap: {result.Name}");
                                                            return(TranslateBlockState(
                                                                       BlockFactory.GetBlockState(result.Name),
                                                                       id, bs.Data));
                                                        }
                                                    }

                                                    return(TranslateBlockState(
                                                               BlockFactory.GetBlockState(bs.Name),
                                                               -1, bs.Data));
                                                }

                                                return(null);
                                            });

                                            if (translated != null)
                                            {
                                                section.Set(x, y, z, translated);
                                            }
                                        }
                                        else
                                        {
                                            //TODO.
                                        }

                                        position++;
                                    }

                                    if (position >= 4096)
                                    {
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            #region OldFormat

                            byte[] blockIds = new byte[4096];
                            defStream.Read(blockIds, 0, blockIds.Length);

                            NibbleArray data = new NibbleArray(4096);
                            defStream.Read(data.Data, 0, data.Data.Length);

                            for (int x = 0; x < 16; x++)
                            {
                                for (int z = 0; z < 16; z++)
                                {
                                    for (int y = 0; y < 16; y++)
                                    {
                                        int idx  = (x << 8) + (z << 4) + y;
                                        var id   = blockIds[idx];
                                        var meta = data[idx];

                                        IBlockState result = null;

                                        if (id > 0 && result == null)
                                        {
                                            var res = BlockFactory.GetBlockStateID(id, meta);

                                            if (AnvilWorldProvider.BlockStateMapper.TryGetValue(res,
                                                                                                out var res2))
                                            {
                                                var t = BlockFactory.GetBlockState(res2);
                                                t = TranslateBlockState(t, id,
                                                                        meta);

                                                result = t;
                                            }
                                            else
                                            {
                                                Log.Info($"Did not find anvil statemap: {result.Name}");
                                                result = TranslateBlockState(BlockFactory.GetBlockState(res),
                                                                             id, meta);
                                            }
                                        }

                                        if (result == null)
                                        {
                                            var results = BlockFactory.RuntimeIdTable.Where(xx =>
                                                                                            xx.Id == id && xx.Data == meta).ToArray();

                                            if (results.Length > 0)
                                            {
                                                result = TranslateBlockState(
                                                    BlockFactory.GetBlockState((uint)results[0].RuntimeId), id,
                                                    meta);
                                            }
                                        }

                                        if (result != null)
                                        {
                                            section.Set(x, y, z, result);
                                        }
                                    }
                                }
                            }

                            #endregion
                        }

                        if (UseAlexChunks)
                        {
                            //  Log.Info($"Alex chunk!");

                            var rawSky = new Utils.NibbleArray(4096);
                            defStream.Read(rawSky.Data, 0, rawSky.Data.Length);

                            var rawBlock = new Utils.NibbleArray(4096);
                            defStream.Read(rawBlock.Data, 0, rawBlock.Data.Length);

                            for (int x = 0; x < 16; x++)
                            {
                                for (int y = 0; y < 16; y++)
                                {
                                    for (int z = 0; z < 16; z++)
                                    {
                                        var peIndex = (x * 256) + (z * 16) + y;
                                        var sky     = rawSky[peIndex];
                                        var block   = rawBlock[peIndex];

                                        var idx = y << 8 | z << 4 | x;

                                        section.SkyLight[idx]   = sky;
                                        section.BlockLight[idx] = block;
                                    }
                                }
                            }
                        }

                        section.RemoveInvalidBlocks();
                        section.IsDirty = true;

                        //Make sure the section is saved.
                        chunkColumn.Sections[s] = section;
                    }


                    byte[] ba = new byte[512];
                    if (defStream.Read(ba, 0, 256 * 2) != 256 * 2)
                    {
                        Log.Error($"Out of data height");
                    }

                    Buffer.BlockCopy(ba, 0, chunkColumn.Height, 0, 512);

                    int[] biomeIds = new int[256];
                    for (int i = 0; i < biomeIds.Length; i++)
                    {
                        biomeIds[i] = defStream.ReadByte();
                    }

                    chunkColumn.BiomeId = biomeIds;

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

                    int borderBlock = VarInt.ReadSInt32(stream);
                    if (borderBlock > 0)
                    {
                        byte[] buf = new byte[borderBlock];
                        int    len = defStream.Read(buf, 0, borderBlock);
                    }


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

                            file.LoadFromStream(stream, NbtCompression.None);
                        }
                    }

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

                    //Done processing this chunk, send to world
                    callback?.Invoke(chunkColumn);
                }
            }
            catch (Exception ex)
            {
                Log.Error($"Exception in chunk loading: {ex.ToString()}");
            }
            finally
            {
                profiler?.Stop();
                MeasureProfiler.SaveData();
            }
        }
Example #8
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);
                }
            }
        }
Example #9
0
 public override void FromStream(BinaryReader reader)
 {
     Value = VarInt.ReadSInt32(reader.BaseStream);
 }