private void Update()
    {
        //if (Time.time - lastClear > 1000) {
        Debug.ClearDeveloperConsole();
        //    lastClear = Time.time;
        //}

        GetChunkCoordFromVector3(playerChunkCoord);

        // Only update the chunks if the player has moved from the chunk they were previously on.
        //if (!playerChunkCoord.Equals(playerLastChunkCoord))
        //    CheckViewDistance();
        tmpTimeDelta += Time.deltaTime;
        //Debug.Log(string.Format("Tick CountLands::{0} GridSize^2::{1}", CountLands, landPoolsSize));
        if (CountLands < landPoolsSize)// initilise map
        {
            if (tmpTimeDelta > -0.1)
            {
                tmpTimeDelta = 0;

                ChunkCoord pos = PreferedLocArray[0];
                PreferedLocArray.RemoveAt(0);
                Chunk newChunk = new Chunk(pos);
                if (!settings.enableThreading)
                {
                    activeChunks.Add(pos);
                    newChunk.PullChunkDataAndUpdateChunk();
                }
                else
                {
                    lock (threadingChunks) {
                        pos.chunk = newChunk;
                        threadingChunks.Add(pos);
                    }
                }
                BoxDebug.DrawBox(new Vector3(pos.x * VoxelData.TileWidthUU, 40, pos.z * VoxelData.TileWidthUU), new Vector3(VoxelData.TileWidthUU, 10, VoxelData.TileWidthUU), Color.red, init_show_time);
                chunkPools.Add(newChunk);
                chunkDict.Add(pos, newChunk);
                CountLands++;
            }
        }
        else   // Lazily check and invalidate chunks.
        {
            if (tmpTimeDelta > -0.125)
            {
                lock (unthreadingChunks){
                    int size = unthreadingChunks.Count;
                    if (size > 0)
                    {
                        for (int i = 0; i < size; i++)
                        {
                            chunkDict.Remove(unthreadingChunks[i]);
                        }
                        unthreadingChunks.Clear();
                    }
                }
                tmpTimeDelta = 0;

                CalculatePositionMap(false);

                if (!settings.enableThreading)
                {
                    //if (!applyingModifications)
                    //    ApplyModifications();

                    //if (chunksToUpdate.Count > 0)
                    //    UpdateChunks();
                }
            }
        }

        lock (this) {
            while (chunksToDraw.Count > 0)
            {
                chunksToDraw.Dequeue().AssignMesh();
            }
        }

        if (Input.GetKeyDown(KeyCode.F3))
        {
            debugScreen.SetActive(!debugScreen.activeSelf);
        }

        if (Input.GetKeyDown(KeyCode.F1))
        {
            SaveSystem.SaveWorld(worldData);
        }
    }
    /** Calculate positions to update.
     * A grid system that starts at player's position, and flip-expand again and again to reach maximum size.
     * The grid system was first wirten for UE4's landscape. https://www.youtube.com/watch?v=xvZg9IgXLLE&t=8s
     * ... now It's used to initialise and update the voxel map. */
    public void CalculatePositionMap(bool init)
    {
        CC = 0;
        if (init)
        {
            PreferedLocations.Clear();
            PreferedLocArray.Clear();
        }
        rCurrentCoord.Set(0, 0);
        float relativeX = player.position.x - baseLocation.x;
        float relativeZ = player.position.z - baseLocation.z;

        rStartCoord.x = Mathf.FloorToInt(relativeX / VoxelData.ChunkWidth);
        rStartCoord.z = Mathf.FloorToInt(relativeZ / VoxelData.ChunkWidth);

        int NormalizdRelativeX = rStartCoord.x * VoxelData.ChunkWidth;
        int NormalizdRelativeZ = rStartCoord.z * VoxelData.ChunkWidth;

        R0x = NormalizdRelativeX + baseLocation.x;
        R0z = NormalizdRelativeZ + baseLocation.z;
        R0y = baseLocation.y;
        if (init)
        {
            BoxDebug.DrawBox(new Vector3(R0x, R0y, R0z), new Vector3(VoxelData.TileWidthUU, 10, VoxelData.TileWidthUU), Color.black, init_show_time);
            PreferedLocArray.Add(new ChunkCoord(rStartCoord.x, rStartCoord.z));
        }
        int square_case = 0;

        if (relativeX >= NormalizdRelativeX + VoxelData.HalfTileWidth)
        {
            square_case = 1;
        }
        if (relativeZ >= NormalizdRelativeZ + VoxelData.HalfTileWidth)
        {
            square_case += 2;
        }

        minX = rStartCoord.x - settings.GridSize / 2;
        maxX = rStartCoord.x + settings.GridSize / 2;
        minZ = rStartCoord.z - settings.GridSize / 2;
        maxZ = rStartCoord.z + settings.GridSize / 2;
        Chunk chunkToReposition = null;

        if (!init)
        {
            // Caculate map extensions.
            //Debug.Log(string.Format("MinMax: minX={0}, maxX={1}, minZ={2}, maxZ={3}", minX, maxX, minZ, maxZ));
            if (settings.GridSize % 2 == 0)
            {
                if ((square_case & 1) != 0)
                {
                    minX++;
                }
                else
                {
                    maxX--;
                }
                if ((square_case & 2) != 0)
                {
                    minZ++;
                }
                else
                {
                    maxZ--;
                }
            }
            for (int i = 0; i < landPoolsSize; i++)
            {
                Chunk      c   = chunkPools[i];
                ChunkCoord pos = c.coord;
                if (pos.x < minX || pos.x > maxX || pos.z < minZ || pos.z > maxZ)
                {
                    chunkToReposition = c;
                    break;
                }
            }

            if (!chunkDict.ContainsKey(rStartCoord)) // check coord not occupied
            //Debug.Log("start not occupied!!!");
            {
                if (chunkToReposition != null)
                {
                    RepositionChunk(chunkToReposition, new ChunkCoord(rStartCoord));
                }
                return;
            }
        }

        bool cornerflipped = square_case == 3 || square_case == 2;
        bool typeA         = square_case == 0 || square_case == 3;

        GridSizeCurrent = 1;
        rcx             = rcz = 0;
        while (GridSizeCurrent < settings.GridSize)
        {
            if (typeA)
            {
                if (!cornerflipped)
                {
                    rcx--;
                    rcz--;
                }
            }
            else
            {
                if (cornerflipped)
                {
                    rcx--;
                }
                else
                {
                    rcz--;
                }
            }
            rCurrentStillx = rcx;
            if (typeA == cornerflipped)
            {
                rCurrentStillx += GridSizeCurrent;
            }
            //if(GridSizeCurrent==3)
            //rCurrentStillx-=1;
            stillx         = rCurrentStillx * VoxelData.ChunkWidth + R0x;
            rCurrentStillz = rcz;
            if (cornerflipped)
            {
                rCurrentStillz += GridSizeCurrent;
            }
            stillz = rCurrentStillz * VoxelData.ChunkWidth + R0z;
            // Expand X.
            for (int i = 0; i <= GridSizeCurrent; i++)
            {
                rCurrentCoord.x = rcx + i;
                MT_TmpCoord.Set(rStartCoord.x + rCurrentCoord.x, rStartCoord.z + rCurrentStillz);
                if (init)
                {
                    Vector3 pos = new Vector3(R0x + rCurrentCoord.x * VoxelData.TileWidthUU, R0y, stillz);
                    BoxDebug.DrawBox(pos + new Vector3(0, 60, 0), new Vector3(VoxelData.TileWidthUU, 10, VoxelData.TileWidthUU), Color.white, init_show_time);
                    PreferedLocArray.Add(new ChunkCoord(MT_TmpCoord));
                }
                else if (!chunkDict.ContainsKey(MT_TmpCoord))   // check coord not occupied
                {
                    if (chunkToReposition != null)
                    {
                        RepositionChunk(chunkToReposition, new ChunkCoord(MT_TmpCoord));
                    }
                    return;
                }
            }
            // Expand Z.
            int ZIndexOffset = cornerflipped?1:0;
            for (int i = 1; i <= GridSizeCurrent; i++)
            {
                rCurrentCoord.z = rcz + i - ZIndexOffset;
                MT_TmpCoord.Set(rStartCoord.x + rCurrentStillx, rStartCoord.z + rCurrentCoord.z);
                if (init)
                {
                    Vector3 pos = new Vector3(stillx, R0y, R0z + rCurrentCoord.z * VoxelData.TileWidthUU);
                    BoxDebug.DrawBox(pos + new Vector3(0, 60, 0), new Vector3(VoxelData.TileWidthUU, 10, VoxelData.TileWidthUU), Color.red, init_show_time);
                    PreferedLocArray.Add(new ChunkCoord(MT_TmpCoord));
                }
                else if (!chunkDict.ContainsKey(MT_TmpCoord))   // check coord not occupied
                {
                    if (chunkToReposition != null)
                    {
                        RepositionChunk(chunkToReposition, new ChunkCoord(MT_TmpCoord));
                    }
                    return;
                }
            }
            GridSizeCurrent++;
            cornerflipped = !cornerflipped;
        }
        //Debug.Log(string.Format("PreferedLocArray::{0} GridSize^2::{1}", PreferedLocArray.Count, landPoolsSize));
    }