public void ResetLinkedVoxelSpans()
        {
            int len = width * depth;

            LinkedVoxelSpan df = new LinkedVoxelSpan(InvalidSpanValue, InvalidSpanValue, -1, -1);

            linkedSpans.ResizeUninitialized(len);
            linkedCellMinMax.Resize(len, NativeArrayOptions.UninitializedMemory);
            for (int i = 0; i < len; i++)
            {
                linkedSpans[i]      = df;
                linkedCellMinMax[i] = new CellMinMax {
                    objectID = -1,
                    min      = 0,
                    max      = 0,
                };
            }
            removedStack.Clear();
        }
        public void AddLinkedSpan(int index, uint bottom, uint top, int area, int voxelWalkableClimb, int objectID)
        {
            var minmax = linkedCellMinMax[index];

            if (minmax.objectID != objectID)
            {
                linkedCellMinMax[index] = new CellMinMax {
                    objectID = objectID,
                    min      = bottom,
                    max      = top,
                };
            }
            else
            {
                minmax.min = math.min(minmax.min, bottom);
                minmax.max = math.max(minmax.max, top);
                linkedCellMinMax[index] = minmax;
            }

            // linkedSpans[index] is the span with the lowest y-coordinate at the position x,z such that index=x+z*width
            // i.e linkedSpans is a 2D array laid out in a 1D array (for performance and simplicity)

            // Check if there is a root span, otherwise we can just add a new (valid) span and exit
            if (linkedSpans[index].bottom == InvalidSpanValue)
            {
                linkedSpans[index] = new LinkedVoxelSpan(bottom, top, area);
                return;
            }

            int prev = -1;

            // Original index, the first span we visited
            int oindex = index;

            while (index != -1)
            {
                var current = linkedSpans[index];
                if (current.bottom > top)
                {
                    // If the current span's bottom higher up than the span we want to insert's top, then they do not intersect
                    // and we should just insert a new span here
                    break;
                }
                else if (current.top < bottom)
                {
                    // The current span and the span we want to insert do not intersect
                    // so just skip to the next span (it might intersect)
                    prev  = index;
                    index = current.next;
                }
                else
                {
                    // Intersection! Merge the spans

                    // voxelWalkableClimb is flagMergeDistance, when a walkable flag is favored before an unwalkable one
                    // So if a walkable span intersects an unwalkable span, the walkable span can be up to voxelWalkableClimb
                    // below the unwalkable span and the merged span will still be walkable
                    if (math.abs((int)top - (int)current.top) <= voxelWalkableClimb)
                    {
                        // linkedSpans[index] is the lowest span, but we might use that span's area anyway if it is walkable
                        area = math.max(area, current.area);
                    }
                    else
                    {
                        // Pick the area from the topmost span
                        if (top < current.top)
                        {
                            area = current.area;
                        }
                    }

                    // Find the new bottom and top for the merged span
                    bottom = math.min(current.bottom, bottom);
                    top    = math.max(current.top, top);

                    // Find the next span in the linked list
                    int next = current.next;
                    if (prev != -1)
                    {
                        // There is a previous span
                        // Remove this span from the linked list
                        // TODO: Kinda slow. Check what asm is generated.
                        var p = linkedSpans[prev];
                        p.next            = next;
                        linkedSpans[prev] = p;

                        // Add this span index to a list for recycling
                        PushToSpanRemovedStack(index);

                        // Move to the next span in the list
                        index = next;
                    }
                    else if (next != -1)
                    {
                        // This was the root span and there is a span left in the linked list
                        // Remove this span from the linked list by assigning the next span as the root span
                        linkedSpans[oindex] = linkedSpans[next];

                        // Recycle the old span index
                        PushToSpanRemovedStack(next);

                        // Move to the next span in the list
                        // NOP since we just removed the current span, the next span
                        // we want to visit will have the same index as we are on now (i.e oindex)
                    }
                    else
                    {
                        // This was the root span and there are no other spans in the linked list
                        // Just replace the root span with the merged span and exit
                        linkedSpans[oindex] = new LinkedVoxelSpan(bottom, top, area);
                        return;
                    }
                }
            }

            // We now have a merged span that needs to be inserted
            // and connected with the existing spans

            // The new merged span will be inserted right after 'prev' (if it exists, otherwise before index)

            // Take a node from the recycling stack if possible
            // Otherwise create a new node (well, just a new index really)
            int nextIndex;

            if (removedStack.Length > 0)
            {
                // Pop
                nextIndex = removedStack[removedStack.Length - 1];
                removedStack.RemoveAtSwapBack(removedStack.Length - 1);
            }
            else
            {
                nextIndex = linkedSpans.Length;
                linkedSpans.Resize(linkedSpans.Length + 1, NativeArrayOptions.UninitializedMemory);
            }

            if (prev != -1)
            {
                linkedSpans[nextIndex] = new LinkedVoxelSpan(bottom, top, area, linkedSpans[prev].next);
                // TODO: Check asm
                var p = linkedSpans[prev];
                p.next            = nextIndex;
                linkedSpans[prev] = p;
            }
            else
            {
                linkedSpans[nextIndex] = linkedSpans[oindex];
                linkedSpans[oindex]    = new LinkedVoxelSpan(bottom, top, area, nextIndex);
            }
        }