//apply terrain area info if it exist
        protected void SetTerrainArea(Volume volume, TerrainColliderInfoAbstract info, Area defaultArea)
        {
            if (info.alphaMap != null)
            {
                var     areaLibrary = PathFinder.settings.areaLibrary;
                int[][] areaMap     = ProcessAlphaMap(info);

                for (int x = 0; x < template.lengthX_extra; x++)
                {
                    for (int z = 0; z < template.lengthZ_extra; z++)
                    {
                        int a = areaMap[x][z];
                        volume.SetArea(x, z, areaLibrary[a]);
                        if (a == 1)
                        {
                            volume.SetPassability(x, z, Passability.Unwalkable);
                        }
                    }
                }
            }
            else
            {
                volume.SetArea(defaultArea);
            }
        }
        //add some values to target TerrainColliderInfoAbstract so later on we can process maps
        protected void SetTerrainSettings(
            TerrainColliderInfoAbstract info,
            Terrain terrain,
            int startXClamp, int startZClamp,
            int endXClamp, int endZClamp,
            int terrainStartX, int terrainStartZ,
            float terrainSizeX, float terrainSizeZ,
            Vector3 position)
        {
            var navmeshSettings = terrain.gameObject.GetComponent <TerrainNavmeshSettings>();

            if (navmeshSettings != null && navmeshSettings.isActiveAndEnabled && navmeshSettings.data.Any(x => x != 0))  //0 is default so if there is settings full of deffault areas then dont need that
            {
                TerrainData data = terrain.terrainData;
                Vector3     size = data.size;
                info.settings    = navmeshSettings;
                info.startXClamp = startXClamp;
                info.startZClamp = startZClamp;

                info.endXClamp = endXClamp;
                info.endZClamp = endZClamp;

                info.terrainStartX = terrainStartX;
                info.terrainStartZ = terrainStartZ;

                info.terrainSizeX = terrainSizeX;
                info.terrainSizeZ = terrainSizeZ;

                //all this values needed in 2 places. here to use data.GetAlphamaps in main thread and later in not main thread
                //so we just store it in terrain collider info
                info.alphaWidth  = data.alphamapWidth;
                info.alphaHeight = data.alphamapHeight;

                //normalized start and end
                //dont needed later
                float terNormStartX = Mathf.Clamp01((template.chunkData.realX - template.properties.radius - position.x) / size.x);
                float terNormStartZ = Mathf.Clamp01((template.chunkData.realZ - template.properties.radius - position.z) / size.z);

                float terNormEndX = Mathf.Clamp01((template.chunkData.realX + PathFinder.settings.gridSize + template.properties.radius - position.x) / size.x);
                float terNormEndZ = Mathf.Clamp01((template.chunkData.realZ + PathFinder.settings.gridSize + template.properties.radius - position.z) / size.z);

                //alpha map position of chunk
                info.alphaStartX = Mathf.RoundToInt(terNormStartX * info.alphaWidth);
                info.alphaStartZ = Mathf.RoundToInt(terNormStartZ * info.alphaHeight);

                //alpha map size of chunk
                //size needed only now
                info.alphaSizeX = Math.Min(Mathf.RoundToInt((terNormEndX - terNormStartX) * info.alphaWidth) + 1, info.alphaWidth - info.alphaStartX);
                info.alphaSizeZ = Math.Min(Mathf.RoundToInt((terNormEndZ - terNormStartZ) * info.alphaHeight) + 1, info.alphaHeight - info.alphaStartZ);

                info.alphaMap     = data.GetAlphamaps(info.alphaStartX, info.alphaStartZ, info.alphaSizeX, info.alphaSizeZ);
                info.possibleArea = (from areaID in navmeshSettings.data select PathFinder.GetArea(areaID)).ToArray(); //else if doCollectAreaInfo == false than later it became defaul area
            }
        }
        //make area map from raw data. as input alpha map, as output int[][] where int is index of area in area library
        //used in threads splited to separate function cause it's just unreadable in other case
        //changes "areaMap" and "passabilityMap" variables inside terrainInfo
        protected int[][] ProcessAlphaMap(TerrainColliderInfoAbstract terrainInfo)
        {
            float[,,] alpha = terrainInfo.alphaMap;
            int alphaCount = alpha.GetLength(2);

            int[] alphaToArea = terrainInfo.settings.data;

            //shome stored values
            int startXClamp = terrainInfo.startXClamp;
            int startZClamp = terrainInfo.startZClamp;

            int endXClamp = terrainInfo.endXClamp;
            int endZClamp = terrainInfo.endZClamp;

            int terrainStartX = terrainInfo.terrainStartX;
            int terrainStartZ = terrainInfo.terrainStartZ;

            float terrainSizeX = terrainInfo.terrainSizeX;
            float terrainSizeZ = terrainInfo.terrainSizeZ;

            int alphaWidth  = terrainInfo.alphaWidth;
            int alphaHeight = terrainInfo.alphaHeight;

            int alphaStartX = terrainInfo.alphaStartX;
            int alphaStartZ = terrainInfo.alphaStartZ;

            int alphaSizeXIndexLimit = terrainInfo.alphaSizeX - 1;
            int alphaSizeZIndexLimit = terrainInfo.alphaSizeZ - 1;

            int[][] areaMap = new int[template.lengthX_extra][];

            for (int x = 0; x < template.lengthX_extra; x++)
            {
                areaMap[x] = new int[template.lengthZ_extra];
            }

            terrainInfo.areaMap = areaMap;

            //this done this way to take into account that a alpha map not aligned with chunk start
            for (int x = startXClamp; x < endXClamp; x++)
            {
                int curX = Mathf.Clamp(Mathf.RoundToInt((x - terrainStartX) / terrainSizeX * alphaWidth) - alphaStartX, 0, alphaSizeXIndexLimit);

                for (int z = startZClamp; z < endZClamp; z++)
                {
                    int curZ = Mathf.Clamp(Mathf.RoundToInt((z - terrainStartZ) / terrainSizeZ * alphaHeight) - alphaStartZ, 0, alphaSizeZIndexLimit);

                    int highest = 0;
                    for (int i = 0; i < alphaCount; i++)
                    {
                        if (alpha[curZ, curX, i] > alpha[curZ, curX, highest])
                        {
                            highest = i;
                        }
                    }

                    areaMap[x - template.startX_extra][z - template.startZ_extra] = alphaToArea[highest];
                }
            }

            return(areaMap);
        }
        protected Volume CollectTrees(TerrainColliderInfoAbstract terrain)
        {
            List <Bounds> treeBounds = terrain.treeData;

            if (treeBounds == null || treeBounds.Count == 0)
            {
                return(null);
            }

            //Vector3[] trs;
            //int[] ind;
            //GenerateTreesMesh(treeBounds, out trs, out ind);


            //Debuger_K.AddMesh(trs, ind, new Color(1, 0, 0, 0.1f));

            Area   defaultArea = PathFinder.getDefaultArea;
            Volume treeVolume  = new Volume(template.lengthX_extra, template.lengthZ_extra, defaultArea);

            treeVolume.terrain = true;
            treeVolume.trees   = true;

            Bounds chunkBounds = template.chunkOffsetedBounds;

            int l = fancyVerts.Length;

            Vector3[] treeBuffer = new Vector3[l];

            foreach (var bound in treeBounds)
            {
                if (!chunkBounds.Intersects(bound))
                {
                    continue;
                }

                Matrix4x4 m = Matrix4x4.TRS(bound.center, Quaternion.identity, new Vector3(bound.size.x, bound.size.y * 0.5f, bound.size.z));

                for (int i = 0; i < l; i++)
                {
                    treeBuffer[i] = m.MultiplyPoint3x4(fancyVerts[i]);
                }

#if UNITY_EDITOR
                if (Debuger_K.doDebug && Debuger_K.debugOnlyNavMesh == false)
                {
                    Debuger_K.AddTreeCollider(template.gridPosX, template.gridPosZ, template.properties, new Bounds(bound.center, bound.extents), treeBuffer, fancyTris);
                }
#endif

                for (int tris = 0; tris < fancyTris.Length; tris += 3)
                {
                    base.RasterizeTriangle(
                        treeVolume,
                        treeBuffer[fancyTris[tris]],
                        treeBuffer[fancyTris[tris + 1]],
                        treeBuffer[fancyTris[tris + 2]],
                        template.voxelSize,
                        template.startX_extra, template.endX_extra,
                        template.startZ_extra, template.endZ_extra,
                        defaultArea,
                        Passability.Unwalkable,
                        VoxelState.Terrain,
                        VoxelState.Tree);
                }
            }
            treeVolume.SetVolumeMinimum(-1000f);
            treeVolume.dead = true;
            return(treeVolume);
        }