using System; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Threading; using AwesomeTechnologies.Utility; using Unity.Collections; #if UNITY_EDITOR using UnityEditor; #endif using UnityEngine; namespace AwesomeTechnologies.Vegetation.PersistentStorage { [Serializable] public class SourceCount { public byte VegetationSourceID; public int Count; } [Serializable] public class PersistentVegetationInstanceInfo { public string VegetationItemID; public int Count; public List SourceCountList = new List(); public void AddSourceCountList(List sourceCountList) { for (int i = 0; i <= sourceCountList.Count - 1; i++) { AddSourceCount(sourceCountList[i]); } } public void AddSourceCount(SourceCount sourceCount) { SourceCount tempSourceCount = GetSourceCount(sourceCount.VegetationSourceID); if (tempSourceCount == null) { tempSourceCount = new SourceCount { VegetationSourceID = sourceCount.VegetationSourceID }; SourceCountList.Add(tempSourceCount); } tempSourceCount.Count += sourceCount.Count; } SourceCount GetSourceCount(byte vegetationSourceID) { for (int i = 0; i <= SourceCountList.Count - 1; i++) { if (SourceCountList[i].VegetationSourceID == vegetationSourceID) return SourceCountList[i]; } return null; } } [Serializable] public struct PersistentVegetationItem { public Vector3 Position; public Vector3 Scale; public Quaternion Rotation; public byte VegetationSourceID; public float DistanceFalloff; } [Serializable] public class PersistentVegetationInfo { public string VegetationItemID; [SerializeField] public List VegetationItemList = new List(); [NonSerialized] public NativeArray NativeVegetationItemArray; public List SourceCountList = new List(); public void CopyToNativeArray() { NativeVegetationItemArray = new NativeArray(VegetationItemList.Count,Allocator.Persistent); NativeVegetationItemArray.CopyFromFast(VegetationItemList); } public void ClearCell() { VegetationItemList.Clear(); SourceCountList.Clear(); } public void AddPersistentVegetationItemInstance(ref PersistentVegetationItem persistentVegetationItem) { IncreaseSourceCount(persistentVegetationItem.VegetationSourceID); VegetationItemList.Add(persistentVegetationItem); } public void RemovePersistentVegetationItemInstance(ref PersistentVegetationItem persistentVegetationItem) { DecreaseSourceCount(persistentVegetationItem.VegetationSourceID); VegetationItemList.Remove(persistentVegetationItem); } public void RemovePersistentVegetationInstanceAtIndex(int index) { if (index >= VegetationItemList.Count) return; DecreaseSourceCount(VegetationItemList[index].VegetationSourceID); VegetationItemList.RemoveAt(index); } public void UpdatePersistentVegetationItemInstanceSourceId(ref PersistentVegetationItem persistentVegetationItem, byte newSourceID) { if (persistentVegetationItem.VegetationSourceID != newSourceID) { DecreaseSourceCount(persistentVegetationItem.VegetationSourceID); persistentVegetationItem.VegetationSourceID = newSourceID; IncreaseSourceCount(persistentVegetationItem.VegetationSourceID); } } void IncreaseSourceCount(byte vegetationSourceID) { SourceCount sourceCount = GetSourceCount(vegetationSourceID); if (sourceCount == null) { sourceCount = new SourceCount { VegetationSourceID = vegetationSourceID }; SourceCountList.Add(sourceCount); } sourceCount.Count++; } SourceCount GetSourceCount(byte vegetationSourceID) { for (int i = 0; i <= SourceCountList.Count - 1; i++) { if (SourceCountList[i].VegetationSourceID == vegetationSourceID) return SourceCountList[i]; } return null; } void DecreaseSourceCount(byte vegetationSourceID) { SourceCount sourceCount = GetSourceCount(vegetationSourceID); if (sourceCount == null) return; sourceCount.Count--; if (sourceCount.Count == 0) SourceCountList.Remove(sourceCount); } public void Dispose() { if (NativeVegetationItemArray.IsCreated) { NativeVegetationItemArray.Dispose(); } } } [Serializable] public class PersistentVegetationCell { public List PersistentVegetationInfoList = new List(); public void Dispose() { for (int i = 0; i <= PersistentVegetationInfoList.Count -1; i++) { PersistentVegetationInfoList[i].Dispose(); } } public void AddVegetationItemInstance(string vegetationItemID, Vector3 position, Vector3 scale, Quaternion rotation, byte vegetationSourceID, float distanceFalloff) { PersistentVegetationInfo persistentVegetationInfo = GetPersistentVegetationInfo(vegetationItemID); if (persistentVegetationInfo == null) { persistentVegetationInfo = new PersistentVegetationInfo { VegetationItemID = vegetationItemID }; PersistentVegetationInfoList.Add(persistentVegetationInfo); } PersistentVegetationItem persistentVegetationItem = new PersistentVegetationItem { Position = position, Rotation = rotation, Scale = scale, VegetationSourceID = vegetationSourceID, DistanceFalloff = distanceFalloff }; persistentVegetationInfo.AddPersistentVegetationItemInstance(ref persistentVegetationItem); } public void RemoveVegetationItemInstance(string vegetationItemID, Vector3 position, float minimumDistance) { PersistentVegetationInfo persistentVegetationInfo = GetPersistentVegetationInfo(vegetationItemID); if (persistentVegetationInfo == null) return; for (int i = persistentVegetationInfo.VegetationItemList.Count - 1; i >= 0; i--) { if (Vector3.Distance(persistentVegetationInfo.VegetationItemList[i].Position, position) < minimumDistance) { persistentVegetationInfo.VegetationItemList.RemoveAt(i); } } } public void RemoveVegetationItemInstance2D(string vegetationItemID, Vector3 position, float minimumDistance) { PersistentVegetationInfo persistentVegetationInfo = GetPersistentVegetationInfo(vegetationItemID); if (persistentVegetationInfo == null) return; for (int i = persistentVegetationInfo.VegetationItemList.Count - 1; i >= 0; i--) { if (Vector2.Distance( new Vector2(persistentVegetationInfo.VegetationItemList[i].Position.x, persistentVegetationInfo.VegetationItemList[i].Position.z), new Vector2(position.x, position.z)) < minimumDistance) { persistentVegetationInfo.VegetationItemList.RemoveAt(i); } } } public void AddVegetationItemInstanceEx(string vegetationItemID, Vector3 position, Vector3 scale, Quaternion rotation, byte vegetationSourceID, float minimumDistance, float distanceFalloff) { PersistentVegetationInfo persistentVegetationInfo = GetPersistentVegetationInfo(vegetationItemID); if (persistentVegetationInfo == null) { persistentVegetationInfo = new PersistentVegetationInfo { VegetationItemID = vegetationItemID }; PersistentVegetationInfoList.Add(persistentVegetationInfo); } float closestDistance = CalculateClosestItemDistance(position, persistentVegetationInfo.VegetationItemList); if (closestDistance < minimumDistance) return; PersistentVegetationItem persistentVegetationItem = new PersistentVegetationItem { Position = position, Rotation = rotation, Scale = scale, VegetationSourceID = vegetationSourceID, DistanceFalloff = distanceFalloff }; persistentVegetationInfo.AddPersistentVegetationItemInstance(ref persistentVegetationItem); } float CalculateClosestItemDistance(Vector3 position, List instanceList) { float nearestSqrMag = float.PositiveInfinity; Vector3 nearestVector3 = Vector3.zero; for (int i = 0; i < instanceList.Count; i++) { float sqrMag = (instanceList[i].Position - position).sqrMagnitude; if (sqrMag < nearestSqrMag) { nearestSqrMag = sqrMag; nearestVector3 = instanceList[i].Position; } } return Vector3.Distance(nearestVector3, position); } public void ClearCell() { PersistentVegetationInfoList.Clear(); } public PersistentVegetationInfo GetPersistentVegetationInfo(string vegetationItemID) { for (int i = 0; i <= PersistentVegetationInfoList.Count - 1; i++) { if (PersistentVegetationInfoList[i].VegetationItemID == vegetationItemID) return PersistentVegetationInfoList[i]; } return null; } public void RemoveVegetationItemInstances(string vegetationItemID) { PersistentVegetationInfo persistentVegetationInfo = GetPersistentVegetationInfo(vegetationItemID); if (persistentVegetationInfo != null) { PersistentVegetationInfoList.Remove(persistentVegetationInfo); } } public void RemoveVegetationItemInstances(string vegetationItemID, byte vegetationSourceID) { PersistentVegetationInfo persistentVegetationInfo = GetPersistentVegetationInfo(vegetationItemID); if (persistentVegetationInfo != null) { for (int i = persistentVegetationInfo.VegetationItemList.Count - 1; i >= 0; i--) { if (persistentVegetationInfo.VegetationItemList[i].VegetationSourceID == vegetationSourceID) { persistentVegetationInfo.RemovePersistentVegetationInstanceAtIndex(i); } } if (persistentVegetationInfo.VegetationItemList.Count == 0) { PersistentVegetationInfoList.Remove(persistentVegetationInfo); } } } } [Serializable] public class ExportData { public List PersistentVegetationCellList; public List PersistentVegetationInstanceInfoList; public List PersistentVegetationInstanceSourceList; } [PreferBinarySerialization] [Serializable] public class PersistentVegetationStoragePackage : ScriptableObject { public List PersistentVegetationCellList = new List(); public List PersistentVegetationInstanceInfoList = new List(); public List PersistentVegetationInstanceSourceList = new List(); public void Dispose() { for (int i = 0; i <= PersistentVegetationCellList.Count -1; i++) { PersistentVegetationCellList[i].Dispose(); } } public void ExportToFile(string filename) { var exportData = new ExportData { PersistentVegetationCellList = PersistentVegetationCellList, PersistentVegetationInstanceInfoList = PersistentVegetationInstanceInfoList, PersistentVegetationInstanceSourceList = PersistentVegetationInstanceSourceList }; BinaryFormatter bf = SerializationSurrogateUtil.GetBinaryFormatter(); FileStream file = File.Create(filename); bf.Serialize(file, exportData); file.Close(); } public void ExportToStream(Stream outputStream) { var exportData = new ExportData { PersistentVegetationCellList = PersistentVegetationCellList, PersistentVegetationInstanceInfoList = PersistentVegetationInstanceInfoList, PersistentVegetationInstanceSourceList = PersistentVegetationInstanceSourceList }; BinaryFormatter bf = SerializationSurrogateUtil.GetBinaryFormatter(); bf.Serialize(outputStream, exportData); outputStream.Position = 0; } public void ImportFromStream(Stream inputStream) { BinaryFormatter bf = SerializationSurrogateUtil.GetBinaryFormatter(); var exportData = (ExportData)bf.Deserialize(inputStream); PersistentVegetationCellList = exportData.PersistentVegetationCellList; PersistentVegetationInstanceInfoList = exportData.PersistentVegetationInstanceInfoList; PersistentVegetationInstanceSourceList = exportData.PersistentVegetationInstanceSourceList; inputStream.Position = 0; #if UNITY_EDITOR EditorUtility.SetDirty(this); #endif } public void ImportFromFile(string filename) { BinaryFormatter bf = SerializationSurrogateUtil.GetBinaryFormatter(); FileStream file = File.Open(filename,FileMode.Open); var exportData = (ExportData)bf.Deserialize(file); PersistentVegetationCellList = exportData.PersistentVegetationCellList; PersistentVegetationInstanceInfoList = exportData.PersistentVegetationInstanceInfoList; PersistentVegetationInstanceSourceList = exportData.PersistentVegetationInstanceSourceList; file.Close(); #if UNITY_EDITOR EditorUtility.SetDirty(this); #endif } public bool Initialized { get { return PersistentVegetationCellList.Count > 0; } } [SerializeField] private bool _instanceInfoDirty; public void ClearPersistentVegetationCells() { PersistentVegetationCellList.Clear(); } public void SetInstanceInfoDirty() { _instanceInfoDirty = true; } public void RemoveVegetationItemInstances(string vegetationItemID) { for (int i = 0; i <= PersistentVegetationCellList.Count - 1; i++) { PersistentVegetationCellList[i].RemoveVegetationItemInstances(vegetationItemID); } _instanceInfoDirty = true; } public void RemoveVegetationItemInstances(string vegetationItemID, byte vegetationSourceID) { for (int i = 0; i <= PersistentVegetationCellList.Count - 1; i++) { PersistentVegetationCellList[i].RemoveVegetationItemInstances(vegetationItemID, vegetationSourceID); } _instanceInfoDirty = true; } public void AddVegetationCell() { PersistentVegetationCell persistentVegetationCell = new PersistentVegetationCell(); PersistentVegetationCellList.Add(persistentVegetationCell); _instanceInfoDirty = true; } public void AddVegetationItemInstance(int cellIndex, string vegetationItemID, Vector3 position, Vector3 scale, Quaternion rotation, byte vegetationSourceID,float distanceFalloff) { if (PersistentVegetationCellList.Count > cellIndex) { PersistentVegetationCellList[cellIndex].AddVegetationItemInstance(vegetationItemID, position, scale, rotation, vegetationSourceID,distanceFalloff); } _instanceInfoDirty = true; #if UNITY_EDITOR if (ThreadUtility.MainThread == Thread.CurrentThread) { EditorUtility.SetDirty(this); } #endif } public void AddVegetationItemInstanceEx(int cellIndex, string vegetationItemID, Vector3 position, Vector3 scale, Quaternion rotation, byte vegetationSourceID, float minimumDistance, float distanceFalloff) { if (PersistentVegetationCellList.Count > cellIndex) { PersistentVegetationCellList[cellIndex].AddVegetationItemInstanceEx(vegetationItemID, position, scale, rotation, vegetationSourceID, minimumDistance,distanceFalloff); } _instanceInfoDirty = true; #if UNITY_EDITOR EditorUtility.SetDirty(this); #endif } public void RemoveVegetationItemInstance(int cellIndex, string vegetationItemID, Vector3 position, float minimumDistance) { if (PersistentVegetationCellList.Count > cellIndex) { PersistentVegetationCellList[cellIndex].RemoveVegetationItemInstance(vegetationItemID, position, minimumDistance); } _instanceInfoDirty = true; #if UNITY_EDITOR EditorUtility.SetDirty(this); #endif } public void RemoveVegetationItemInstance2D(int cellIndex, string vegetationItemID, Vector3 position, float minimumDistance) { if (PersistentVegetationCellList.Count > cellIndex) { PersistentVegetationCellList[cellIndex].RemoveVegetationItemInstance2D(vegetationItemID, position, minimumDistance); } _instanceInfoDirty = true; #if UNITY_EDITOR EditorUtility.SetDirty(this); #endif } public List GetPersistentVegetationInstanceInfoList() { if (_instanceInfoDirty) { UpdatePersistentVegetationInstanceInfo(); _instanceInfoDirty = false; } return PersistentVegetationInstanceInfoList; } void UpdatePersistentVegetationInstanceInfo() { PersistentVegetationInstanceInfoList.Clear(); for (int i = 0; i <= PersistentVegetationCellList.Count - 1; i++) { PersistentVegetationCell cell = PersistentVegetationCellList[i]; for (int j = 0; j <= cell.PersistentVegetationInfoList.Count - 1; j++) { PersistentVegetationInstanceInfo instanceInfo = GetPersistentVegetationInstanceInfo(cell.PersistentVegetationInfoList[j].VegetationItemID); if (instanceInfo == null) { instanceInfo = new PersistentVegetationInstanceInfo { VegetationItemID = cell.PersistentVegetationInfoList[j].VegetationItemID }; PersistentVegetationInstanceInfoList.Add(instanceInfo); } instanceInfo.Count += cell.PersistentVegetationInfoList[j].VegetationItemList.Count; instanceInfo.AddSourceCountList(cell.PersistentVegetationInfoList[j].SourceCountList); } } } PersistentVegetationInstanceInfo GetPersistentVegetationInstanceInfo(string vegetationItemID) { for (int i = 0; i <= PersistentVegetationInstanceInfoList.Count - 1; i++) { if (PersistentVegetationInstanceInfoList[i].VegetationItemID == vegetationItemID) return PersistentVegetationInstanceInfoList[i]; } return null; } } }