Пример #1
0
        private void ProcessNode(IBlockAccess level, ChunkColumn chunk, BlockCoordinates coordinates, Queue <BlockCoordinates> lightBfsQueue, HashSet <BlockCoordinates> lightBfSet)
        {
            //if (section.IsAllAir())

            byte currentSkyLight = GetSkyLight(coordinates, chunk);

            int      sectionIdx = coordinates.Y >> 4;
            SubChunk subChunk   = chunk.GetSubChunk(coordinates.Y);

            byte maxSkyLight = currentSkyLight;

            if (coordinates.Y < 255)
            {
                var up = coordinates.BlockUp();
                maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, up, currentSkyLight, up: true));
            }

            if (coordinates.Y > 0)
            {
                var down = coordinates.BlockDown();
                maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, down, currentSkyLight, down: true));
            }

            var west = coordinates.BlockWest();

            maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, west, currentSkyLight));


            var east = coordinates.BlockEast();

            maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, east, currentSkyLight));


            var south = coordinates.BlockSouth();

            maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, south, currentSkyLight));

            var north = coordinates.BlockNorth();

            maxSkyLight = Math.Max(maxSkyLight, SetLightLevel(level, chunk, subChunk, sectionIdx, lightBfsQueue, lightBfSet, north, currentSkyLight));

            if (IsTransparent(coordinates, subChunk) && currentSkyLight != 15)
            {
                int diffuseLevel = GetDiffuseLevel(coordinates, subChunk);
                maxSkyLight = (byte)Math.Max(currentSkyLight, maxSkyLight - diffuseLevel);

                if (maxSkyLight > currentSkyLight)
                {
                    level.SetSkyLight(coordinates, maxSkyLight);

                    if (!lightBfSet.Contains(coordinates))
                    {
                        lightBfsQueue.Enqueue(coordinates);
                        lightBfSet.Add(coordinates);
                    }
                }
            }
        }
Пример #2
0
        public static byte GetSkyLight(BlockCoordinates blockCoordinates, SubChunk chunk)
        {
            if (chunk == null)
            {
                return(15);
            }

            int bx = blockCoordinates.X & 0x0f;
            int by = blockCoordinates.Y & 0xff;
            int bz = blockCoordinates.Z & 0x0f;

            return(chunk.GetSkylight(bx, by - 16 * (by >> 4), bz));
        }
Пример #3
0
        public static bool IsTransparent(BlockCoordinates blockCoordinates, SubChunk section)
        {
            if (section == null)
            {
                return(true);
            }

            int bx = blockCoordinates.X & 0x0f;
            int by = blockCoordinates.Y & 0xff;
            int bz = blockCoordinates.Z & 0x0f;

            int bid = section.GetBlockId(bx, by - 16 * (by >> 4), bz);

            return(bid == 0 || BlockFactory.TransparentBlocks[bid] == 1);
        }
Пример #4
0
        public static int GetDiffuseLevel(BlockCoordinates blockCoordinates, SubChunk section)
        {
            //TODO: Figure out if this is really correct. Perhaps should be zero.
            if (section == null)
            {
                return(15);
            }

            int bx = blockCoordinates.X & 0x0f;
            int by = blockCoordinates.Y & 0xff;
            int bz = blockCoordinates.Z & 0x0f;

            int bid = section.GetBlockId(bx, by - 16 * (by >> 4), bz);

            return(bid == 8 || bid == 9 ? 3 : bid == 18 || bid == 161 || bid == 30 ? 2 : 1);
        }
Пример #5
0
        public object Clone()
        {
            SubChunk cc = CreateObject();

            cc._isAllAir = _isAllAir;
            cc.IsDirty   = IsDirty;

            cc._runtimeIds = new List <int>(_runtimeIds);
            _blocks.CopyTo(cc._blocks, 0);
            cc._loggedRuntimeIds = new List <int>(_loggedRuntimeIds);
            _loggedBlocks.CopyTo(cc._loggedBlocks, 0);
            _blocklight.Data.CopyTo(cc._blocklight.Data, 0);
            _skylight.Data.CopyTo(cc._skylight.Data, 0);

            if (_cache != null)
            {
                cc._cache = (byte[])_cache.Clone();
            }

            return(cc);
        }
Пример #6
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;
            }
        }
Пример #7
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;
            }
        }
Пример #8
0
        private byte SetLightLevel(IBlockAccess level, ChunkColumn chunk, SubChunk subChunk, int sectionIdx, Queue <BlockCoordinates> lightBfsQueue, HashSet <BlockCoordinates> lightBfSet, BlockCoordinates coordinates, byte lightLevel, bool down = false, bool up = false)
        {
            //Interlocked.Add(ref visits, 1);

            if (TrackResults)
            {
                MakeVisit(coordinates);
            }

            if (!(up || down) && (chunk.X != coordinates.X >> 4 || chunk.Z != coordinates.Z >> 4))
            {
                chunk    = level.GetChunk((ChunkCoordinates)coordinates);
                subChunk = null;
            }
            else
            {
                if ((up || down) && coordinates.Y >> 4 != sectionIdx)
                {
                    subChunk = null;
                }
            }

            if (chunk == null /* || chunk.chunks == null*/)
            {
                return(lightLevel);
            }

            if (!down && !up && coordinates.Y >= GetHeight(coordinates, chunk))
            {
                if (GetSkyLight(coordinates, subChunk) != 15)
                {
                    SetSkyLight(coordinates, 15, chunk);

                    if (!lightBfSet.Contains(coordinates))
                    {
                        lightBfsQueue.Enqueue(coordinates);
                        lightBfSet.Add(coordinates);
                    }
                }

                return(15);
            }

            if (subChunk == null)
            {
                subChunk = chunk.GetSubChunk(coordinates.Y);
            }

            bool isTransparent = IsTransparent(coordinates, subChunk);
            byte skyLight      = GetSkyLight(coordinates, subChunk);

            if (down && isTransparent && lightLevel == 15)
            {
                if (IsNotBlockingSkylight(coordinates, chunk))
                {
                    if (skyLight != 15)
                    {
                        SetSkyLight(coordinates, 15, chunk);
                    }

                    if (!lightBfSet.Contains(coordinates))
                    {
                        lightBfsQueue.Enqueue(coordinates);
                        lightBfSet.Add(coordinates);
                    }

                    return(15);
                }
            }

            if (isTransparent)
            {
                int diffuseLevel = GetDiffuseLevel(coordinates, subChunk);
                if (skyLight + 1 + diffuseLevel <= lightLevel)
                {
                    byte newLevel = (byte)(lightLevel - diffuseLevel);
                    SetSkyLight(coordinates, newLevel, chunk);

                    if (!lightBfSet.Contains(coordinates))
                    {
                        lightBfsQueue.Enqueue(coordinates);
                        lightBfSet.Add(coordinates);
                    }

                    return(newLevel);
                }
            }

            return(skyLight);
        }