Пример #1
0
        private void ParseSection(SubChunk section, ReadOnlySpan <byte> data)
        {
            var reader = new SpanReader();

            var version = reader.ReadByte(data);

            if (version != 8)
            {
                throw new Exception("Wrong chunk version");
            }

            var storageSize = reader.ReadByte(data);

            for (int storage = 0; storage < storageSize; storage++)
            {
                byte paletteAndFlag = reader.ReadByte(data);
                bool isRuntime      = (paletteAndFlag & 1) != 0;
                if (isRuntime)
                {
                    throw new Exception("Can't use runtime for persistent storage.");
                }
                int bitsPerBlock  = paletteAndFlag >> 1;
                int blocksPerWord = (int)Math.Floor(32d / bitsPerBlock);
                int wordCount     = (int)Math.Ceiling(4096d / blocksPerWord);

                int blockIndex = reader.Position;
                reader.Position += wordCount * 4;

                int paletteSize = reader.ReadInt32(data);

                var palette = new Dictionary <int, (short, byte)>();
                for (int j = 0; j < paletteSize; j++)
                {
                    var file = new NbtFile {
                        BigEndian = false, UseVarInt = false
                    };
                    var buffer = data.Slice(reader.Position).ToArray();

                    int numberOfBytesRead = (int)file.LoadFromStream(new MemoryStream(buffer), NbtCompression.None);
                    reader.Position += numberOfBytesRead;
                    var    tag       = file.RootTag;
                    string blockName = tag["name"].StringValue;
                    Block  block     = BlockFactory.GetBlockByName(blockName);
                    short  blockId   = 0;
                    if (block != null)
                    {
                        blockId = (short)block.Id;
                    }
                    else
                    {
                        Log.Warn($"Missing block={blockName}");
                    }
                    short blockMeta = tag["val"].ShortValue;
                    palette.Add(j, (blockId, (byte)blockMeta));
                }

                int nextStore = reader.Position;
                reader.Position = blockIndex;

                int position = 0;
                for (int wordIdx = 0; wordIdx < wordCount; wordIdx++)
                {
                    uint word = reader.ReadUInt32(data);
                    for (int block = 0; block < blocksPerWord; block++)
                    {
                        if (position >= 4096)
                        {
                            continue;                                           // padding bytes
                        }
                        int state = (int)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1));
                        int x     = (position >> 8) & 0xF;
                        int y     = position & 0xF;
                        int z     = (position >> 4) & 0xF;
                        if (state > palette.Count)
                        {
                            Log.Error($"Got wrong state={state} from word. bitsPerBlock={bitsPerBlock}, blocksPerWord={blocksPerWord}, Word={word}");
                        }
                        short bid      = palette[state].Item1;
                        byte  metadata = palette[state].Item2;

                        int runtimeId = (int)BlockFactory.GetRuntimeId(bid, metadata);
                        if (storage == 0)
                        {
                            section.SetBlockByRuntimeId(x, y, z, runtimeId);
                        }
                        else
                        {
                            section.SetLoggedBlockByRuntimeId(x, y, z, runtimeId);
                        }
                        position++;
                    }
                }
                reader.Position = nextStore;
            }
        }
Пример #2
0
        private void ParseSection(SubChunk section, ReadOnlyMemory <byte> data)
        {
            var reader = new MemoryStreamReader(data);

            var version = reader.ReadByte();

            if (version != 8)
            {
                throw new Exception("Wrong chunk version");
            }

            var storageSize = reader.ReadByte();

            for (int storage = 0; storage < storageSize; storage++)
            {
                byte paletteAndFlag = (byte)reader.ReadByte();
                bool isRuntime      = (paletteAndFlag & 1) != 0;
                if (isRuntime)
                {
                    throw new Exception("Can't use runtime for persistent storage.");
                }
                int bitsPerBlock  = paletteAndFlag >> 1;
                int blocksPerWord = (int)Math.Floor(32d / bitsPerBlock);
                int wordCount     = (int)Math.Ceiling(4096d / blocksPerWord);

                long blockIndex = reader.Position;
                reader.Position += wordCount * 4;

                int paletteSize = reader.ReadInt32();

                var palette = new Dictionary <int, int>();
                for (int j = 0; j < paletteSize; j++)
                {
                    var file = new NbtFile
                    {
                        BigEndian = false,
                        UseVarInt = false
                    };
                    file.LoadFromStream(reader, 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.Add(j, block.GetRuntimeId());
                }

                long nextStore = reader.Position;
                reader.Position = blockIndex;

                int position = 0;
                for (int wordIdx = 0; wordIdx < wordCount; wordIdx++)
                {
                    uint word = reader.ReadUInt32();
                    for (int block = 0; block < blocksPerWord; block++)
                    {
                        if (position >= 4096)
                        {
                            continue;                                           // padding bytes
                        }
                        int state = (int)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1));
                        int x     = (position >> 8) & 0xF;
                        int y     = position & 0xF;
                        int z     = (position >> 4) & 0xF;
                        if (state > palette.Count)
                        {
                            Log.Error($"Got wrong state={state} from word. bitsPerBlock={bitsPerBlock}, blocksPerWord={blocksPerWord}, Word={word}");
                        }

                        if (storage == 0)
                        {
                            section.SetBlockByRuntimeId(x, y, z, palette[state]);
                        }
                        else
                        {
                            section.SetLoggedBlockByRuntimeId(x, y, z, palette[state]);
                        }
                        position++;
                    }
                }
                reader.Position = nextStore;
            }
        }