예제 #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;
            ChunkSection subChunk   = (ChunkSection)chunk.GetSection(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, ChunkColumn chunk)
        {
            if (chunk == null)
            {
                return(15);
            }

            return(chunk.GetSkylight(blockCoordinates.X & 0x0f, blockCoordinates.Y & 0xff, blockCoordinates.Z & 0x0f));
        }
예제 #3
0
        public static int GetHeight(BlockCoordinates blockCoordinates, ChunkColumn chunk)
        {
            if (chunk == null)
            {
                return(256);
            }

            return(chunk.GetHeight(blockCoordinates.X & 0x0f, blockCoordinates.Z & 0x0f));
        }
예제 #4
0
        public int GetHeight(BlockCoordinates coordinates)
        {
            ChunkColumn chunk = GetChunk(coordinates, true);

            if (chunk == null)
            {
                return(_heightForUnloadedChunk);
            }

            return(chunk.GetHeight(coordinates.X & 0x0f, coordinates.Z & 0x0f));
        }
예제 #5
0
        public static bool IsNotBlockingSkylight(BlockCoordinates blockCoordinates, ChunkColumn chunk)
        {
            if (chunk == null)
            {
                return(true);
            }

            var b = chunk.GetBlockState(blockCoordinates.X & 0x0f, blockCoordinates.Y & 0xff, blockCoordinates.Z & 0x0f).Block;

            return(b is Air || !b.BlockMaterial.BlocksLight());           // (b.Transparent && !(b is Leaves));
            //	int bid = chunk.GetBlockId(blockCoordinates.X & 0x0f, blockCoordinates.Y & 0xff, blockCoordinates.Z & 0x0f);
            //	return bid == 0 || (BlockFactory.TransparentBlocks[bid] == 1 && bid != 18 && bid != 161 && bid != 30 && bid != 8 && bid != 9);
        }
예제 #6
0
        public static byte GetSkyLight(BlockCoordinates blockCoordinates, ChunkSection 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));
        }
예제 #7
0
        private void MakeVisit(BlockCoordinates inc)
        {
            BlockCoordinates coordinates = new BlockCoordinates(inc.X, 0, inc.Z);

            if (Visits.ContainsKey(coordinates))
            {
                Visits[coordinates] = Visits[coordinates] + 1;
            }
            else
            {
                Visits.TryAdd(coordinates, 1);
            }
        }
예제 #8
0
        private static int GetHeighestSurrounding(int x, int z, ChunkColumn chunk, IBlockAccess level)
        {
            int h = chunk.GetHeight(x, z);

            if (h == 255)
            {
                return(h);
            }

            if (x == 0 || x == 15 || z == 0 || z == 15)
            {
                var coords = new BlockCoordinates(x + (chunk.X * 16), h, z + (chunk.Z * 16));

                //h = Math.Max(h, level.GetHeight(coords + BlockCoordinates.Up));
                h = Math.Max(h, level.GetHeight(coords + BlockCoordinates.West));
                h = Math.Max(h, level.GetHeight(coords + BlockCoordinates.East));
                h = Math.Max(h, level.GetHeight(coords + BlockCoordinates.North));
                h = Math.Max(h, level.GetHeight(coords + BlockCoordinates.South));
                if (h > 255)
                {
                    h = 255;
                }
                if (h < 0)
                {
                    h = 0;
                }
                return(h);
            }

            //if (z < 15) h = Math.Max(h, chunk.GetHeight(x, z + 1));
            //if (z > 0) h = Math.Max(h, chunk.GetHeight(x, z - 1));
            //if (x < 15) h = Math.Max(h, chunk.GetHeight(x + 1, z));
            //if (x < 15 && z > 0) h = Math.Max(h, chunk.GetHeight(x + 1, z - 1));
            //if (x < 15 && z < 15) h = Math.Max(h, chunk.GetHeight(x + 1, z + 1));
            //if (x > 0) h = Math.Max(h, chunk.GetHeight(x - 1, z));
            //if (x > 0 && z > 0) h = Math.Max(h, chunk.GetHeight(x - 1, z - 1));
            //if (x > 0 && z < 15) h = Math.Max(h, chunk.GetHeight(x - 1, z + 1));

            h = Math.Max(h, chunk.GetHeight(x, z + 1));
            h = Math.Max(h, chunk.GetHeight(x, z - 1));
            h = Math.Max(h, chunk.GetHeight(x + 1, z));
            //h = Math.Max(h, chunk.GetHeight(x + 1, z - 1));
            //h = Math.Max(h, chunk.GetHeight(x + 1, z + 1));
            h = Math.Max(h, chunk.GetHeight(x - 1, z));
            //h = Math.Max(h, chunk.GetHeight(x - 1, z - 1));
            //h = Math.Max(h, chunk.GetHeight(x - 1, z + 1));

            return(h);
        }
예제 #9
0
        private static bool IsTransparent(BlockCoordinates blockCoordinates, ChunkSection section)
        {
            if (section == null)
            {
                return(true);
            }

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

            var state = section.Get(bx, by - 16 * (by >> 4), bz);

            return(state.Block is Air || state.Block.Transparent);
            //	return bid == 0 || BlockFactory.TransparentBlocks[bid] == 1;
        }
예제 #10
0
        public static int GetDiffuseLevel(BlockCoordinates blockCoordinates, ChunkSection 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;

            var state = section.Get(bx, by - 16 * (by >> 4), bz);

            return(state.Block.LightOpacity);
            //return bid == 8 || bid == 9 ? 3 : bid == 18 || bid == 161 || bid == 30 ? 2 : 1;
        }
예제 #11
0
        public bool RecalcSkyLight(ChunkColumn chunk, IBlockAccess level)
        {
            if (chunk == null)
            {
                return(false);
            }

            var lightBfQueue = new Queue <BlockCoordinates>();
            var lightBfSet   = new HashSet <BlockCoordinates>();

            for (int x = 0; x < 16; x++)
            {
                for (int z = 0; z < 16; z++)
                {
                    if (!IsOnChunkBorder(x, z))
                    {
                        continue;
                    }

                    int height = GetHeighestSurrounding(x, z, chunk, level);
                    if (height == 0)
                    {
                        continue;
                    }

                    //var skyLight = chunk.GetSkylight(x, height, z);
                    //if (skyLight == 15)
                    {
                        //Block block = level.GetBlockId(new BlockCoordinates(x + (chunk.x*16), height, z + (chunk.z*16)), chunk);
                        //Calculate(level, block);
                        //Calculate(level, new BlockCoordinates(x + (chunk.x*16), height, z + (chunk.z*16)), lightBfQueue);
                        var coordinates = new BlockCoordinates(x + (chunk.X * 16), height, z + (chunk.Z * 16));
                        lightBfQueue.Enqueue(coordinates);
                        lightBfSet.Add(coordinates);
                    }
                    //else
                    //{
                    //	Log.Error($"Block with wrong light level. Expected 15 but was {skyLight}");
                    //}
                }
            }

            Calculate(level, lightBfQueue, lightBfSet);

            return(true);
        }
예제 #12
0
        public void Calculate(World level, BlockCoordinates coordinates)
        {
            int currentLight = level.GetSkyLight(coordinates);

            var         cc     = new ChunkCoordinates(coordinates);
            ChunkColumn chunk  = (ChunkColumn)level.GetChunkColumn(cc.X, cc.Z);
            var         height = chunk.GetRecalculatedHeight(coordinates.X & 0x0f, coordinates.Z & 0x0f);

            Queue <BlockCoordinates> sourceQueue = new Queue <BlockCoordinates>();

            sourceQueue.Enqueue(coordinates);
            if (currentLight != 0)
            {
                Queue <BlockCoordinates>   resetQueue = new Queue <BlockCoordinates>();
                HashSet <BlockCoordinates> visits     = new HashSet <BlockCoordinates>();

                // Reset all lights that potentially derive from this
                resetQueue.Enqueue(coordinates);

                Queue <BlockCoordinates> deleteQueue = new Queue <BlockCoordinates>();
                while (resetQueue.Count > 0)
                {
                    var coord = resetQueue.Dequeue();
                    if (visits.Contains(coord))
                    {
                        continue;
                    }

                    visits.Add(coord);

                    if (coord.DistanceTo(coordinates) > 16)
                    {
                        continue;
                    }

                    ResetLight(level, resetQueue, sourceQueue, coord);
                    if (!sourceQueue.Contains(coord))
                    {
                        deleteQueue.Enqueue(coord);
                    }
                }

                level.SetSkyLight(coordinates, 0);

                foreach (var delete in deleteQueue)
                {
                    level.SetSkyLight(delete, 0);
                }
            }
            else
            {
                sourceQueue.Enqueue(coordinates);
                sourceQueue.Enqueue(coordinates.BlockUp());
                sourceQueue.Enqueue(coordinates.BlockDown());
                sourceQueue.Enqueue(coordinates.BlockWest());
                sourceQueue.Enqueue(coordinates.BlockEast());
                sourceQueue.Enqueue(coordinates.BlockNorth());
                sourceQueue.Enqueue(coordinates.BlockSouth());
            }

            chunk.SetHeight(coordinates.X & 0x0f, coordinates.Z & 0x0f, (short)height);

            // Recalc
            Queue <BlockCoordinates>   lightBfQueue = new Queue <BlockCoordinates>(sourceQueue);
            HashSet <BlockCoordinates> lightBfSet   = new HashSet <BlockCoordinates>(sourceQueue);

            SkyLightBlockAccess blockAccess = new SkyLightBlockAccess(level.ChunkManager);

            Calculate(blockAccess, lightBfQueue, lightBfSet);
        }
예제 #13
0
 public Block GetBlock(BlockCoordinates coord, ChunkColumn tryChunk = null)
 {
     return(null);
 }
예제 #14
0
 public ChunkColumn GetChunk(BlockCoordinates coordinates, bool cacheOnly = false)
 {
     return(GetChunk((ChunkCoordinates)coordinates, cacheOnly));
 }
예제 #15
0
        public void SetSkyLight(BlockCoordinates coordinates, byte skyLight)
        {
            ChunkColumn chunk = GetChunk(coordinates, true);

            chunk?.SetSkyLight(coordinates.X & 0x0f, coordinates.Y & 0xff, coordinates.Z & 0x0f, skyLight);
        }
예제 #16
0
 public static void SetSkyLight(BlockCoordinates coordinates, byte skyLight, ChunkColumn chunk)
 {
     chunk?.SetSkyLight(coordinates.X & 0x0f, coordinates.Y & 0xff, coordinates.Z & 0x0f, skyLight);
 }
예제 #17
0
        private byte SetLightLevel(IBlockAccess level, ChunkColumn chunk, ChunkSection 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);
            }

            var chunkCoords = (ChunkCoordinates)coordinates;

            if (!(up || down) && (chunk.X != coordinates.X >> 4 || chunk.Z != coordinates.Z >> 4))
            {
                chunk    = (ChunkColumn)level.GetChunk(chunkCoords);
                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 = (ChunkSection)chunk.Sections[coordinates.Y >> 4];
            }

            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);
        }
예제 #18
0
 private static void SetSkyLight(IBlockAccess world, BlockCoordinates coordinates, byte skyLight)
 {
     world?.SetSkyLight(coordinates, skyLight);
     //chunk?.SetSkyLight(coordinates.X & 0x0f, coordinates.Y & 0xff, coordinates.Z & 0x0f, skyLight);
 }
예제 #19
0
        private void TestForSource(World level, Queue <BlockCoordinates> resetQueue, Queue <BlockCoordinates> sourceQueue, BlockCoordinates coordinates, int currentLight, bool down = false)
        {
            int light = level.GetSkyLight(coordinates);

            if (light == 0)
            {
                return;
            }

            if (light > currentLight || (light == 15 && !down))
            {
                if (!sourceQueue.Contains(coordinates))
                {
                    sourceQueue.Enqueue(coordinates);
                }
                return;
            }

            if (!resetQueue.Contains(coordinates))
            {
                resetQueue.Enqueue(coordinates);
            }
        }
예제 #20
0
 public byte GetBlockLight(BlockCoordinates coordinates)
 {
     return(0);
 }
예제 #21
0
 private static void SetSkyLight(IBlockAccess world, BlockCoordinates coordinates, byte skyLight, ChunkColumn chunk)
 {
     chunk?.SetSkyLight(coordinates.X & 0x0f, coordinates.Y & 0xff, coordinates.Z & 0x0f, skyLight);
 }
예제 #22
0
        public void ResetLight(World level, Queue <BlockCoordinates> resetQueue, Queue <BlockCoordinates> sourceQueue, BlockCoordinates coordinates)
        {
            int currentLight = level.GetSkyLight(coordinates);

            if (coordinates.Y < 255)
            {
                TestForSource(level, resetQueue, sourceQueue, coordinates.BlockUp(), currentLight);
            }
            if (coordinates.Y > 0)
            {
                TestForSource(level, resetQueue, sourceQueue, coordinates.BlockDown(), currentLight, true);
            }
            TestForSource(level, resetQueue, sourceQueue, coordinates.BlockWest(), currentLight);
            TestForSource(level, resetQueue, sourceQueue, coordinates.BlockEast(), currentLight);
            TestForSource(level, resetQueue, sourceQueue, coordinates.BlockNorth(), currentLight);
            TestForSource(level, resetQueue, sourceQueue, coordinates.BlockSouth(), currentLight);
        }
예제 #23
0
 public byte GetSkyLight(BlockCoordinates coordinates)
 {
     return(15);
 }