public static void Generate(GrindSurface surface, ColliderGenerationSettings collider_generation_settings = null)
    {
        IEnumerator routine()
        {
            var original_rotation = surface.transform.rotation;

            surface.transform.rotation = Quaternion.identity;

            yield return(null);

            settings = collider_generation_settings;

            // build a list of vertexes from child objects that are valid potential grindable surfaces
            // do a set offset sphere checks to see if we have open space in any cardinal directions

            vertices.Clear();
            vertexScores.Clear();
            endPoints.Clear();
            blockedPoints.Clear();
            activeSplinePoints.Clear();

            foreach (var m in surface.GetComponentsInChildren <MeshFilter>())
            {
                for (int i = 0; i < m.sharedMesh.vertexCount; i++)
                {
                    if (vertices.Count > MaxVertices)
                    {
                        break;
                    }

                    if (IsValidPotentialVertex(surface.transform, m, i, out var w, out var score))
                    {
                        if (vertices.Contains(w) == false)
                        {
                            vertices.Add(w);
                            vertexScores.Add(score);
                        }
                    }
                }
            }

            vertices = vertices.OrderByDescending(v => vertexScores[vertices.IndexOf(v)]).ToList();

            Debug.Log($"Found {vertices.Count} potential valid vertices in child meshes.");

            // start a grind spline by picking a valid vertex
            // find the nearest valid vert and add that, repeat until there are no valid verts left

            var start         = vertices[0];
            var active_spline = CreateSpline(surface, start, collider_generation_settings);
            var current_point = start;
            var current_index = 0;

            vertices.RemoveAt(0);

            endPoints.Add(start);

            AddSplinePoint(active_spline, start);

            while (active_spline != null)
            {
                RefreshSearchList();

                // if ran out of verts to use, we're done

                if (searchList.Count == 0 || (searchList.Count == 1 && searchList[0] == current_point))
                {
                    break;
                }

                // find nearest vert for our next spline point

                var previous_point = current_index > 0 ? active_spline.PointsContainer.GetChild(current_index - 1) : null;

                if (TryGetNextValidPoint(surface, out var next_point, current_point, previous_point?.position))
                {
                    if (vertices.Contains(next_point))
                    {
                        vertices.Remove(next_point);
                    }

                    AddSplinePoint(active_spline, next_point);

                    current_point = next_point;
                    current_index++;
                }
    public static void Generate(GrindSurface surface)
    {
        // build a list of vertexes from child objects that are valid potential grindable surfaces
        // do a set offset sphere checks to see if we have open space in any cardinal directions

        vertices.Clear();
        endPoints.Clear();
        blockedPoints.Clear();
        activeSplinePoints.Clear();

        foreach (var m in surface.GetComponentsInChildren <MeshFilter>())
        {
            foreach (var v in m.sharedMesh.vertices.Distinct())
            {
                var w = m.transform.TransformPoint(v);

                if (IsValidPotentialVertex(w))
                {
                    vertices.Add(w);
                }
            }
        }

        Debug.Log($"Found {vertices.Count} potential valid vertices in child meshes.");

        // start a grind spline by picking a valid vertex
        // find the nearest valid vert and add that, repeat until there are no valid verts left

        var start         = vertices[0];
        var active_spline = CreateSpline(surface, start);
        var current_point = start;
        var current_index = 0;

        vertices.RemoveAt(0);

        endPoints.Add(start);

        AddSplinePoint(active_spline, start);

        while (active_spline != null)
        {
            RefreshSearchList();

            // if ran out of verts to use, we're done

            if (searchList.Count == 0 || (searchList.Count == 1 && searchList[0] == current_point))
            {
                break;
            }

            // find nearest vert for our next spline point

            var previous_point = current_index > 0 ? active_spline.transform.GetChild(current_index - 1) : null;

            if (TryGetNextValidPoint(surface, out var next_point, current_point, previous_point?.position))
            {
                if (vertices.Contains(next_point))
                {
                    vertices.Remove(next_point);
                }

                AddSplinePoint(active_spline, next_point);

                current_point = next_point;
                current_index++;
            }