public static bool SaveTemplate
        (
            LBLandscape landscape,
            string LBEditorVersion,
            string landscapeTemplateName,
            ref bool isSceneSaveRequired,
            bool createTemplatePackage,
            bool addMapTexturesToTemplatePackage,
            bool addLayerHeightmapTexturesToTemplatePackage,
            bool addLBLightingToTemplate,
            bool addPathsToTemplate,
            bool addStencilsToTemplate,
            bool addPathMeshMaterialsToTemplate
        )
        {
            bool isSuccessful = false;

            string landscapeName = landscape.name;

            // Create a new gameobject in the scene hierarchy that we can turn into a prefab
            GameObject newTemplateObj = new GameObject(landscapeName + " template");

            if (newTemplateObj == null)
            {
                Debug.LogWarning("Landscape Builder - could not create temporary gameobject for " + landscapeName + " template");
            }
            else
            {
                LBTemplate lbTemplate = newTemplateObj.AddComponent <LBTemplate>();
                if (lbTemplate == null)
                {
                    Debug.LogWarning("Landscape Builder - could not add LBTemplate component " + landscapeName + " template");
                    GameObject.DestroyImmediate(newTemplateObj);
                }
                else
                {
                    // This is the installed version of LB when the template was created
                    lbTemplate.LBVersion = LBEditorVersion;
                    // This is the version of the landscape when the template was created
                    lbTemplate.LastUpdatedVersion = landscape.LastUpdatedVersion;

                    // The version of Unity that created this template
                    lbTemplate.templateUnityVersion = Application.unityVersion;

                    lbTemplate.useLegacyNoiseOffset = landscape.useLegacyNoiseOffset;

                    // Name of the landscape game object
                    lbTemplate.landscapeName = landscapeName;
                    lbTemplate.size          = landscape.size;
                    lbTemplate.start         = landscape.start;

                    // Landscape terrain settings
                    Vector3 terrainSize3D = landscape.GetLandscapeTerrainSize();
                    lbTemplate.heightmapResolution       = landscape.GetLandscapeTerrainHeightmapResolution();
                    lbTemplate.terrainWidth              = terrainSize3D.x;
                    lbTemplate.terrainHeight             = terrainSize3D.y;
                    lbTemplate.pixelError                = landscape.GetLandscapeTerrainPixelError();
                    lbTemplate.baseMapDistance           = landscape.GetLandscapeTerrainBaseMapDist();
                    lbTemplate.alphaMapResolution        = landscape.GetLandscapeTerrainAlphaMapResolution();
                    lbTemplate.baseTextureResolution     = landscape.GetLandscapeTerrainBaseTextureResolution();
                    lbTemplate.treeDistance              = landscape.GetLandscapeTerrainTreeDistance();
                    lbTemplate.treeBillboardDistance     = landscape.GetLandscapeTerrainTreeBillboardStart();
                    lbTemplate.detailDistance            = landscape.GetLandscapeTerrainDetailDistance();
                    lbTemplate.detailDensity             = landscape.GetLandscapeTerrainDetailDensity();
                    lbTemplate.detailResolution          = landscape.GetLandscapeTerrainDetailResolution();
                    lbTemplate.treeFadeDistance          = landscape.GetLandscapeTerrainTreeFadeLength();
                    lbTemplate.grassWindSpeed            = landscape.GetLandscapeTerrainGrassWindSpeed();
                    lbTemplate.grassWindRippleSize       = landscape.GetLandscapeTerrainGrassWindRippleSize();
                    lbTemplate.grassWindBending          = landscape.GetLandscapeTerrainGrassWindBending();
                    lbTemplate.grassWindTint             = landscape.GetLandscapeTerrainGrassWindTint();
                    lbTemplate.terrainLegacySpecular     = landscape.GetLandscapeTerrainLegacySpecular();
                    lbTemplate.terrainLegacyShininess    = landscape.GetLandscapeTerrainLegacyShininess();
                    lbTemplate.useTerrainDrawInstanced   = landscape.GetLandscapeTerrainDrawInstanced();
                    lbTemplate.useTerrainPerPixelNormals = GetTerrainPerPixelNormals(landscape);
                    lbTemplate.terrainGroupingID         = landscape.GetLandscapeTerrainGroupingID();
                    lbTemplate.terrainAutoConnect        = landscape.GetLandscapeTerrainAutoConnect();

                    // Synchronize with a duplicate enum in lbTemplate
                    lbTemplate.terrainMaterialType = (LBTemplate.TerrainMaterialType)landscape.GetTerrainMaterialType();

                    // Check if any lists are null
                    if (landscape.topographyLayersList == null)
                    {
                        landscape.topographyLayersList = new List <LBLayer>();
                    }
                    if (landscape.terrainTexturesList == null)
                    {
                        landscape.terrainTexturesList = new List <LBTerrainTexture>();
                    }
                    if (landscape.terrainTreesList == null)
                    {
                        landscape.terrainTreesList = new List <LBTerrainTree>();
                    }
                    if (landscape.terrainGrassList == null)
                    {
                        landscape.terrainGrassList = new List <LBTerrainGrass>();
                    }
                    if (landscape.lbGroupList == null)
                    {
                        landscape.lbGroupList = new List <LBGroup>();
                    }
                    if (landscape.landscapeMeshList == null)
                    {
                        landscape.landscapeMeshList = new List <LBLandscapeMesh>();
                    }
                    if (landscape.landscapeWaterList == null)
                    {
                        landscape.landscapeWaterList = new List <LBWater>();
                    }

                    // Update texture names to help detect missing textures when importing templates into another project
                    for (int txIdx = 0; txIdx < landscape.terrainTexturesList.Count; txIdx++)
                    {
                        // Only attempt to update the textureName if it is null or an empty string.
                        // This avoids loosing details about an already missing texture
                        if (string.IsNullOrEmpty(landscape.terrainTexturesList[txIdx].textureName))
                        {
                            if (landscape.terrainTexturesList[txIdx].texture != null)
                            {
                                landscape.terrainTexturesList[txIdx].textureName = landscape.terrainTexturesList[txIdx].texture.name;
                                isSceneSaveRequired = true;
                            }
                        }

                        // Only attempt to update the normalMapName if it is null or an empty string.
                        // This avoids loosing details about an already missing normalMap
                        if (string.IsNullOrEmpty(landscape.terrainTexturesList[txIdx].normalMapName))
                        {
                            if (landscape.terrainTexturesList[txIdx].normalMap != null)
                            {
                                landscape.terrainTexturesList[txIdx].normalMapName = landscape.terrainTexturesList[txIdx].normalMap.name;
                                isSceneSaveRequired = true;
                            }
                        }
                    }

                    // Update Grass texture names to help detect missing textures when importing templates into another project
                    for (int grIdx = 0; grIdx < landscape.terrainGrassList.Count; grIdx++)
                    {
                        // Only attempt to update the grass textureName if it is null or an empty string.
                        // This avoids loosing details about an already missing grass texture
                        if (string.IsNullOrEmpty(landscape.terrainGrassList[grIdx].textureName))
                        {
                            if (landscape.terrainGrassList[grIdx].texture != null)
                            {
                                landscape.terrainGrassList[grIdx].textureName = landscape.terrainGrassList[grIdx].texture.name;
                                isSceneSaveRequired = true;
                            }
                        }

                        // Only attempt to update the grass meshPrefName if it is null or an empty string.
                        // This avoids loosing details about an already missing grass mesh prefab
                        if (string.IsNullOrEmpty(landscape.terrainGrassList[grIdx].meshPrefabName))
                        {
                            if (landscape.terrainGrassList[grIdx].meshPrefab != null)
                            {
                                landscape.terrainGrassList[grIdx].meshPrefabName = landscape.terrainGrassList[grIdx].meshPrefab.name;
                                isSceneSaveRequired = true;
                            }
                        }
                    }

                    // Update Tree prefab names to help detect missing prefabs when importing templates into another project
                    for (int trIdx = 0; trIdx < landscape.terrainTreesList.Count; trIdx++)
                    {
                        // Only attempt to update the tree prefabName if it is null or an empty string.
                        // This avoids loosing details about an already missing tree prefab
                        if (string.IsNullOrEmpty(landscape.terrainTreesList[trIdx].prefabName))
                        {
                            if (landscape.terrainTreesList[trIdx].prefab != null)
                            {
                                landscape.terrainTreesList[trIdx].prefabName = landscape.terrainTreesList[trIdx].prefab.name;
                                isSceneSaveRequired = true;
                            }
                        }
                    }

                    // Update Mesh prefab names to help detect missing prefabs when importing templates into another project
                    for (int meshIdx = 0; meshIdx < landscape.landscapeMeshList.Count; meshIdx++)
                    {
                        // Only attempt to update the mesh prefabName if it is null or an empty string.
                        // This avoids loosing details about an already missing mesh prefab
                        if (string.IsNullOrEmpty(landscape.landscapeMeshList[meshIdx].prefabName))
                        {
                            if (landscape.landscapeMeshList[meshIdx].prefab != null)
                            {
                                landscape.landscapeMeshList[meshIdx].prefabName = landscape.landscapeMeshList[meshIdx].prefab.name;
                                isSceneSaveRequired = true;
                            }
                        }
                    }

                    int numGroups = landscape.lbGroupList == null ? 0 : landscape.lbGroupList.Count;

                    // Update Group Member prefab names to help detect missing prefabs when importing templates into another project
                    for (int grpIdx = 0; grpIdx < numGroups; grpIdx++)
                    {
                        if (landscape.lbGroupList[grpIdx].groupMemberList != null)
                        {
                            List <LBGroupMember> groupMemberList = landscape.lbGroupList[grpIdx].groupMemberList;
                            for (int grpMbrIdx = 0; grpMbrIdx < groupMemberList.Count; grpMbrIdx++)
                            {
                                // Only attempt to update the prefab prefabName if it is null or an empty string.
                                // This avoids loosing details about an already missing prefab
                                if (string.IsNullOrEmpty(groupMemberList[grpMbrIdx].prefabName))
                                {
                                    if (groupMemberList[grpMbrIdx].prefab != null)
                                    {
                                        groupMemberList[grpMbrIdx].prefabName = groupMemberList[grpMbrIdx].prefab.name;
                                        isSceneSaveRequired = true;
                                    }
                                }
                            }
                        }
                    }

                    // Landscape class lists - perform deep copy (#SMS 2.0.6 Beta 6f)
                    // Attempts to avoid issue where a template prefab is created (and later deleted) which could delete data
                    // from the landscape meta-data in the scene.
                    lbTemplate.topographyLayersList = landscape.topographyLayersList.ConvertAll(lyr => new LBLayer(lyr));
                    lbTemplate.terrainTexturesList  = landscape.terrainTexturesList.ConvertAll(tt => new LBTerrainTexture(tt));
                    lbTemplate.terrainTreesList     = landscape.terrainTreesList.ConvertAll(tt => new LBTerrainTree(tt));
                    lbTemplate.terrainGrassList     = landscape.terrainGrassList.ConvertAll(tg => new LBTerrainGrass(tg));
                    lbTemplate.lbGroupList          = landscape.lbGroupList.ConvertAll(grp => new LBGroup(grp));
                    lbTemplate.landscapeMeshList    = landscape.landscapeMeshList.ConvertAll(msh => new LBLandscapeMesh(msh));
                    lbTemplate.landscapeWaterList   = landscape.landscapeWaterList.ConvertAll(wtr => new LBWater(wtr, false));

                    // Check for surface and/or base mesh materials in Group Object Paths
                    for (int grpIdx = 0; grpIdx < numGroups; grpIdx++)
                    {
                        int numGrpMembers = landscape.lbGroupList[grpIdx].groupMemberList == null ? 0 : landscape.lbGroupList[grpIdx].groupMemberList.Count;

                        for (int grpMbrIdx = 0; grpMbrIdx < numGrpMembers; grpMbrIdx++)
                        {
                            LBGroupMember _lbGroupMember = landscape.lbGroupList[grpIdx].groupMemberList[grpMbrIdx];
                            // A deep copy will attempt create a new instance of the material using our LBGroupMember clone constructor
                            // In this case we need to reference the actual material in the project folder.
                            // If the Object Path was a duplicate of an existing Object Path, then this may also fail.
                            if (_lbGroupMember != null && _lbGroupMember.lbMemberType == LBGroupMember.LBMemberType.ObjPath && _lbGroupMember.lbObjPath != null)
                            {
                                lbTemplate.lbGroupList[grpIdx].groupMemberList[grpMbrIdx].lbObjPath.surfaceMeshMaterial = _lbGroupMember.lbObjPath.surfaceMeshMaterial;
                                lbTemplate.lbGroupList[grpIdx].groupMemberList[grpMbrIdx].lbObjPath.baseMeshMaterial    = _lbGroupMember.lbObjPath.baseMeshMaterial;
                            }
                        }
                    }

                    // Final Pass varibles
                    lbTemplate.useFinalPassSmoothing        = landscape.useFinalPassSmoothing;
                    lbTemplate.finalPassSmoothingIterations = landscape.finalPassSmoothingIterations;
                    lbTemplate.finalPassPixelRange          = landscape.finalPassPixelRange;
                    lbTemplate.fPassSmoothStencilGUID       = landscape.fPassSmoothStencilGUID;
                    lbTemplate.fPassSmoothStencilLayerGUID  = landscape.fPassSmoothStencilLayerGUID;
                    lbTemplate.fPassSmoothFilterMode        = landscape.fPassSmoothFilterMode;

                    lbTemplate.thermalErosionPreset           = landscape.thermalErosionPreset;
                    lbTemplate.useThermalErosion              = landscape.useThermalErosion;
                    lbTemplate.thermalErosionIterations       = landscape.thermalErosionIterations;
                    lbTemplate.thermalErosionTalusAngle       = landscape.thermalErosionTalusAngle;
                    lbTemplate.thermalErosionStrength         = landscape.thermalErosionStrength;
                    lbTemplate.fPassThErosionStencilGUID      = landscape.fPassThErosionStencilGUID;
                    lbTemplate.fPassThErosionStencilLayerGUID = landscape.fPassThErosionStencilLayerGUID;
                    lbTemplate.fPassThErosionFilterMode       = landscape.fPassThErosionFilterMode;

                    // Group Settings
                    lbTemplate.autoRefreshGroupDesigner = landscape.autoRefreshGroupDesigner;

                    // Vegetation Integration variables
                    lbTemplate.useVegetationSystem         = landscape.useVegetationSystem;
                    lbTemplate.useVegetationSystemTextures = landscape.useVegetationSystemTextures;

                    // Landscape Extension
                    lbTemplate.useLandscapeExtension = landscape.useLandscapeExtension;
                    if (landscape.lbLandscapeExtension != null)
                    {
                        lbTemplate.lbLandscapeExtension = new LBLandscapeExtension(landscape.lbLandscapeExtension);
                    }
                    else
                    {
                        lbTemplate.lbLandscapeExtension = new LBLandscapeExtension();
                    }

                    // GPU acceleration
                    lbTemplate.useGPUTexturing  = landscape.useGPUTexturing;
                    lbTemplate.useGPUTopography = landscape.useGPUTopography;
                    lbTemplate.useGPUGrass      = landscape.useGPUGrass;
                    lbTemplate.useGPUPath       = landscape.useGPUPath;

                    // Undo override
                    lbTemplate.isUndoTopographyDisabled = landscape.isUndoTopographyDisabled;

                    // Topography Mask - there is one per landscape
                    lbTemplate.topographyMaskMode     = (LBTemplate.MaskMode)landscape.topographyMaskMode;
                    lbTemplate.distanceToCentreMask   = landscape.distanceToCentreMask;
                    lbTemplate.maskWarpAmount         = landscape.maskWarpAmount;
                    lbTemplate.maskNoiseTileSize      = landscape.maskNoiseTileSize;
                    lbTemplate.maskNoiseOffsetX       = landscape.maskNoiseOffsetX;
                    lbTemplate.maskNoiseOffsetY       = landscape.maskNoiseOffsetY;
                    lbTemplate.maskNoiseCurveModifier = landscape.maskNoiseCurveModifier;

                    // Does user wish to include LBLighting?
                    if (addLBLightingToTemplate)
                    {
                        // Only include LBLighting if it is in the scene
                        LBLighting lbLighting = GameObject.FindObjectOfType <LBLighting>();
                        if (lbLighting == null)
                        {
                            lbTemplate.isLBLightingIncluded = false;
                            Debug.LogWarning("Landscape Builder - Export Template - No LBLighting found in the scene");
                        }
                        else
                        {
                            lbTemplate.isLBLightingIncluded = true;
                            lbTemplate.AddLBLightingSettings(lbLighting);
                        }
                    }
                    else
                    {
                        lbTemplate.isLBLightingIncluded = false;
                    }

                    // Create an empty list of Asset Paths for the mesh materials
                    List <string> lbMapPathMaterialAssetPathList = new List <string>();

                    if (addPathsToTemplate)
                    {
                        // Find any Camera Paths in this landscape (changed from all in scene in 1.3.2 Beta 9b)
                        List <LBCameraPath> lbCameraPathList = LBCameraPath.GetCameraPathsInLandscape(landscape);
                        if (lbCameraPathList != null)
                        {
                            // Get the LBPath from each LBCameraPath and add it to the LBTemplate instance
                            foreach (LBCameraPath lbCameraPath in lbCameraPathList)
                            {
                                if (lbCameraPath.lbPath != null)
                                {
                                    // Update the path name before adding to the template
                                    if (lbCameraPath.gameObject != null)
                                    {
                                        lbCameraPath.lbPath.pathName = lbCameraPath.gameObject.name;
                                        isSceneSaveRequired          = true;
                                    }
                                    lbTemplate.lbPathList.Add(lbCameraPath.lbPath);
                                }
                            }
                        }

                        // Find all MapPaths in the this landscape
                        List <LBMapPath> lbMapPathList = LBMapPath.GetMapPathsInLandscape(landscape);
                        if (lbMapPathList != null)
                        {
                            // Get the LBPath from each LBMapPath and add it to the LBTemplate instance
                            foreach (LBMapPath lbMapPath in lbMapPathList)
                            {
                                if (lbMapPath.lbPath != null)
                                {
                                    // Update the path name before adding to the template
                                    if (lbMapPath.gameObject != null)
                                    {
                                        lbMapPath.lbPath.pathName = lbMapPath.gameObject.name;

                                        // Check for a mesh
                                        if (lbMapPath.lbPath.lbMesh != null && addPathMeshMaterialsToTemplate)
                                        {
                                            lbMapPath.lbPath.meshTempMaterial = lbMapPath.meshMaterial;

                                            // If also creating a package, remember the asset path for this mesh material
                                            if (createTemplatePackage)
                                            {
                                                string mapPathMatAssetPath = UnityEditor.AssetDatabase.GetAssetPath(lbMapPath.meshMaterial);
                                                if (!string.IsNullOrEmpty(mapPathMatAssetPath))
                                                {
                                                    lbMapPathMaterialAssetPathList.Add(mapPathMatAssetPath);
                                                }
                                            }
                                        }
                                        else
                                        {
                                            lbMapPath.lbPath.meshTempMaterial = null;
                                        }

                                        isSceneSaveRequired = true;
                                    }
                                    lbTemplate.lbPathList.Add(lbMapPath.lbPath);
                                }
                            }
                        }
                    }

                    if (addStencilsToTemplate)
                    {
                        List <LBStencil> lbStencilList = LBStencil.GetStencilsInLandscape(landscape, true);
                        if (lbTemplate.lbTemplateStencilList == null)
                        {
                            lbTemplate.lbTemplateStencilList = new List <LBTemplateStencil>();
                        }

                        if (lbTemplate.lbTemplateStencilList != null && lbStencilList != null)
                        {
                            // Create a LBTemplateStencil for each Stencil in the landscape, and add it to the Template.
                            // NOTE Does not copy the USHORT layerArray or render textures in the Stencil Layers as we want to keep
                            // the Template as small as possible.
                            foreach (LBStencil lbStencil in lbStencilList)
                            {
                                if (lbStencil != null)
                                {
                                    LBTemplateStencil lbTemplateStencil = new LBTemplateStencil(lbStencil);
                                    if (lbTemplateStencil != null)
                                    {
                                        lbTemplate.lbTemplateStencilList.Add(lbTemplateStencil);
                                    }
                                }
                            }
                        }
                    }

                    // Create template folders if they don't already exist
                    LBEditorHelper.CheckFolder("Assets/LandscapeBuilder/Templates");

                    if (!Directory.Exists("LandscapeBuilder/TemplatePackages"))
                    {
                        Directory.CreateDirectory("LandscapeBuilder/TemplatePackages");
                    }

                    // Create a prefab
                    bool   continueToSave    = false;
                    string templateFullPath  = Application.dataPath + "/LandscapeBuilder/Templates/" + landscapeTemplateName + ".prefab";
                    string templateAssetPath = "Assets/LandscapeBuilder/Templates/" + landscapeTemplateName + ".prefab";
                    if (File.Exists(templateFullPath))
                    {
                        if (EditorUtility.DisplayDialog("Template Already Exists", "Are you sure you want to save the template? The currently existing" +
                                                        " template will be lost.", "Overwrite", "Cancel"))
                        {
                            if (!AssetDatabase.DeleteAsset(templateAssetPath))
                            {
                                Debug.LogWarning("Landscape Builder - could not overwrite Assets/LandscapeBuilder/Templates/" + landscapeTemplateName + " for " + landscapeName + " template");
                            }
                            else
                            {
                                continueToSave = true;
                            }
                        }
                    }
                    else
                    {
                        continueToSave = true;
                    }

                    if (continueToSave)
                    {
                        #if UNITY_2018_3_OR_NEWER
                        GameObject templatePrefabGO = PrefabUtility.SaveAsPrefabAsset(newTemplateObj, templateAssetPath);
                        #else
                        GameObject templatePrefabGO = PrefabUtility.CreatePrefab(templateAssetPath, newTemplateObj);
                        #endif

                        if (templatePrefabGO != null && createTemplatePackage)
                        {
                            // Always include the template prefab (this is meta-data only)
                            List <string> templateAssetPaths = new List <string>();
                            templateAssetPaths.Add(templateAssetPath);

                            // Although technically users could include 3rd party textures in a LBMap texture, they are MUCH more likely to use
                            // map textures generated from within Landscape Builder.
                            if (addMapTexturesToTemplatePackage)
                            {
                                List <string> uniqueMapTexPaths = LBLandscapeOperations.GetMapTextureAssetPathsFromLandscape(landscape, true);
                                if (uniqueMapTexPaths != null)
                                {
                                    if (uniqueMapTexPaths.Count > 0)
                                    {
                                        templateAssetPaths.AddRange(uniqueMapTexPaths);
                                    }
                                }
                            }

                            if (addLayerHeightmapTexturesToTemplatePackage)
                            {
                                // Get a list of the image-based topography layers with a heightmap texture
                                List <LBLayer> layerList = landscape.topographyLayersList.FindAll(lyr => lyr.heightmapImage != null && (lyr.type == LBLayer.LayerType.ImageBase || lyr.type == LBLayer.LayerType.ImageAdditive || lyr.type == LBLayer.LayerType.ImageSubtractive || lyr.type == LBLayer.LayerType.ImageDetail));
                                if (layerList != null)
                                {
                                    //Debug.Log("Save Template found " + layerList.Count + " image layers with a heightmap");
                                    for (int lyrIdx = 0; lyrIdx < layerList.Count; lyrIdx++)
                                    {
                                        // Get the path in the asset db to the image-based layer heightmap texture
                                        string heightmapPath = UnityEditor.AssetDatabase.GetAssetPath(layerList[lyrIdx].heightmapImage);
                                        if (!string.IsNullOrEmpty(heightmapPath))
                                        {
                                            templateAssetPaths.Add(heightmapPath);
                                        }
                                    }
                                }
                            }

                            // Add the list of map path mesh materials we add earlier.
                            if (addPathMeshMaterialsToTemplate && lbMapPathMaterialAssetPathList.Count > 0)
                            {
                                templateAssetPaths.AddRange(lbMapPathMaterialAssetPathList);
                            }

                            AssetDatabase.ExportPackage(templateAssetPaths.ToArray(), "LandscapeBuilder/TemplatePackages/" + landscapeTemplateName + ".unitypackage", ExportPackageOptions.Interactive);
                        }
                        LBEditorHelper.HighlightItemInProjectWindow(templateAssetPath);
                    }

                    // Cleanup scene hierarchy
                    GameObject.DestroyImmediate(newTemplateObj);
                }
            }

            return(isSuccessful);
        }