public static List <Island> generateWorld(WorldConfig config)
        {
            DebugLoggingTimer timer = new DebugLoggingTimer();

            timer.begin("generateWorld");

            // create 2d voronoi-derived graph, with centers, edges and corners
            Graph graph = generateGraph(config.seed, config.size, config.pointCount);

            timer.logEventComplete("generateGraph()");

            WorldGenElevation elevationGenerator = new WorldGenElevation(graph, config.clipPercentile);

            elevationGenerator.generateElevations();
            timer.logEventComplete("generateElevations()");

            List <Island> islands = findIslands(graph);

            Debug.Log("island count " + islands.Count);
            timer.logEventComplete("findIslands()");

            World world = new World(config.seed, config.size, graph, islands);

            timer.logEventComplete("instantiateWorld()");

            // WorldGenBiomes.separateTheLandFromTheWater(world, new PerlinIslandShape(seed, worldSize));
            return(islands);
        }
        public static List <GameObject> createIslandObjects(WorldConfig config, List <Island> islands)
        {
            DebugLoggingTimer timer = new DebugLoggingTimer();

            timer.begin("createIslandObjects");

            List <GameObject> islandObjects = new List <GameObject>(islands.Count);

            foreach (var island in islands)
            {
                timer.begin($"starting island {island.islandId}");
                // initialise gameobject
                GameObject gameObj = new GameObject();
                gameObj.name  = $"Island {island.islandId}";
                gameObj.layer = LayerMask.NameToLayer("Terrain");

                WorldGenMesh.triangulate(gameObj, config.topSideMaterial, island.centers, config.size);
                timer.logEventComplete("triangulated topside for island " + island.islandId);

                island.topsideBounds = CalculateBounds(island.center, gameObj);
                timer.logEventComplete("generated topside bounds for island " + island.islandId);

                // first pass at adding a nav mesh
                foreach (GameObject agentType in config.navAgents)
                {
                    NavMeshSurface navMeshSurface = gameObj.AddComponent <NavMeshSurface>();
                    navMeshSurface.agentTypeID       = agentType.GetComponent <NavMeshAgent>().agentTypeID;
                    navMeshSurface.overrideVoxelSize = true;
                    navMeshSurface.voxelSize         = 0.5f;
                    navMeshSurface.BuildNavMesh();
                }
                timer.logEventComplete("built NavMeshes for island " + island.islandId);

                WorldGenElevation.generateIslandUndersideElevations(config.seed, island);
                timer.logEventComplete("generated underside for island " + island.islandId);

                WorldGenMesh.triangulate(gameObj, config.undersideMaterial, island.undersideCoords, config.size);
                timer.logEventComplete("triangulated underside for island " + island.islandId);

                island.totalBounds = CalculateBounds(island.center, gameObj);
                timer.logEventComplete("generated total bounds for island " + island.islandId);

                islandObjects.Add(gameObj);
            }
            timer.end();

            return(islandObjects);
        }