//UNDONE
    public static List<List<U16Vec2>> CreateClusters(ref Chunk map, GlobalTerrainSettings.ClustersSettings clustersParam)
    {
        ushort height = map.Height;
        ushort width = map.Width;

        List<List<U16Vec2>> clusters = new List<List<U16Vec2>>(clustersParam.Count);

        for (byte i = 0; i < clustersParam.Count; ++i)
        {
            U16Vec2 pos;
            pos.X = (ushort)Random.Range(1, width - 1);
            pos.Y = (ushort)Random.Range(1, height - 1);
            if ((map.TerrainMatrix[pos.Y, pos.X] & TerrainType.RIVER) == TerrainType.NONE)
            {
                clusters.Add(new List<U16Vec2>());
                SpreadCluster(map, pos, clustersParam.Size, clusters[i]);
            }
            else
                --i;
        }
        return clusters;
    }
    static Stack<U16Vec2> RiverStack; //Стек для постройки реки

    #endregion Fields

    #region Methods

    public static void CreateChunk(ref Chunk map, GlobalTerrainSettings settings, HeighmapNeighboring hmNbHeight, float landscapeRoughness, HeighmapNeighboring hmNbForest, float forestRoughness, float forestDensity)
    {
        float?[,] buf = new float?[map.Height, map.Width];
        WorldGenerator.CreateHeightmap(ref buf, landscapeRoughness, hmNbHeight);
        for (ushort y = 0; y < map.Height; ++y)
            for (ushort x = 0; x < map.Width; ++x)
            {
                map.HeightMatrix[y, x] = Mathf.Clamp(buf[y, x].Value, 0, Mathf.Abs(buf[y, x].Value));
                buf[y, x] = null;
            }

        WorldGenerator.CreateHeightmap(ref buf, forestRoughness, hmNbForest);
        for (ushort y = 0; y < map.Height; ++y)
            for (ushort x = 0; x < map.Width; ++x)
            {
                buf[y, x] = buf[y, x].Value * forestDensity;
                map.ForestMatrix[y, x] = Mathf.Clamp(buf[y, x].Value, 0, Mathf.Abs(buf[y, x].Value));
            }
        map.Rivers = WorldGenerator.CreateRivers(map.HeightMatrix, ref map.TerrainMatrix, settings.RiversParam);
        map.Clusters = WorldGenerator.CreateClusters(ref map, settings.ClustersParam);
        map.Roads = WorldGenerator.CreateRoads(map.HeightMatrix, ref map.TerrainMatrix, map.Clusters, settings.RoadsParam);
        WorldGenerator.CreateTerrainmap(ref map.TerrainMatrix, map.HeightMatrix, settings);
    }
    static void DirectRoad(float[,] heightMatrix, TerrainType[,] terrainMatrix, U16Vec2 pos, U16Vec2 destination, List<U16Vec2> road, GlobalTerrainSettings.RoadsSettings roadsParam)
    {
        ushort height = (ushort)heightMatrix.GetLength(0);
        ushort width = (ushort)heightMatrix.GetLength(1);

        road.Add(pos);
        terrainMatrix[pos.Y, pos.X] |= TerrainType.ROAD;

        if (pos.Y > 0 && pos.Y < height - 1 && pos.X > 0 && pos.X < width - 1 && !(destination.X == pos.X && destination.Y == pos.Y))
        {
            byte k = (byte)(pos.X & 1); //TODO Провести рефакторинг.

            float max = heightMatrix[pos.Y + k, pos.X - 1], avg = 0;
            float cur = heightMatrix[pos.Y + k, pos.X - 1];
            avg += cur;

            cur = heightMatrix[pos.Y + 1, pos.X];
            if (max < cur)
                max = cur;
            avg += cur;

            cur = heightMatrix[pos.Y + k, pos.X + 1];
            if (max < cur)
                max = cur;
            avg += cur;

            cur = heightMatrix[pos.Y - 1 + k, pos.X + 1];
            if (max < cur)
                max = cur;
            avg += cur;

            cur = heightMatrix[pos.Y - 1, pos.X];
            if (max < cur)
                max = cur;
            avg += cur;

            cur = heightMatrix[pos.Y - 1 + k, pos.X - 1];
            if (max < cur)
                max = cur;
            avg += cur;

            avg /= 6;
            max += 0.0001f; //!

            float weight = 0, buf;
            sbyte dx = 0, dy = 0;

            if (!road.Contains(new U16Vec2((ushort)(pos.X - 1), (ushort)(pos.Y + k))) && ((buf = (Mathf.Abs(destination.X - pos.X) - Mathf.Abs(destination.X - (pos.X - 1)) + Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y + k)) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y + k, pos.X - 1] - avg))) * ((terrainMatrix[pos.Y + k, pos.X - 1] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y + k, pos.X - 1] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight))
            {
                weight = buf;
                dx = -1;
                dy = (sbyte)k;
            }
            if (!road.Contains(new U16Vec2((ushort)(pos.X + 1), (ushort)(pos.Y + k))) && ((buf = (Mathf.Abs(destination.X - pos.X) - Mathf.Abs(destination.X - (pos.X + 1)) + Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y + k)) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y + k, pos.X + 1] - avg))) * ((terrainMatrix[pos.Y + k, pos.X + 1] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y + k, pos.X + 1] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight))
            {
                weight = buf;
                dx = 1;
                dy = (sbyte)k;
            }
            if (!road.Contains(new U16Vec2(pos.X, (ushort)(pos.Y + 1))) && ((buf = (Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y + 1)) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y + 1, pos.X] - avg))) * ((terrainMatrix[pos.Y + 1, pos.X] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y + 1, pos.X] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight))//!После диагонали
            {
                weight = buf;
                dx = 0;
                dy = 1;
            }
            if (!road.Contains(new U16Vec2((ushort)(pos.X + 1), (ushort)(pos.Y - (k ^ 1)))) && ((buf = (Mathf.Abs(destination.X - pos.X) - Mathf.Abs(destination.X - (pos.X + 1)) + Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y - (k ^ 1))) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y - (k ^ 1), pos.X + 1] - avg))) * ((terrainMatrix[pos.Y - (k ^ 1), pos.X + 1] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y - (k ^ 1), pos.X + 1] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight))
            {
                weight = buf;
                dx = 1;
                dy = (sbyte)(-(k ^ 1));
            }
            if (!road.Contains(new U16Vec2((ushort)(pos.X - 1), (ushort)(pos.Y - (k ^ 1)))) && ((buf = (Mathf.Abs(destination.X - pos.X) - Mathf.Abs(destination.X - (pos.X - 1)) + Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y - (k ^ 1))) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y - (k ^ 1), pos.X - 1] - avg))) * ((terrainMatrix[pos.Y - (k ^ 1), pos.X - 1] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y - (k ^ 1), pos.X - 1] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight))
            {
                weight = buf;
                dx = -1;
                dy = (sbyte)(-(k ^ 1));
            }
            if (!road.Contains(new U16Vec2(pos.X, (ushort)(pos.Y - 1))) && ((buf = (Mathf.Abs(destination.Y - pos.Y) - Mathf.Abs(destination.Y - (pos.Y - 1)) + 3) * (max - Mathf.Abs(heightMatrix[pos.Y - 1, pos.X] - avg))) * ((terrainMatrix[pos.Y - 1, pos.X] & TerrainType.ROAD) != TerrainType.NONE ? roadsParam.RoadMergeMultiplier : 1) * ((terrainMatrix[pos.Y, pos.X] & terrainMatrix[pos.Y - 1, pos.X] & TerrainType.RIVER) != TerrainType.NONE ? roadsParam.GoingAlongRiverMultiplier : 1) > weight))//!После диагонали
            {
                weight = buf;
                dx = 0;
                dy = -1;
            }

            if (dx == 0 && dy == 0)
                throw new System.Exception("Infinite recursion detected. Try to check heightmap values.");

            DirectRoad(heightMatrix, terrainMatrix, new U16Vec2((ushort)(pos.X + dx), (ushort)(pos.Y + dy)), destination, road, roadsParam);
        }
    }
    public static void CreateTerrainmap(ref TerrainType[,] terrainmap, float[,] matrix, GlobalTerrainSettings terrainParam)
    {
        ushort height = (ushort)terrainmap.GetLength(0);
        ushort width = (ushort)terrainmap.GetLength(1);

        for (ushort y = 0; y < height; ++y)
            for (ushort x = 0; x < width; ++x)
                if (matrix[y, x] < terrainParam.Terrains[0].StartingHeight)
                    terrainmap[y, x] |= terrainParam.BottommostTerrain;
                else if (matrix[y, x] >= terrainParam.Terrains[terrainParam.Terrains.Length - 1].StartingHeight)
                    terrainmap[y, x] |= terrainParam.Terrains[terrainParam.Terrains.Length - 1].TerrainType;
                else
                    for (byte i = 1; i < terrainParam.Terrains.Length; ++i)
                        if (matrix[y, x] < terrainParam.Terrains[i].StartingHeight)
                        {
                            terrainmap[y, x] |= terrainParam.Terrains[i - 1].TerrainType;
                            break;
                        }
    }
 public static List<List<U16Vec2>> CreateRoads(float[,] heightMap, ref TerrainType[,] terrainMap, List<List<U16Vec2>> clusters, GlobalTerrainSettings.RoadsSettings roadsParam)
 {
     List<List<U16Vec2>> roads = new List<List<U16Vec2>>();
     for (byte i = 0; i < clusters.Count >> 1; ++i)
     {
         roads.Add(new List<U16Vec2>());
         DirectRoad(heightMap, terrainMap, clusters[i][0], clusters[(clusters.Count >> 1) + i][0], roads[i], roadsParam);
     }
     return roads;
 }
    /// <summary>
    /// Создаёт реки.
    /// </summary>
    /// <returns>Список рек.</returns>
    /// <param name="heightMatrix">Карта высот.</param>
    /// <param name="riverMatrix">[out] Карта рек.</param>
    public static List<List<U16Vec2>> CreateRivers(float[,] heightMap, ref TerrainType[,] terrainMap, GlobalTerrainSettings.RiversSettings riversParam)
    {
        RiverStack = new Stack<U16Vec2>();

        ushort height = (ushort)heightMap.GetLength(0);
        ushort width = (ushort)heightMap.GetLength(1);

        double avg = 0;
        foreach (float h in heightMap)
            avg += h;
        avg /= height * width;
        float minRiverHeight = (float)avg * riversParam.Height;

        List<List<U16Vec2>> rivers = new List<List<U16Vec2>>();

        for (byte i = 0; i < riversParam.Count; ++i)
        {
            bool riverCreated = false;
            for (ushort y = 1; y < height - 1 && !riverCreated; ++y) //TODO
                for (ushort x = 1; x < width - 1 && !riverCreated; ++x) //TODO
                    if (heightMap[y, x] > minRiverHeight && (terrainMap[y, x] & TerrainType.RIVER) == TerrainType.NONE && RiverNeighbours(new U16Vec2(x, y), terrainMap) == 0) //Проверяем, можно ли нам начать создание реки с этого хекса
                        for (byte k = 0; k < riversParam.Attempts && !riverCreated; ++k)
                        {
                            DirectRiver(new U16Vec2(x, y), heightMap, terrainMap, riversParam.FlowHeightKoef); //Запускаем рекурсию
                            if (RiverStack.Count >= riversParam.MinimumLength)
                            { //Если река получилась больше необходим длины, то помечаем ячейки матрицы, иначе пробуем ещё раз
                                foreach (U16Vec2 hex in RiverStack)
                                    terrainMap[hex.Y, hex.X] |= TerrainType.RIVER;
                                riverCreated = true;
                                rivers.Add(new List<U16Vec2>(RiverStack));
                                rivers[rivers.Count - 1].Reverse();
                            }
                            RiverStack.Clear();
                        }
        }
        RiverStack = null;
        return rivers;
    }