public CombinedTerrainTileMesh(CombinedMeshType combinationType, int lodResolution, int lodDistance, int lodSize)
        {
            type             = combinationType;
            mesh             = new Mesh();
            mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;

            int numTiles = 0;

            if (type == CombinedMeshType.Corner)
            {
                numTiles = lodSize * lodSize;
            }
            else if (type == CombinedMeshType.Edge)
            {
                numTiles = (((lodDistance - lodSize) * 2) + 1) * lodSize;
            }
            else
            {
                numTiles = ((lodSize * 2) + 1) * ((lodSize * 2) + 1);
            }

            int numVertices  = ((lodResolution + 1) * (lodResolution + 1)) * numTiles;
            int numTriangles = lodResolution * lodResolution * 2 * numTiles;

            vertices  = new List <Vector3>(numVertices);
            normals   = new List <Vector3>(numVertices);
            uvs       = new List <Vector2>(numVertices);
            triangles = new List <int>(numTriangles);
        }
        // Start is called before the first frame update
        void Start()
        {
            // Initialise variables
            tileSize          = size / numTiles;
            prevPlayerTilePos = Vector2Int.one * int.MaxValue;
            map = new Map(mapSeed, size, numTiles, tileResolution, heightmapProvider);

            // Create mesh renderers and filters
            int numLODs = lodDistances.Length;

            lodGameObjects          = new List <GameObject> [numLODs];
            tileMeshes              = new TerrainTileMesh[numTiles, numTiles];
            tileLODs                = new int[numTiles, numTiles];
            tileEdgeTransitionFlags = new int[numTiles, numTiles];
            lodMeshes               = new List <CombinedTerrainTileMesh> [numLODs];
            meshRenderers           = new List <MeshRenderer> [numLODs];
            meshFilters             = new List <MeshFilter> [numLODs];

            // Create LOD meshes
            for (int i = 0; i < numLODs; i++)
            {
                lodGameObjects[i] = new List <GameObject>(8);
                lodMeshes[i]      = new List <CombinedTerrainTileMesh>(8);
                meshRenderers[i]  = new List <MeshRenderer>(8);
                meshFilters[i]    = new List <MeshFilter>(8);

                for (int m = 0; m < 8; m++)
                {
                    lodGameObjects[i].Add(new GameObject());
                    lodGameObjects[i][m].transform.parent = transform;
                    lodGameObjects[i][m].name             = "LOD " + i + " mesh " + m;
                    lodGameObjects[i][m].layer            = LayerMask.NameToLayer(terrainLayer);

                    CombinedMeshType meshType = CombinedMeshType.Corner;

                    if (i == 0)
                    {
                        meshType = CombinedMeshType.Center;
                    }
                    else if (m > 3)
                    {
                        meshType = CombinedMeshType.Edge;
                    }

                    int prevLODDistance = (i == 0) ? 0 : lodDistances[i - 1];

                    lodMeshes[i].Add(new CombinedTerrainTileMesh(meshType, tileResolution / MathUtilities.Pow(2, i), lodDistances[i], Mathf.Max(0, lodDistances[i] - prevLODDistance)));

                    meshRenderers[i].Add(lodGameObjects[i][m].AddComponent(typeof(MeshRenderer)) as MeshRenderer);
                    meshRenderers[i][m].sharedMaterial = terrainMaterial;

                    meshFilters[i].Add(lodGameObjects[i][m].AddComponent(typeof(MeshFilter)) as MeshFilter);
                    meshFilters[i][m].mesh = lodMeshes[i][m].mesh;
                }
            }

            // Create tile objects
            for (int x = 0; x < numTiles; x++)
            {
                for (int z = 0; z < numTiles; z++)
                {
                    tileLODs[x, z]   = -1;
                    tileMeshes[x, z] = new TerrainTileMesh(tileResolution);
                }
            }

            // Initialise heightmap provider
            heightmapProvider.Init(mapSeed, size);

            // Start mesh updater thread
            ThreadStart MeshUpdaterThreadStart = MeshUpdateThread;

            meshUpdaterThread      = new Thread(MeshUpdaterThreadStart);
            meshUpdateThreadStatus = (int)MeshUpdateThreadStatus.Idle;
            meshUpdaterThread.Start();
        }