示例#1
0
        private void GenerateHeightMap(IChunk chunk)
        {
            Coordinates3D coords;
            var           map = new byte[Chunk.Width, Chunk.Depth];

            for (byte x = 0; x < Chunk.Width; x++)
            {
                for (byte z = 0; z < Chunk.Depth; z++)
                {
                    for (byte y = (byte)(chunk.GetHeight(x, z) + 2); y > 0; y--)
                    {
                        if (y >= Chunk.Height)
                        {
                            continue;
                        }
                        coords.X = x; coords.Y = y - 1; coords.Z = z;
                        var id = chunk.GetBlockID(coords);
                        if (id == 0)
                        {
                            continue;
                        }
                        var provider = BlockRepository.GetBlockProvider(id);
                        if (provider.LightOpacity != 0)
                        {
                            map[x, z] = y;
                            break;
                        }
                    }
                }
            }
            HeightMaps[chunk.Coordinates] = map;
        }
示例#2
0
        private void UpdateHeightMap(Coordinates3D coords)
        {
            IChunk chunk;
            var    adjusted = World.FindBlockPosition(coords, out chunk, generate: false);

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

            for (byte y = (byte)(chunk.GetHeight(x, z) + 2); y > 0; y--)
            {
                if (y >= Chunk.Height)
                {
                    continue;
                }
                _.X = x; _.Y = y - 1; _.Z = z;
                var id = chunk.GetBlockID(_);
                if (id == 0)
                {
                    continue;
                }
                var provider = BlockRepository.GetBlockProvider(id);
                if (provider.LightOpacity != 0)
                {
                    map[x, z] = y;
                    break;
                }
            }
        }
示例#3
0
        public void DoSpread(IMultiplayerServer server, IWorld world, BlockDescriptor descriptor)
        {
            foreach (var coord in SpreadableBlocks)
            {
                var check = descriptor.Coordinates + coord;
                if (world.GetBlockID(check) == AirBlock.BlockID)
                {
                    // Check if this is adjacent to a flammable block
                    foreach (var adj in AdjacentBlocks)
                    {
                        var provider = BlockRepository.GetBlockProvider(
                            world.GetBlockID(check + adj));
                        if (provider.Flammable)
                        {
                            if (provider.Hardness == 0)
                            {
                                check = check + adj;
                            }

                            // Spread to this block
                            world.SetBlockID(check, FireBlock.BlockID);
                            ScheduleUpdate(server, world, world.GetBlockData(check));
                            break;
                        }
                    }
                }
            }
        }
示例#4
0
        public void DoUpdate(IMultiPlayerServer server, IWorld world, BlockDescriptor descriptor)
        {
            var down = descriptor.Coordinates + Coordinates3D.Down;

            var current = world.GetBlockId(descriptor.Coordinates);

            if (current != BlockId && current != LavaBlock.BlockId && current != StationaryLavaBlock.BlockId)
            {
                return;
            }

            // Decay
            var meta = world.GetMetadata(descriptor.Coordinates);

            meta++;
            if (meta == 0xE)
            {
                if (!world.IsValidPosition(down) || world.GetBlockId(down) != NetherrackBlock.BlockId)
                {
                    world.SetBlockId(descriptor.Coordinates, AirBlock.BlockId);
                    return;
                }
            }

            world.SetMetadata(descriptor.Coordinates, meta);

            if (meta > 9)
            {
                var pick     = AdjacentBlocks[meta % AdjacentBlocks.Length];
                var provider = BlockRepository
                               .GetBlockProvider(world.GetBlockId(pick + descriptor.Coordinates));
                if (provider.Flammable)
                {
                    world.SetBlockId(pick + descriptor.Coordinates, AirBlock.BlockId);
                }
            }

            // Spread
            DoSpread(server, world, descriptor);

            // Schedule next event
            ScheduleUpdate(server, world, descriptor);
        }
示例#5
0
        private void FlowOutward(IWorld world, LiquidFlow target, IMultiplayerServer server)
        {
            // For each block we can flow into, generate an item entity if appropriate
            var provider = world.BlockRepository.GetBlockProvider(world.GetBlockID(target.TargetBlock));

            provider.GenerateDropEntity(new BlockDescriptor {
                Coordinates = target.TargetBlock, ID = provider.ID
            }, world, server, ItemStack.EmptyStack);
            // And overwrite the block with a new fluid block.
            world.SetBlockID(target.TargetBlock, FlowingID);
            world.SetMetadata(target.TargetBlock, target.Level);
            var chunk = world.FindChunk(target.TargetBlock);

            server.Scheduler.ScheduleEvent("fluid", chunk,
                                           TimeSpan.FromSeconds(SecondsBetweenUpdates),
                                           s => AutomataUpdate(s, world, target.TargetBlock));
            if (FlowingID == LavaBlock.BlockID)
            {
                (BlockRepository.GetBlockProvider(FireBlock.BlockID) as FireBlock).ScheduleUpdate(
                    server, world, world.GetBlockData(target.TargetBlock));
            }
        }
示例#6
0
        /// <summary>
        ///  Propegates a lighting change to an adjacent voxel (if neccesary)
        /// </summary>
        private void PropegateLightEvent(int x, int y, int z, byte value, LightingOperation op)
        {
            var coords = new Coordinates3D(x, y, z);

            if (!World.IsValidPosition(coords))
            {
                return;
            }
            IChunk chunk;
            var    adjustedCoords = World.FindBlockPosition(coords, out chunk, false);

            if (chunk == null || !chunk.TerrainPopulated)
            {
                return;
            }
            var current = op.SkyLight ? World.GetSkyLight(coords) : World.GetBlockLight(coords);

            if (value == current)
            {
                return;
            }
            var provider = BlockRepository.GetBlockProvider(World.GetBlockId(coords));

            if (op.Initial)
            {
                var emissiveness = provider.Luminance;
                if (chunk.GetHeight((byte)adjustedCoords.X, (byte)adjustedCoords.Z) <= y)
                {
                    emissiveness = 15;
                }
                if (emissiveness >= current)
                {
                    return;
                }
            }

            EnqueueOperation(new BoundingBox(new Vector3(x, y, z), new Vector3(x + 1, y + 1, z + 1)), op.SkyLight, op.Initial);
        }
示例#7
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 Coordinates3D(x, y, z);

            IChunk chunk;
            var    adjustedCoords = World.FindBlockPosition(coords, out chunk, generate: false);

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

            var id       = World.GetBlockID(coords);
            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 = Math.Max(provider.LightOpacity, (byte)1);

            byte current = op.SkyLight ? World.GetSkyLight(coords) : World.GetBlockLight(coords);
            byte final   = 0;

            // Calculate emissiveness
            byte emissiveness = provider.Luminance;

            if (op.SkyLight)
            {
                var height = HeightMaps[chunk.Coordinates][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++)
                {
                    if (World.IsValidPosition(coords + Neighbors[i]))
                    {
                        IChunk c;
                        var    adjusted = World.FindBlockPosition(coords + Neighbors[i], out c, generate: false);
                        if (c != null) // We don't want to generate new chunks just to light this voxel
                        {
                            byte val;
                            if (op.SkyLight)
                            {
                                val = c.GetSkyLight(adjusted);
                            }
                            else
                            {
                                val = c.GetBlockLight(adjusted);
                            }
                            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, final);
                }
                else
                {
                    chunk.SetBlockLight(adjustedCoords, final);
                }

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

                // Propegate lighting change to neighboring blocks
                PropegateLightEvent(x - 1, y, z, propegated, op);
                PropegateLightEvent(x, y - 1, z, propegated, op);
                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);
                }
            }
        }
示例#8
0
 public override void BlockMined(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user)
 {
     world.SetBlockId(descriptor.Coordinates, WaterBlock.BlockId);
     BlockRepository.GetBlockProvider(WaterBlock.BlockId).BlockPlaced(descriptor, face, world, user);
 }