Exemple #1
0
        public void UpdateHeightMap(BlockCoordinates coords)
        {
            IChunkColumn chunk;
            var          adjusted = World.FindBlockPosition(coords, out chunk);

            if (chunk == null)
            {
                return;
            }
            var chunkPos = new ChunkCoordinates(chunk.X, chunk.Z);

            if (!HeightMaps.ContainsKey(chunkPos))
            {
                return;
            }
            var              map = HeightMaps[chunkPos];
            byte             x = (byte)adjusted.X; byte z = (byte)adjusted.Z;
            BlockCoordinates _;

            for (byte y = (byte)(chunk.GetHeight(x, z) + 2); y > 0; y--)
            {
                if (y >= 255)
                {
                    continue;
                }
                _.X = x; _.Y = y - 1; _.Z = z;
                var provider = chunk.GetBlockState(_.X, _.Y, _.Z).Block;

                if (!provider.Renderable)
                {
                    continue;
                }
                if (provider.LightOpacity != 0)
                {
                    map[x, z] = y;
                    break;
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Computes the correct lighting value for a given voxel.
        /// </summary>
        private void LightVoxel(int x, int y, int z, LightingOperation op)
        {
            var coords = new BlockCoordinates(x, y, z);

            IChunkColumn chunk;
            var          adjustedCoords = World.FindBlockPosition(coords, out chunk);

            if (chunk == null) // Move on if this chunk is empty
            {
                return;
            }

            var provider = chunk.GetBlockState(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z).Block;
            // var provider = BlockRepository.GetBlockProvider(id);

            // The opacity of the block determines the amount of light it receives from
            // neighboring blocks. This is subtracted from the max of the neighboring
            // block values. We must subtract at least 1.
            byte opacity = (byte)Math.Max(provider.LightOpacity, (byte)1);

            byte current = op.SkyLight ? chunk.GetSkylight(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z) : chunk.GetBlocklight(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z);
            byte final   = 0;

            // Calculate emissiveness
            byte emissiveness = (byte)provider.LightValue;

            if (op.SkyLight)
            {
                var chunkPos = new ChunkCoordinates(chunk.X, chunk.Z);
                byte[,] map;
                if (!HeightMaps.TryGetValue(chunkPos, out map))
                {
                    GenerateHeightMap(chunk);
                    map = HeightMaps[chunkPos];
                }
                // var height = chunk.GetHeight(adjustedCoords.X, adjustedCoords.Z);
                var height = map[adjustedCoords.X, adjustedCoords.Z];
                // For skylight, the emissiveness is 15 if y >= height
                if (y >= height)
                {
                    emissiveness = 15;
                }
                else
                {
                    if (provider.LightOpacity >= 15)
                    {
                        emissiveness = 0;
                    }
                }
            }

            if (opacity < 15 || emissiveness != 0)
            {
                // Compute the light based on the max of the neighbors
                byte max = 0;
                for (int i = 0; i < Neighbors.Length; i++)
                {
                    IChunkColumn c;
                    var          adjusted = World.FindBlockPosition(coords + Neighbors[i], out c);
                    //var n = coords + Neighbors[i];
                    //  if (World.HasBlock(n.X, n.Y, n.Z))
                    if (c != null)
                    {
                        byte val;
                        if (op.SkyLight)
                        {
                            val = c.GetSkylight(adjusted.X, adjusted.Y, adjusted.Z);
                        }
                        else
                        {
                            val = c.GetBlocklight(adjusted.X, adjusted.Y, adjusted.Z);
                        }
                        max = Math.Max(max, val);
                    }
                }
                // final = MAX(max - opacity, emissiveness, 0)
                final = (byte)Math.Max(max - opacity, emissiveness);
                if (final < 0)
                {
                    final = 0;
                }
            }

            if (final != current)
            {
                // Apply changes
                if (op.SkyLight)
                {
                    chunk.SetSkyLight(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z, final);
                }
                else
                {
                    chunk.SetBlocklight(adjustedCoords.X, adjustedCoords.Y, adjustedCoords.Z, final);
                }

                byte propegated = (byte)Math.Max(final - 1, 0);

                // Propegate lighting change to neighboring blocks
                if (x - 1 <= op.Box.Min.X)
                {
                    PropegateLightEvent(x - 1, y, z, propegated, op);
                }
                if (y - 1 <= op.Box.Min.Y)
                {
                    PropegateLightEvent(x, y - 1, z, propegated, op);
                }
                if (z - 1 <= op.Box.Min.Z)
                {
                    PropegateLightEvent(x, y, z - 1, propegated, op);
                }

                if (x + 1 >= op.Box.Max.X)
                {
                    PropegateLightEvent(x + 1, y, z, propegated, op);
                }
                if (y + 1 >= op.Box.Max.Y)
                {
                    PropegateLightEvent(x, y + 1, z, propegated, op);
                }
                if (z + 1 >= op.Box.Max.Z)
                {
                    PropegateLightEvent(x, y, z + 1, propegated, op);
                }
            }
        }