/// <summary>
        /// TODO: This is a very complicated method. Is there a way to move towards componentisation?
        /// TODO: Layer filter method should be able to include/exclude arbitrary numbers of layers (currently it is all or one)
        /// Generally it doesn't make sense to apply only one component for a given layer. While partial recalculation
        /// might be possible, it doesn't currently exist. So when we recalcualte one component on a layer, we also
        /// recalculate all other Components on that layer.
        /// </summary>
        /// <param name="wrapper">The wrapper to recalculate the Components for</param>
        /// <param name="layerFilter">A name filter for the layers (for recalculating a single layer)</param>
        public static void ApplyAllLayerComponents(TerrainWrapper wrapper, string layerFilter = null)
        {
            Profiler.BeginSample("ApplyallLayerComponents");

            var mappings = SortComponents(wrapper, layerFilter);

            for (int i = 0; i < mappings.Count; i++)
            {
                var layerStampMapping = mappings[i];
                for (int j = 0; j < layerStampMapping.Components.Count; j++)
                {
                    MiscUtilities.ProgressBar(String.Format("PreBake for Component {0}", layerStampMapping.Components[j].name), String.Format("{0}/{1}", j, layerStampMapping.Components.Count), j / (float)layerStampMapping.Components.Count);
                    layerStampMapping.Components[j].OnPreBake();
                }
            }

            mappings = SortComponents(wrapper, layerFilter);
            if (wrapper.Locked)
            {
                Debug.LogWarning(string.Format("Attempted to write to Terrain Wrapper {0} but it was locked.", wrapper.name), wrapper);
            }
            else
            {
                bool anyLayerWrittenTo = false;
                // Okay, we've organised our Components in such a way so we can iterate through and execute them.
                // Iterating the mappings here is equivalent to iterating through the TerrainWrapper layers and executing all the relevant Components for each layer.
                for (int i = 0; i < mappings.Count; i++)
                {
                    var layerStampMapping = mappings[i];
                    var layer             = wrapper.GetLayer <MMTerrainLayer>(layerStampMapping.LayerName, false, true); // Is this redundant or just cautious? See line 100

                    // Here, we copy the flattened information of all layers below this layer to the current layer, to easily blend new data with old data.
                    // A somewhat naive solution, but the best I have found after trying several out.
                    wrapper.CopyCompoundToLayer(layer);

                    anyLayerWrittenTo = true;

                    if (wrapper.WriteHeights)
                    {
                        // Heights are a special type of layer, as layerComponents have the ability to compete with each other and determine who gets control of a point
                        // on the map through their height values. For this reason heights needed to be evaluated first, so winners can be determined.
                        for (int j = 0; j < layerStampMapping.Components.Count; j++)
                        {
                            MiscUtilities.ProgressBar(String.Format("Applying Heights for Component {0} : Layer {1}", layerStampMapping.Components[j].name, layer.name), String.Format("{0}/{1}", j, layerStampMapping.Components.Count), j / (float)layerStampMapping.Components.Count);
                            layerStampMapping.Components[j].ProcessHeights(wrapper, layer, j + 1);
                        }
                    }

                    // The Stencil is a critical component of componenting. Fundament It holds a dual purpose - blending
                    for (int j = 0; j < layerStampMapping.Components.Count; j++)
                    {
                        var stamp = layerStampMapping.Components[j];
                        MiscUtilities.ProgressBar(String.Format("Applying Stencil for Component {0} : Layer {1}", stamp.name, layer.name), String.Format("{0}/{1}", j, layerStampMapping.Components.Count), j / (float)layerStampMapping.Components.Count);
                        stamp.ProcessStencil(wrapper, layer, j + 1);
                    }

                    MiscUtilities.ClampStencil(layer.Stencil);

                    for (int j = 0; j < layerStampMapping.Components.Count; j++)
                    {
                        var layerComponent = layerStampMapping.Components[j];
                        var stencilKey     = j + 1;

                        if (wrapper.WriteSplats)
                        {
                            MiscUtilities.ProgressBar(String.Format("Applying Splats for Component {0} : Layer {1}", layerStampMapping.Components[j].name, layer.name), String.Format("{0}/{1}", j, layerStampMapping.Components.Count), j / (float)layerStampMapping.Components.Count);
                            layerComponent.ProcessSplats(wrapper, layer, stencilKey);
                        }

                        if (wrapper.WriteObjects)
                        {
                            MiscUtilities.ProgressBar(String.Format("Applying Objects for Component {0} : Layer {1}", layerStampMapping.Components[j].name, layer.name), String.Format("{0}/{1}", j, layerStampMapping.Components.Count), j / (float)layerStampMapping.Components.Count);
                            layerComponent.ProcessObjects(wrapper, layer, stencilKey);
                        }

                        if (wrapper.WriteTrees)
                        {
                            MiscUtilities.ProgressBar(String.Format("Applying Trees for Component {0} : Layer {1}", layerStampMapping.Components[j].name, layer.name), String.Format("{0}/{1}", j, layerStampMapping.Components.Count), j / (float)layerStampMapping.Components.Count);
                            layerComponent.ProcessTrees(wrapper, layer, stencilKey);
                        }

                        if (wrapper.WriteDetails)
                        {
                            MiscUtilities.ProgressBar(String.Format("Applying Details for Component {0} : Layer {1}", layerStampMapping.Components[j].name, layer.name), String.Format("{0}/{1}", j, layerStampMapping.Components.Count), j / (float)layerStampMapping.Components.Count);
                            layerComponent.ProcessDetails(wrapper, layer, stencilKey);
                        }

                        #if VEGETATION_STUDIO
                        if (wrapper.WriteVegetationStudio)
                        {
                            MiscUtilities.ProgressBar(String.Format("Applying Details for Component {0} : Layer {1}", layerStampMapping.Components[j].name, layer.name), String.Format("{0}/{1}", j, layerStampMapping.Components.Count), j / (float)layerStampMapping.Components.Count);
                            layerComponent.ProcessVegetationStudio(wrapper, layer, stencilKey);
                        }
                        #endif

                        layer.Dirty = false;
                    }

                    if (anyLayerWrittenTo)
                    {
                        wrapper.SetDirtyAbove(layer);
                        MiscUtilities.ColoriseStencil(layer.Stencil);
                        wrapper.ClearCompoundCache(layer);
        #if UNITY_EDITOR
                        UnityEditor.EditorUtility.SetDirty(layer);
        #endif
                        wrapper.Dirty = true;
                    }
                }
            }
            for (int i = 0; i < mappings.Count; i++)
            {
                var layerStampMapping = mappings[i];
                for (int j = 0; j < layerStampMapping.Components.Count; j++)
                {
                    layerStampMapping.Components[j].OnPostBake();
                }
            }
            MiscUtilities.ClearProgressBar();
            Profiler.EndSample();
        }