Example #1
0
        public int CalculateSkyLights(IBlockAccess level, ChunkColumn[] chunks)
        {
            int       calcCount = 0;
            Stopwatch calcTime  = new Stopwatch();
            int       lastCount = 0;

            foreach (var chunk in chunks)
            {
                if (!_visitedColumns.TryAdd(chunk, true))
                {
                    continue;
                }

                //if (chunk.IsAllAir) continue;

                calcTime.Restart();
                if (RecalcSkyLight(chunk, level))
                {
                    //calcCount++;

                    //var elapsedMilliseconds = calcTime.ElapsedMilliseconds;
                    //var c = Visits.Sum(pair => pair.Value);
                    //if (elapsedMilliseconds > 0) Log.Debug($"Recalc skylight chunk {chunk.x}, {chunk.z}, count #{calcCount} (air={chunk.isAllAir}) chunks. Time {elapsedMilliseconds}ms and {c - lastCount} visits");
                    //lastCount = c;
                    //PrintVisits();
                }
            }

            //Log.Debug($"Recalc skylight for #{calcCount} chunk. Made {lastCount} visits.");

            return(calcCount);
        }
Example #2
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);
                    }
                }
            }
        }
Example #3
0
        public void Calculate(IBlockAccess level, Queue <BlockCoordinates> lightBfQueue, HashSet <BlockCoordinates> lightBfSet)
        {
            try
            {
                //if (block.SkyLight != 15)
                //{
                //	Log.Error($"Block at {block.Coordinates} had unexpected light level. Expected 15 but was {block.SkyLight}");
                //}

                while (lightBfQueue.Count > 0)
                {
                    var coordinates = lightBfQueue.Dequeue();
                    lightBfSet.Remove(coordinates);
                    if (coordinates.Y < 0 || coordinates.Y > 255)
                    {
                        if (DoLogging)
                        {
                            Log.Warn($"Y coord out of bounce {coordinates.Y}");
                        }
                        continue;
                    }

                    ChunkColumn chunk = level.GetChunk(coordinates);
                    if (chunk == null)
                    {
                        if (DoLogging)
                        {
                            Log.Warn($"Chunk was null");
                        }
                        continue;
                    }

                    var newChunkCoord = (ChunkCoordinates)coordinates;
                    if (chunk.X != newChunkCoord.X || chunk.Z != newChunkCoord.Z)
                    {
                        chunk = (ChunkColumn)level.GetChunk(newChunkCoord);
                        if (chunk == null)
                        {
                            if (DoLogging)
                            {
                                Log.Warn($"Chunk with new coords was null");
                            }
                            continue;
                        }
                    }

                    ProcessNode(level, chunk, coordinates, lightBfQueue, lightBfSet);
                }
            }
            catch (Exception e)
            {
                Log.Error("Calculation", e);
            }
        }
Example #4
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);
        }
Example #5
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);
        }
Example #6
0
        private void ResetLight(IBlockAccess 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);
        }
Example #7
0
        private void TestForSource(IBlockAccess 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);
            }
        }
Example #8
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);
        }
Example #9
0
        public void Calculate(IBlockAccess level, BlockCoordinates coordinates)
        {
            int currentLight = level.GetSkyLight(coordinates);

            var         cc     = new ChunkCoordinates(coordinates);
            ChunkColumn chunk  = (ChunkColumn)level.GetChunk(cc);
            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(level, lightBfQueue, lightBfSet);
        }
Example #10
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);
 }
Example #11
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);
 }