/// <summary>
        /// Set array of blocks
        /// </summary>
        /// <param name="blockDatas">array containing data of each block you want to place</param>
        /// <param name="destroy">spawn destroy particle</param>
        public void SetBlocks(BlockData[] blockDatas, SetBlockSettings blockSettings)
        {
            List <JobHandle> jobHandles    = new List <JobHandle>();
            List <Chunk>     chunksToBuild = new List <Chunk>();

            bool[] neighboursToBuild = new bool[4];

            for (int i = 0; i < blockDatas.Length; i++)
            {
                BlockPosition blockPosition = blockDatas[i].position;
                BlockType     blockType     = blockDatas[i].blockType;

                SetBlockWithoutRebuild(blockPosition, blockType, blockSettings);

                // check neighbours
                if (blockPosition.x == 16)
                {
                    Chunk neighbourChunk = NeighbourChunks[0];
                    if (neighbourChunk)
                    {
                        neighbourChunk.blocks[Utils.BlockPosition3DtoIndex(0, blockPosition.y, blockPosition.z)] = blockType;
                        neighbourChunk.isTerrainModified = true;
                        neighboursToBuild[0]             = true;
                    }
                }
                else if (blockPosition.x == 1)
                {
                    Chunk neighbourChunk = NeighbourChunks[1];
                    if (neighbourChunk)
                    {
                        neighbourChunk.blocks[Utils.BlockPosition3DtoIndex(17, blockPosition.y, blockPosition.z)] = blockType;
                        neighbourChunk.isTerrainModified = true;
                        neighboursToBuild[1]             = true;
                    }
                }

                if (blockPosition.z == 16)
                {
                    Chunk neighbourChunk = NeighbourChunks[2];
                    if (neighbourChunk)
                    {
                        neighbourChunk.blocks[Utils.BlockPosition3DtoIndex(blockPosition.x, blockPosition.y, 0)] = blockType;
                        neighbourChunk.isTerrainModified = true;
                        neighboursToBuild[2]             = true;
                    }
                }
                else if (blockPosition.z == 1)
                {
                    Chunk neighbourChunk = NeighbourChunks[3];
                    if (neighbourChunk)
                    {
                        neighbourChunk.blocks[Utils.BlockPosition3DtoIndex(blockPosition.x, blockPosition.y, 17)] = blockType;
                        neighbourChunk.isTerrainModified = true;
                        neighboursToBuild[3]             = true;
                    }
                }

                UpdateNeighbourBlocks(blockDatas[i].position, 10);
            }

            // add current chunk
            BuildMesh(jobHandles);
            chunksToBuild.Add(this);

            for (int j = 0; j < 4; j++)
            {
                if (neighboursToBuild[j])
                {
                    Chunk tc = NeighbourChunks[j];
                    tc.BuildMesh(jobHandles);
                    chunksToBuild.Add(tc);
                }
            }

            NativeArray <JobHandle> njobHandles = new NativeArray <JobHandle>(jobHandles.ToArray(), Allocator.Temp);

            JobHandle.CompleteAll(njobHandles);

            // build meshes
            foreach (Chunk tc in chunksToBuild)
            {
                tc.ApplyMesh();
            }

            // clear & dispose
            jobHandles.Clear();
            chunksToBuild.Clear();

            njobHandles.Dispose();
        }
        /// <summary>
        /// Set block at position and rebuild mesh - use when you want to place one block, else take a look at
        /// <see cref="SetBlockWithoutRebuild(int, int, int, BlockType, bool)"/> or <see cref="SetBlocks(BlockData[], bool)"/>
        /// </summary>
        /// <param name="x">x position of block</param>
        /// <param name="y">y position of block</param>
        /// <param name="z">z position of block</param>
        /// <param name="blockType">type of block you want to place</param>
        /// <param name="destroy">spawn destroy particle</param>
        public void SetBlock(BlockPosition blockPosition, BlockType blockType, SetBlockSettings blockSettings)
        {
            List <JobHandle> jobHandles    = new List <JobHandle>();
            List <Chunk>     chunksToBuild = new List <Chunk>();

            SetBlockWithoutRebuild(blockPosition, blockType, blockSettings);

            // add current chunk
            BuildMesh(jobHandles);
            chunksToBuild.Add(this);

            // check neighbours
            if (blockPosition.x == 16)
            {
                Chunk neighbourChunk = NeighbourChunks[0];
                if (neighbourChunk)
                {
                    neighbourChunk.blocks[Utils.BlockPosition3DtoIndex(0, blockPosition.y, blockPosition.z)] = blockType;
                    neighbourChunk.isTerrainModified = true;
                    neighbourChunk.BuildMesh(jobHandles);
                    chunksToBuild.Add(neighbourChunk);
                }
            }
            else if (blockPosition.x == 1)
            {
                Chunk neighbourChunk = NeighbourChunks[1];
                if (neighbourChunk)
                {
                    neighbourChunk.blocks[Utils.BlockPosition3DtoIndex(17, blockPosition.y, blockPosition.z)] = blockType;
                    neighbourChunk.isTerrainModified = true;
                    neighbourChunk.BuildMesh(jobHandles);
                    chunksToBuild.Add(neighbourChunk);
                }
            }

            if (blockPosition.z == 16)
            {
                Chunk neighbourChunk = NeighbourChunks[2];
                if (neighbourChunk)
                {
                    neighbourChunk.blocks[Utils.BlockPosition3DtoIndex(blockPosition.x, blockPosition.y, 0)] = blockType;
                    neighbourChunk.isTerrainModified = true;
                    neighbourChunk.BuildMesh(jobHandles);
                    chunksToBuild.Add(neighbourChunk);
                }
            }
            else if (blockPosition.z == 1)
            {
                Chunk neighbourChunk = NeighbourChunks[3];
                if (neighbourChunk)
                {
                    neighbourChunk.blocks[Utils.BlockPosition3DtoIndex(blockPosition.x, blockPosition.y, 17)] = blockType;
                    neighbourChunk.isTerrainModified = true;
                    neighbourChunk.BuildMesh(jobHandles);
                    chunksToBuild.Add(neighbourChunk);
                }
            }

            NativeArray <JobHandle> njobHandles = new NativeArray <JobHandle>(jobHandles.ToArray(), Allocator.TempJob);

            JobHandle.CompleteAll(njobHandles);

            // build meshes
            foreach (Chunk tc in chunksToBuild)
            {
                tc.ApplyMesh();
            }

            // clear & dispose
            jobHandles.Clear();
            chunksToBuild.Clear();
            njobHandles.Dispose();

            UpdateNeighbourBlocks(blockPosition, 10);
        }