#if FLORA_PRESENT using ProceduralWorlds.Flora; #endif using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; namespace Gaia { /// /// Data structure to provide override values for the asset guid / instance ID for a Flora LOD entry. List of those overrides are being used to handle loading of multiple LODs per spawn rule. /// public class FloraLODIdOverrides { public string m_assetGUIDOverride; public int m_instanceIDOverride; } /// /// Data structure to support serializing multiple LODs of flora setting objects for trees / terrain details together with tree / terrain detail resource settings in the spawner /// [System.Serializable] public class FloraLOD { public int m_index = 0; public bool m_foldedOut = false; public GaiaConstants.SpawnerResourceType m_spawnerResourceType; public string m_name = "New Flora Settings Object"; public string m_detailerSettingsObjectAssetGUID; public int m_detailerSettingsObjectInstanceID; #if FLORA_PRESENT public DetailScriptableObject DetailerSettingsObject { get { if (m_pwDetailerSettingsObject == null) { if (!(m_spawnerResourceType == GaiaConstants.SpawnerResourceType.TerrainDetail || m_spawnerResourceType == GaiaConstants.SpawnerResourceType.TerrainTree)) { Debug.LogError($"Trying to create a Flora Scriptable object for a {m_spawnerResourceType} resource, this is not supported (yet)"); return null; } if (!string.IsNullOrEmpty(m_detailerSettingsObjectAssetGUID)) { #if UNITY_EDITOR string assetPath = AssetDatabase.GUIDToAssetPath(m_detailerSettingsObjectAssetGUID); //This can be multiple objects since the scriptable object can be embedded in a spawner settings file UnityEngine.Object[] allObjects = AssetDatabase.LoadAllAssetsAtPath(assetPath); //Looking for the object via the instance ID foreach (UnityEngine.Object obj in allObjects) { if (obj.GetType() == typeof(DetailScriptableObject) && obj.GetInstanceID() == m_detailerSettingsObjectInstanceID) { //found it, cast it into the correct type to store it m_pwDetailerSettingsObject = (DetailScriptableObject)obj; //is this a file that was embedded within other assets at this path? if (allObjects.Count() > 1) { //we need to create a copy and save it to not work with the embedded file m_pwDetailerSettingsObject = ScriptableObject.Instantiate(m_pwDetailerSettingsObject); FloraUtils.SaveSettingsFile(m_pwDetailerSettingsObject, ref m_detailerSettingsObjectAssetGUID, ref m_detailerSettingsObjectInstanceID, false, m_name + "_" + m_index.ToString(), GaiaDirectories.GetFloraDataPath()); } } } #endif } } return m_pwDetailerSettingsObject; } set { if (value != m_pwDetailerSettingsObject) { m_pwDetailerSettingsObject = value; if (value != null) { #if UNITY_EDITOR m_detailerSettingsObjectAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(value)); m_detailerSettingsObjectInstanceID = value.GetInstanceID(); #endif } else { m_detailerSettingsObjectAssetGUID = ""; m_detailerSettingsObjectInstanceID = -1; } } } } //This needs to be serialized still to survive recompiles, etc.! [SerializeField] private DetailScriptableObject m_pwDetailerSettingsObject; /// /// Creates an instantiated (separate) copy of the detailer settings object in the Gaia User Data directory. /// public void InstantiateDetailerSettingsGO(ref Dictionary materialMap) { #if UNITY_EDITOR if (m_pwDetailerSettingsObject == null) { if (!string.IsNullOrEmpty(m_detailerSettingsObjectAssetGUID)) { string assetPath = AssetDatabase.GUIDToAssetPath(m_detailerSettingsObjectAssetGUID); //This can be multiple objects since the scriptable object can be embedded in a spawner settings file UnityEngine.Object[] allObjects = AssetDatabase.LoadAllAssetsAtPath(assetPath); //Looking for the object via the instance ID foreach (UnityEngine.Object obj in allObjects) { if (obj.GetType() == typeof(DetailScriptableObject) && obj.GetInstanceID() == m_detailerSettingsObjectInstanceID) { //found it, cast it into the correct type to store it m_pwDetailerSettingsObject = (DetailScriptableObject)obj; } } } } if (m_pwDetailerSettingsObject == null) { return; } string floraDataPath = GaiaDirectories.GetFloraDataPath(); if (m_pwDetailerSettingsObject != null) { m_pwDetailerSettingsObject = ScriptableObject.Instantiate(m_pwDetailerSettingsObject); FloraUtils.SaveSettingsFile(m_pwDetailerSettingsObject, ref m_detailerSettingsObjectAssetGUID, ref m_detailerSettingsObjectInstanceID, false, m_name + "_LOD" + m_index.ToString(), floraDataPath); } Material[] mats = m_pwDetailerSettingsObject.Mat.Where(x => x != null).ToArray(); List createdMaterials = new List(); //Handle Materials - those should never be null in theory, just need to be re-instantiated and saved for (int i = 0; i < mats.Length; i++) { //if the material map contains the instance ID already, this means this material has already been created within the Flora data folder int instanceID = m_pwDetailerSettingsObject.Mat[i].GetInstanceID(); if (materialMap.Keys.Contains(instanceID)) { //-> take the already existing material then! m_pwDetailerSettingsObject.Mat[i] = (Material)AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(materialMap.First(x => x.Key == instanceID).Value), typeof(Material)); } else { //create a new material string originalName = m_pwDetailerSettingsObject.Mat[i].name; m_pwDetailerSettingsObject.Mat[i] = Material.Instantiate(m_pwDetailerSettingsObject.Mat[i]); //Remove "(Clone)" from the name m_pwDetailerSettingsObject.Mat[i].name = originalName; string assetPath = floraDataPath + "/" + m_pwDetailerSettingsObject.Mat[i].name + "_" + instanceID + ".mat"; AssetDatabase.CreateAsset(m_pwDetailerSettingsObject.Mat[i], assetPath); //AssetDatabase.ImportAsset(assetPath); //Log the creation of the material for this instance ID in the material map materialMap.Add(instanceID,AssetDatabase.AssetPathToGUID(assetPath)); //createdMaterials.Add((Material)AssetDatabase.LoadAssetAtPath(assetPath, typeof(Material))); createdMaterials.Add(m_pwDetailerSettingsObject.Mat[i]); } } //Migrate shaders in materials (could potentially be created in different pipeline originally) GaiaUtils.ProcessMaterialLibrary(createdMaterials); #endif } /// /// Copies the fields of the old object over into the existing one to overwrite it /// /// public void CopySettingsAndApply(DetailScriptableObject oldObject) { string oldName = oldObject.name; GaiaUtils.CopyFields(m_pwDetailerSettingsObject, oldObject, true); DetailerSettingsObject = oldObject; DetailerSettingsObject.name = oldName; DetailerSettingsObject.SourceDataType = CoreCommonFloraData.SourceDataType.Detail; //Make sure the materials use the right shader GaiaUtils.ProcessMaterialLibrary(DetailerSettingsObject.Mat.ToList()); #if UNITY_EDITOR EditorUtility.ClearProgressBar(); #endif } #endif } }