Example #1
0
    public void ApplyBlock(BlockType b, BlockCoord coord)
    {
        int x = coord.x;
        int y = coord.y;
        int z = coord.z;

        switch (b)
        {
        case BlockType.BRICK_X_AXIS:
            this.blocks[x][y][z].type     = BlockType.BRICK_X_AXIS;
            this.blocks[x + 1][y][z].type = BlockType.BRICK_EXT;
            break;

        case BlockType.BRICK_Y_AXIS:
            this.blocks[x][y][z].type     = BlockType.BRICK_Y_AXIS;
            this.blocks[x][y + 1][z].type = BlockType.BRICK_EXT;
            break;

        case BlockType.BRICK_Z_AXIS:
            this.blocks[x][y][z].type     = BlockType.BRICK_Z_AXIS;
            this.blocks[x][y][z + 1].type = BlockType.BRICK_EXT;
            break;

        case BlockType.EMPTY:
            this.DestroyBlock(new BlockCoord(x, y, z));
            break;

        default:
            break;
        }
    }
Example #2
0
    public bool BlockIsSupported(BlockType b, BlockCoord coord)
    {
        coord = this.FindSourceCoord(coord);
        int x = coord.x;
        int y = coord.y;
        int z = coord.z;

        // On the ground
        if (y == 0)
        {
            return(true);
        }
        // Central block could be supported
        if (this.blocks[x][y - 1][z].type != BlockType.EMPTY)
        {
            return(true);
        }
        // Each special shape
        switch (b)
        {
        case BlockType.BRICK_X_AXIS:
            return(this.blocks[x + 1][y - 1][z].type != BlockType.EMPTY);

        case BlockType.BRICK_Z_AXIS:
            return(this.blocks[x][y - 1][z + 1].type != BlockType.EMPTY);

        default:
            return(false);
        }
    }
Example #3
0
    public void SpawnItemAt(ref List <BlockCoord> selectedBlockCoords)
    {
        if (DoesItemSpawn() == false)
        {
            return;
        }

        int        lastBlock      = selectedBlockCoords.Count - 1;
        BlockCoord itemBlockCoord = selectedBlockCoords[lastBlock];

        Block block = hexGrid.GetBlockAt(itemBlockCoord);

        if (matchCount >= CircularBlockThreshold)
        {
            block.SetBlockType(BlockType.Item_Circular);
        }

        else if (matchCount >= DiagonalBlockThreshold)
        {
            block.SetBlockType(BlockType.Item_Diagonal);
        }

        else if (matchCount >= VerticalBlockThreshold)
        {
            block.SetBlockType(BlockType.Item_Vertical);
        }

        selectedBlockCoords.RemoveAt(lastBlock);
    }
Example #4
0
 public bool IsValidPlacement(BlockType b, BlockCoord coord)
 {
     if (new Block(b).IsValidCoord(this, coord))
     {
         return(BlockIsSupported(b, coord));
     }
     return(false);
 }
Example #5
0
        /// <summary>
        /// Unmarks a previously marked chunk coordinate to be ticked when this chunk is loaded.
        /// </summary>
        public void UnmarkForTickUpdate(int x, int y, int z)
        {
            var coord = new BlockCoord(x, y, z);

            if (blockTicks.Contains(coord))
            {
                blockTicks.Remove(coord);
            }
        }
Example #6
0
    public bool BlockIsSupported2(BlockType b, BlockCoord coord)
    {
        coord = this.FindSourceCoord(coord);
        int x = coord.x;
        int y = coord.y;
        int z = coord.z;

        // On the ground
        if (y == 0)
        {
            return(true);
        }

        bool main_strong = false;
        bool ext_strong  = false;
        bool main_weak   = false;
        bool ext_weak    = false;
        bool ext_top     = false;
        bool main_top    = false;

        // Central block could be supported
        if (this.SpaceIsFilled(x, y - 1, z))
        {
            main_strong = true;
            main_top    = this.SpaceIsFilled(x, y + 1, z);
        }
        // Each special shape
        switch (b)
        {
        case BlockType.BRICK_X_AXIS:
            ext_strong = this.SpaceIsFilled(x + 1, y - 1, z);
            ext_weak  |= this.SpaceIsFilled(x + 2, y, z);
            main_weak |= this.SpaceIsFilled(x - 1, y, z);
            ext_top    = this.SpaceIsFilled(x + 1, y + 1, z);
            break;

        case BlockType.BRICK_Z_AXIS:
            ext_strong = this.SpaceIsFilled(x, y - 1, z + 1);
            ext_weak  |= this.SpaceIsFilled(x, y, z + 2);
            main_weak |= this.SpaceIsFilled(x, y, z - 1);
            ext_top    = this.SpaceIsFilled(x, y + 1, z + 1);
            break;

        case BlockType.BRICK_Y_AXIS:
            main_top = true;
            break;

        default:
            ext_strong = false;
            ext_weak   = false;
            main_weak  = false;
            break;
        }
        return((main_strong && ext_strong) ||
               (main_strong && ext_weak) || (ext_strong && main_weak) ||
               (main_strong && main_top) || (ext_strong && ext_top));
    }
Example #7
0
        /// <summary>
        /// Marks the given chunk coordinate to be ticked when this chunk is loaded.
        /// </summary>
        public void MarkForTickUpdate(int x, int y, int z)
        {
            var coord = new BlockCoord(x, y, z);

            if (!blockTicks.Contains(coord))
            {
                blockTicks.Add(coord);
            }
        }
Example #8
0
    // TODO: CLEAN
    public void DestroyBlock(BlockCoord pos)
    {
        BlockCoord coord = this.FindSourceCoord(pos);
        int        x     = coord.x;
        int        y     = coord.y;
        int        z     = coord.z;

        switch (this.blocks[x][y][z].type)
        {
        case BlockType.BRICK_X_AXIS:
            this.blocks[x][y][z].type     = BlockType.EMPTY;
            this.blocks[x + 1][y][z].type = BlockType.EMPTY;
            if (y + 1 < this.blocks[0].Length &&
                !this.BlockIsSupported(new BlockCoord(x, y + 1, z)))
            {
                this.DestroyBlock(new BlockCoord(x, y + 1, z));
            }
            if (y + 1 < this.blocks[0].Length &&
                !this.BlockIsSupported(new BlockCoord(x + 1, y + 1, z)))
            {
                this.DestroyBlock(new BlockCoord(x + 1, y + 1, z));
            }
            break;

        case BlockType.BRICK_Y_AXIS:
            this.blocks[x][y][z].type     = BlockType.EMPTY;
            this.blocks[x][y + 1][z].type = BlockType.EMPTY;
            if (y + 2 < this.blocks[0].Length &&
                !this.BlockIsSupported(new BlockCoord(x, y + 2, z)))
            {
                this.DestroyBlock(new BlockCoord(x, y + 2, z));
            }
            break;

        case BlockType.BRICK_Z_AXIS:
            this.blocks[x][y][z].type     = BlockType.EMPTY;
            this.blocks[x][y][z + 1].type = BlockType.EMPTY;
            if (y + 1 < this.blocks[0].Length &&
                !this.BlockIsSupported(new BlockCoord(x, y + 1, z)))
            {
                this.DestroyBlock(new BlockCoord(x, y + 1, z));
            }
            if (y + 1 < this.blocks[0].Length &&
                !this.BlockIsSupported(new BlockCoord(x, y + 1, z + 1)))
            {
                this.DestroyBlock(new BlockCoord(x, y + 1, z + 1));
            }
            break;

        default:
            break;
        }
    }
    public void SetAffectedBlocks()
    {
        var currentBlockNeighbors = baseBehaviour.neighborGrid.Coordinates[currentBlock.Coord.X, currentBlock.Coord.Y];

        BlockCoord topLeft     = currentBlockNeighbors[(byte)BlockDirection.TopLeft];
        BlockCoord topRight    = currentBlockNeighbors[(byte)BlockDirection.TopRight];
        BlockCoord bottomLeft  = currentBlockNeighbors[(byte)BlockDirection.BottomLeft];
        BlockCoord bottomRight = currentBlockNeighbors[(byte)BlockDirection.BottomRight];

        while (topLeft.IsValid)
        {
            if (baseBehaviour.hexGrid.GetBlockAt(topLeft).IsItem() == false)
            {
                baseBehaviour.selectedBlockSet.CoordList.Add(topLeft);
            }

            topLeft = baseBehaviour.neighborGrid.Coordinates[topLeft.X, topLeft.Y][(byte)BlockDirection.TopLeft];
        }

        while (topRight.IsValid)
        {
            if (baseBehaviour.hexGrid.GetBlockAt(topRight).IsItem() == false)
            {
                baseBehaviour.selectedBlockSet.CoordList.Add(topRight);
            }

            topRight = baseBehaviour.neighborGrid.Coordinates[topRight.X, topRight.Y][(byte)BlockDirection.TopRight];
        }

        while (bottomLeft.IsValid)
        {
            if (baseBehaviour.hexGrid.GetBlockAt(bottomLeft).IsItem() == false)
            {
                baseBehaviour.selectedBlockSet.CoordList.Add(bottomLeft);
            }

            bottomLeft = baseBehaviour.neighborGrid.Coordinates[bottomLeft.X, bottomLeft.Y][(byte)BlockDirection.BottomLeft];
        }

        while (bottomRight.IsValid)
        {
            if (baseBehaviour.hexGrid.GetBlockAt(bottomRight).IsItem() == false)
            {
                baseBehaviour.selectedBlockSet.CoordList.Add(bottomRight);
            }

            bottomRight = baseBehaviour.neighborGrid.Coordinates[bottomRight.X, bottomRight.Y][(byte)BlockDirection.BottomRight];
        }

        baseBehaviour.selectedBlockSet.CoordList.Add(currentBlock.Coord);
    }
 private bool BlockIsOpaque(int x, int y, int z)
 {
     if (x < 0 || y < 0 || z < 0 || x >= Chunk.size || y >= Chunk.size || z >= Chunk.size)
     {
         var bc = new BlockCoord(x, y, z);
         var c  = manager.Get(chunk.coord + bc.ChunkCoord);
         if (c == null)
         {
             Debug.LogError("ChunkMeshGenerator is missing surrounding chunks " + x + " " + y + " " + z + " -> " + bc.ChunkCoord);
         }
         return(Block.Get(c.GetBlock(bc.LocalCoord)).isOpaque);
     }
     return(Block.Get(chunk.GetBlock(x, y, z)).isOpaque);
 }
 public void SetRequestRegion(BlockCoord min, BlockCoord max)
 {
     lock (blockRequest)
     {
         RequestRegionMin   = min;
         RequestRegionMax   = max;
         blockRequest.min_x = min.x;
         blockRequest.min_y = min.y;
         blockRequest.min_z = min.z;
         blockRequest.max_x = max.x;
         blockRequest.max_y = max.y;
         blockRequest.max_z = max.z;
     }
 }
Example #12
0
    private void AnimateForegroundFX(BlockCoord blockCoord)
    {
        if (tweeners[blockCoord.X, blockCoord.Y] == null)
        {
            tweeners[blockCoord.X, blockCoord.Y] =
                DOTween.To(() => fxGrid.ForegroundFXs[blockCoord.X, blockCoord.Y].localScale,
                           x => fxGrid.ForegroundFXs[blockCoord.X, blockCoord.Y].localScale = x,
                           Vector3.one,
                           .15f);
        }

        tweeners[blockCoord.X, blockCoord.Y].Restart();

        selectedBlockCoords.Push(blockCoord);
    }
Example #13
0
    public Chunk Generate(Vector3Int coord)
    {
        //Let's start with height map based generation
        Chunk chunk = new Chunk(coord);

        // Go over X and Z
        for (int i = 0; i < Chunk.size; ++i)
        {
            for (int j = 0; j < Chunk.size; ++j)
            {
                var elevation   = ElevationAt(coord, i, j);
                var localHeight = Math.Min(Chunk.size, elevation - coord.y * Chunk.size);
                var grassOnTop  = elevation - coord.y * Chunk.size <= Chunk.size;

                for (int k = 0; k < localHeight; ++k)
                {
                    if (Noise3d(holeNoiseScale * (i + coord.x * Chunk.size), holeNoiseScale * (k + coord.y * Chunk.size), holeNoiseScale * (j + coord.z * Chunk.size)) > holeBias)
                    {
                        if (grassOnTop && k + 1 == localHeight)
                        {
                            var bcoord = new BlockCoord();
                            bcoord.ChunkCoord = coord;
                            bcoord.LocalCoord = new Vector3Int(i, k, j);
                            var randomization = noiseGenerator.Noise3dInterpolated(i, j, k) * snowBiasRandomization;
                            if (elevation >= snowBias + randomization)
                            {
                                chunk.SetBlock(i, k, j, (byte)Block.Type.Snow);
                            }
                            else
                            {
                                chunk.SetBlock(i, k, j, (byte)Block.Type.Grass);
                            }
                        }
                        else if (grassOnTop && k + 3 >= localHeight)
                        {
                            chunk.SetBlock(i, k, j, (byte)Block.Type.Dirt);
                        }
                        else
                        {
                            chunk.SetBlock(i, k, j, (byte)Block.Type.Stone);
                        }
                    }
                }
            }
        }

        return(chunk);
    }
Example #14
0
        ///<summary>Gets the tile entity for the block at the given chunk coordinate (if available).</summary>
        public TileEntity GetTileEntity(int x, int y, int z)
        {
            if (tileEntities == null)
            {
                return(null);
            }
            var c = new BlockCoord(x, y, z);

            if (tileEntities.ContainsKey(c))
            {
                return(tileEntities[c]);
            }
            else
            {
                return(null);
            }
        }
Example #15
0
    private void DeleteRandomBlock()
    {
        for (int i = 0; i < MAX_MUTATE_SEARCH_ITERS; i++)
        {
            int        x     = rng.Next(0, this.blocks.Length);
            int        y     = rng.Next(0, this.blocks[0].Length);
            int        z     = rng.Next(0, this.blocks[0][0].Length);
            BlockCoord coord = new BlockCoord(x, y, z);
            coord = this.FindSourceCoord(coord);
            x     = coord.x;
            y     = coord.y;
            z     = coord.z;

            if (this.blocks[x][y][z].type != BlockType.EMPTY)
            {
                this.DestroyBlock(coord);
                break;
            }
        }
    }
Example #16
0
    public BlockCoord FindSourceCoord(BlockCoord coord)
    {
        BlockCoord new_coord = new BlockCoord(coord);

        if (blocks[coord.x][coord.y][coord.z].type == BlockType.BRICK_EXT)
        {
            if (coord.x > 0 && this.blocks[coord.x - 1][coord.y][coord.z].type == BlockType.BRICK_X_AXIS)
            {
                new_coord.x--;
            }
            else if (coord.y > 0 && this.blocks[coord.x][coord.y - 1][coord.z].type == BlockType.BRICK_Y_AXIS)
            {
                new_coord.y--;
            }
            else if (coord.z > 0)
            {
                new_coord.z--;
            }
        }
        return(new_coord);
    }
Example #17
0
    // TODO: CLEAN
    public BlockType FindValidBlock(BlockCoord coord)
    {
        int x = coord.x;
        int y = coord.y;
        int z = coord.z;
        List <BlockType> possible = new List <BlockType>();

        possible.Add(BlockType.EMPTY);
        // TODO: move this logic into the block class and iterate through all blocks
        if (this.blocks[x][y][z].type != BlockType.EMPTY)
        {
            return(this.blocks[x][y][z].type);
        }
        foreach (BlockType b in System.Enum.GetValues(typeof(BlockType)).Cast <BlockType>())
        {
            if (this.IsValidPlacement(b, coord))
            {
                possible.Add(b);
            }
        }
        return(possible[rng.Next(0, possible.Count)]);
    }
Example #18
0
    // Checks if a block is inside bounds and is not intersecting any other blocks.
    public bool IsValidCoord(Blueprint blueprint, BlockCoord coord)
    {
        int x = coord.x;
        int y = coord.y;
        int z = coord.z;

        switch (this.type)
        {
        case BlockType.EMPTY:
            return(true);

        // ------ Basic Bricks -------
        case BlockType.BRICK_X_AXIS:
            return
                // Bounds check
                (x + 1 < blueprint.blocks.Length &&
                 // Empty space to the left
                 blueprint.blocks[x + 1][y][z].type == BlockType.EMPTY);

        case BlockType.BRICK_Z_AXIS:
            return
                // Bounds check
                (z + 1 < blueprint.blocks[0][0].Length &&
                 // Empty space to the left
                 blueprint.blocks[x][y][z + 1].type == BlockType.EMPTY);

        case BlockType.BRICK_Y_AXIS:
            return
                // Bounds check
                (y + 1 < blueprint.blocks[0].Length &&
                 // Empty space up
                 blueprint.blocks[x][y + 1][z].type == BlockType.EMPTY);

        default:
            return(false);
        }
    }
Example #19
0
    // Different Private Mutation Functions
    private void AddRandomBlock()
    {
        for (int i = 0; i < MAX_MUTATE_SEARCH_ITERS; i++)
        {
            int        x     = rng.Next(0, this.blocks.Length);
            int        y     = rng.Next(0, this.blocks[0].Length);
            int        z     = rng.Next(0, this.blocks[0][0].Length);
            BlockCoord coord = new BlockCoord(x, y, z);
            coord = this.FindSourceCoord(coord);
            x     = coord.x;
            y     = coord.y;
            z     = coord.z;

            if (this.blocks[x][y][z].type == BlockType.EMPTY)
            {
                BlockType possible = this.FindValidBlock(new BlockCoord(x, y, z));
                if (possible != BlockType.EMPTY)
                {
                    this.ApplyBlock(possible, new BlockCoord(x, y, z));
                    break;
                }
            }
        }
    }
Example #20
0
 public void SetRequestRegion(BlockCoord min, BlockCoord max)
 {
     requestRegion.Set(new BlockCoord.Range(min, max));
 }
 public MapDataStore(BlockCoord block)
     : this(block.ToDFCoord(), BLOCK_SIZE)
 {
 }
 public void CopySliceTo(BlockCoord block, MapDataStore target)
 {
     CopySliceTo(block.ToDFCoord(), BLOCK_SIZE, target);
 }
 public MapDataStore CopySlice(BlockCoord block)
 {
     return CopySlice(block.ToDFCoord(), BLOCK_SIZE);
 }
 public MapDataStore CopySlice(BlockCoord block)
 {
     return(CopySlice(block.ToDFCoord(), BLOCK_SIZE));
 }
 public void CopySliceTo(BlockCoord block, MapDataStore target)
 {
     CopySliceTo(block.ToDFCoord(), BLOCK_SIZE, target);
 }
 public MapDataStore(BlockCoord block) : this(block.ToDFCoord(), BLOCK_SIZE)
 {
 }
 public void SetRequestRegion(BlockCoord min, BlockCoord max)
 {
     lock (blockRequest)
     {
         RequestRegionMin = min;
         RequestRegionMax = max;
         blockRequest.min_x = min.x;
         blockRequest.min_y = min.y;
         blockRequest.min_z = min.z;
         blockRequest.max_x = max.x;
         blockRequest.max_y = max.y;
         blockRequest.max_z = max.z;
     }
 }
Example #28
0
        private void DoWater(int x, int y, int z)
        {
            Queue <BlockKey> flowQueue = new Queue <BlockKey>();

            BlockKey prikey = new BlockKey(x, y, z);

            flowQueue.Enqueue(prikey);

            List <BlockKey> outflow = TileOutflow(prikey);

            foreach (BlockKey outkey in outflow)
            {
                flowQueue.Enqueue(outkey);
            }

            while (flowQueue.Count > 0)
            {
                BlockKey key = flowQueue.Dequeue();

                int curflow = 16;
                int inflow  = TileInflow(key);

                BlockCoord tile     = TranslateCoord(key.x, key.y, key.z);
                BlockInfo  tileInfo = tile.chunk.GetInfo(tile.lx, tile.ly, tile.lz);
                if (tileInfo.ID == BlockInfo.StationaryWater.ID || tileInfo.ID == BlockInfo.Water.ID)
                {
                    curflow = tile.chunk.GetData(tile.lx, tile.ly, tile.lz);
                }
                else if (tileInfo.BlocksFluid)
                {
                    continue;
                }

                bool curFall = (curflow & (int)LiquidState.FALLING) != 0;
                bool inFall  = (inflow & (int)LiquidState.FALLING) != 0;

                // We won't update from the following states
                if (curflow == 0 || curflow == inflow || curFall)
                {
                    continue;
                }

                int newflow = curflow;

                // Update from inflow if necessary
                if (inFall)
                {
                    newflow = inflow;
                }
                else if (inflow >= 7)
                {
                    newflow = 16;
                }
                else
                {
                    newflow = inflow + 1;
                }

                // If we haven't changed the flow, don't propagate
                if (newflow == curflow)
                {
                    continue;
                }

                // Update flow, add or remove water tile as necessary
                if (newflow < 16 && curflow == 16)
                {
                    // If we're overwriting lava, replace with appropriate stone type and abort propagation
                    if (tileInfo.ID == BlockInfo.StationaryLava.ID || tileInfo.ID == BlockInfo.Lava.ID)
                    {
                        if ((newflow & (int)LiquidState.FALLING) != 0)
                        {
                            int odata = tile.chunk.GetData(tile.lx, tile.ly, tile.lz);
                            if (odata == 0)
                            {
                                tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.Obsidian.ID);
                            }
                            else
                            {
                                tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.Cobblestone.ID);
                            }
                            tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0);
                            continue;
                        }
                    }

                    // Otherwise replace the tile with our water flow
                    tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.StationaryWater.ID);
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow);
                }
                else if (newflow == 16)
                {
                    tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.Air.ID);
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0);
                }
                else
                {
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow);
                }

                // Process outflows
                outflow = TileOutflow(key);

                foreach (BlockKey nkey in outflow)
                {
                    flowQueue.Enqueue(nkey);
                }
            }
        }
        private void DoLava(int x, int y, int z)
        {
            Queue <BlockKey> flowQueue = new Queue <BlockKey>();

            BlockKey prikey = new BlockKey(x, y, z);

            flowQueue.Enqueue(prikey);

            List <BlockKey> outflow = TileOutflow(prikey);

            foreach (BlockKey outkey in outflow)
            {
                flowQueue.Enqueue(outkey);
            }

            while (flowQueue.Count > 0)
            {
                BlockKey key = flowQueue.Dequeue();

                int curflow = 16;
                int inflow  = TileInflow(key);

                BlockCoord tile     = TranslateCoord(key.x, key.y, key.z);
                BlockInfo  tileInfo = tile.chunk.GetInfo(tile.lx, tile.ly, tile.lz);
                if (tileInfo.ID == BlockType.STATIONARY_LAVA || tileInfo.ID == BlockType.LAVA)
                {
                    curflow = tile.chunk.GetData(tile.lx, tile.ly, tile.lz);
                }
                else if (tileInfo.BlocksFluid)
                {
                    continue;
                }

                bool curFall = (curflow & (int)LiquidState.FALLING) != 0;
                bool inFall  = (inflow & (int)LiquidState.FALLING) != 0;

                // We won't update from the following states
                if (curflow == 0 || curflow == inflow || curFall)
                {
                    continue;
                }

                int newflow = curflow;

                // Update from inflow if necessary
                if (inFall)
                {
                    newflow = inflow;
                }
                else if (inflow >= 6)
                {
                    newflow = 16;
                }
                else
                {
                    newflow = inflow + 2;
                }

                // If we haven't changed the flow, don't propagate
                if (newflow == curflow)
                {
                    continue;
                }

                // Update flow, add or remove lava tile as necessary
                if (newflow < 16 && curflow == 16)
                {
                    // If we're overwriting water, replace with appropriate stone type and abort propagation
                    if (tileInfo.ID == BlockType.STATIONARY_WATER || tileInfo.ID == BlockType.WATER)
                    {
                        if ((newflow & (int)LiquidState.FALLING) == 0)
                        {
                            tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockType.COBBLESTONE);
                            tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0);
                            continue;
                        }
                    }

                    tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockType.STATIONARY_LAVA);
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow);
                }
                else if (newflow == 16)
                {
                    tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockType.AIR);
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0);
                }
                else
                {
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow);
                }

                // Process outflows
                outflow = TileOutflow(key);

                foreach (BlockKey nkey in outflow)
                {
                    flowQueue.Enqueue(nkey);
                }
            }
        }
Example #30
0
 public bool BlockIsSupported(BlockCoord coord)
 {
     return(BlockIsSupported(this.blocks[coord.x][coord.y][coord.z].type, coord));
 }
        // -----

        private List <BlockKey> TileOutflow(BlockKey key, int reach = 5)
        {
            Queue <BlockKey> searchQueue = new Queue <BlockKey>();
            Queue <KeyValuePair <BlockKey, int> > traceQueue = new Queue <KeyValuePair <BlockKey, int> >();
            Dictionary <BlockKey, int>            markTable  = new Dictionary <BlockKey, int>();

            searchQueue.Enqueue(key);
            markTable.Add(key, 0);

            // Identify sinks
            while (searchQueue.Count > 0)
            {
                BlockKey branch   = searchQueue.Dequeue();
                int      distance = markTable[branch];

                // Ignore blocks out of range
                if (distance > reach)
                {
                    continue;
                }

                // Ignore invalid blocks
                BlockCoord branchHigh = TranslateCoord(branch.x, branch.y, branch.z);
                if (branchHigh.chunk == null || branch.y == 0)
                {
                    markTable.Remove(branch);
                    continue;
                }

                // If we're not the magical source block...
                if (distance > 0)
                {
                    // Ignore blocks that block fluid (and thus could not become a fluid)
                    BlockInfo branchHighInfo = branchHigh.chunk.GetInfo(branchHigh.lx, branchHigh.ly, branchHigh.lz);
                    if (branchHighInfo.BlocksFluid)
                    {
                        markTable.Remove(branch);
                        continue;
                    }
                }

                // If we found a hole, add as a sink, mark the sink distance.
                BlockCoord branchLow     = TranslateCoord(branch.x, branch.y - 1, branch.z);
                BlockInfo  branchLowInfo = branchLow.chunk.GetInfo(branchLow.lx, branchLow.ly, branchLow.lz);
                if (!branchLowInfo.BlocksFluid)
                {
                    // If we are our own sink, return the only legal outflow
                    if (key == branch)
                    {
                        List <BlockKey> ret = new List <BlockKey>();
                        ret.Add(new BlockKey(branch.x, branch.y - 1, branch.z));
                        return(ret);
                    }

                    reach = distance;
                    traceQueue.Enqueue(new KeyValuePair <BlockKey, int>(branch, distance));
                    continue;
                }

                // Expand to neighbors
                if (distance < reach)
                {
                    BlockKey[] keys =
                    {
                        new BlockKey(branch.x - 1, branch.y, branch.z),
                        new BlockKey(branch.x + 1, branch.y, branch.z),
                        new BlockKey(branch.x,     branch.y, branch.z - 1),
                        new BlockKey(branch.x,     branch.y, branch.z + 1),
                    };

                    for (int i = 0; i < 4; i++)
                    {
                        if (!markTable.ContainsKey(keys[i]))
                        {
                            searchQueue.Enqueue(keys[i]);
                            markTable.Add(keys[i], distance + 1);
                        }
                    }
                }
            }

            // Candidate outflows are marked
            BlockKey[] neighbors =
            {
                new BlockKey(key.x - 1, key.y, key.z),
                new BlockKey(key.x + 1, key.y, key.z),
                new BlockKey(key.x,     key.y, key.z - 1),
                new BlockKey(key.x,     key.y, key.z + 1),
            };

            List <BlockKey> outflow = new List <BlockKey>();

            foreach (BlockKey n in neighbors)
            {
                if (markTable.ContainsKey(n))
                {
                    outflow.Add(n);
                }
            }

            // If there's no sinks, all neighbors are valid outflows
            if (traceQueue.Count == 0)
            {
                return(outflow);
            }

            // Trace back from each sink eliminating shortest path marks
            while (traceQueue.Count > 0)
            {
                KeyValuePair <BlockKey, int> tilekv = traceQueue.Dequeue();
                BlockKey tile = tilekv.Key;

                int distance = tilekv.Value;
                markTable.Remove(tile);

                BlockKey[] keys =
                {
                    new BlockKey(tile.x - 1, tile.y, tile.z),
                    new BlockKey(tile.x + 1, tile.y, tile.z),
                    new BlockKey(tile.x,     tile.y, tile.z - 1),
                    new BlockKey(tile.x,     tile.y, tile.z + 1),
                };

                for (int i = 0; i < 4; i++)
                {
                    int nval;
                    if (!markTable.TryGetValue(keys[i], out nval))
                    {
                        continue;
                    }

                    if (nval < distance)
                    {
                        markTable.Remove(keys[i]);
                        traceQueue.Enqueue(new KeyValuePair <BlockKey, int>(keys[i], nval));
                    }
                }
            }

            // Remove any candidates that are still marked
            foreach (BlockKey n in neighbors)
            {
                if (markTable.ContainsKey(n))
                {
                    outflow.Remove(n);
                }
            }

            return(outflow);
        }
Example #32
0
 public Vector3 OffsetBlockPosition(BlockCoord coord) => OffsetBlockPosition(coord.X, coord.Y);
Example #33
0
 public Block SetBlockAt(BlockCoord coord, Block block) => SetBlockAt(coord.X, coord.Y, block);
        private int TileInflow(BlockKey key)
        {
            // Check if water is falling on us
            if (key.y < _ydim - 1)
            {
                BlockCoord up     = TranslateCoord(key.x, key.y + 1, key.z);
                BlockInfo  upInfo = up.chunk.GetInfo(up.lx, up.ly, up.lz);

                if (upInfo.State == BlockState.FLUID)
                {
                    return(up.chunk.GetData(up.lx, up.ly, up.lz) | (int)LiquidState.FALLING);
                }
            }

            // Otherwise return the min inflow of our neighbors + step
            BlockKey[] keys =
            {
                new BlockKey(key.x - 1, key.y, key.z),
                new BlockKey(key.x + 1, key.y, key.z),
                new BlockKey(key.x,     key.y, key.z - 1),
                new BlockKey(key.x,     key.y, key.z + 1),
            };

            int minFlow = 16;

            // XXX: Might have different neighboring fluids
            for (int i = 0; i < 4; i++)
            {
                BlockCoord neighbor = TranslateCoord(keys[i].x, keys[i].y, keys[i].z);
                if (neighbor.chunk == null)
                {
                    continue;
                }

                BlockInfo neighborInfo = neighbor.chunk.GetInfo(neighbor.lx, neighbor.ly, neighbor.lz);

                if (neighborInfo.State == BlockState.FLUID)
                {
                    int  flow     = neighbor.chunk.GetData(neighbor.lx, neighbor.ly, neighbor.lz);
                    bool flowFall = (flow & (int)LiquidState.FALLING) != 0;

                    if (flowFall)
                    {
                        if (keys[i].y == 0)
                        {
                            continue;
                        }

                        BlockCoord low     = TranslateCoord(keys[i].x, keys[i].y - 1, keys[i].z);
                        BlockInfo  lowinfo = low.chunk.GetInfo(low.lx, low.ly, low.lz);

                        if (lowinfo.BlocksFluid)
                        {
                            return(0);
                        }
                        continue;
                    }
                    if (flow < minFlow)
                    {
                        minFlow = flow;
                    }
                }
            }

            return(minFlow);
        }