using System; using System.Linq; using System.Collections.Generic; using UnityEngine; using UnityEngine.VFX; using UnityObject = UnityEngine.Object; namespace UnityEditor.VFX.UI { abstract class SubGraphCache { string m_Filter; public struct Item { public string category; public string name; public string path; public string guid; public object additionalInfos; } public struct AdditionalBlockInfo { public VFXContextType compatibleType; public VFXDataType compatibleData; } protected List m_Items = new List(); private IEnumerable items { get { UpdateCache(); return m_Items; } } protected abstract void UpdateCache(); static readonly Dictionary s_Caches = new() { { typeof(VisualEffectAsset), new SubGraphCache()}, { typeof(VisualEffectSubgraphBlock), new SubGraphCache()}, { typeof(VisualEffectSubgraphOperator), new SubGraphCache()}, }; public static IEnumerable GetItems(Type type) { return s_Caches.TryGetValue(type, out var cache) ? cache.items : Enumerable.Empty(); } } class SubGraphCache : SubGraphCache where T : VisualEffectObject { protected override void UpdateCache() { var guids = AssetDatabase.FindAssets("t:" + typeof(T).Name); m_Items.Clear(); foreach (var guid in guids) { string path = AssetDatabase.GUIDToAssetPath(guid); if (!path.StartsWith(VisualEffectAssetEditorUtility.templatePath)) { T asset = AssetDatabase.LoadAssetAtPath(path); if (asset != null) { VisualEffectResource res = asset.GetResource(); Item item = new Item { name = asset.name, category = res.GetOrCreateGraph().categoryPath, path = path, guid = guid}; if (item.category == null) item.category = ""; if (typeof(T) == typeof(VisualEffectSubgraphBlock)) { VFXBlockSubgraphContext blockContext = asset.GetResource().GetOrCreateGraph().children.OfType().FirstOrDefault(); if (blockContext != null) { item.additionalInfos = new AdditionalBlockInfo { compatibleType = blockContext.compatibleContextType, compatibleData = blockContext.ownedType }; m_Items.Add(item); } } else m_Items.Add(item); } } } } } class SubgraphVariant : Variant { private readonly string m_Guid; public SubgraphVariant(string name, string category, Type modelType, KeyValuePair[] kvp, string guid) : base(name, category, modelType, kvp, null, null, true) { m_Guid = guid; } public override string GetUniqueIdentifier() => m_Guid; } class VFXNodeProvider : VFXAbstractProvider { readonly Func m_Filter; readonly IEnumerable m_AcceptedTypes; readonly VFXViewController m_Controller; public VFXNodeProvider(VFXViewController controller, Action onAddBlock, Func filter = null, IEnumerable acceptedTypes = null) : base(onAddBlock) { m_Filter = filter; m_AcceptedTypes = acceptedTypes; m_Controller = controller; } #if VFX_HAS_UNIT_TEST public IEnumerable GetDescriptorsForInternalTest() { return GetDescriptors(); } #endif public override IEnumerable GetDescriptors() { var descs = new List(); if (m_AcceptedTypes == null || m_AcceptedTypes.Contains(typeof(VFXContext))) { descs.AddRange(VFXLibrary.GetContexts()); } if (m_AcceptedTypes == null || m_AcceptedTypes.Contains(typeof(VFXOperator))) { descs.AddRange(VFXLibrary.GetOperators()); descs.AddRange(SubGraphCache.GetItems(typeof(VisualEffectSubgraphOperator)).Select(x => new VFXModelDescriptor(new SubgraphVariant( x.name, x.category, typeof(VisualEffectSubgraphOperator), new []{ new KeyValuePair("path", x.path)}, x.guid), null))); descs.AddRange(m_Controller.graph.attributesManager.GetCustomAttributes().Select(x => new VFXModelDescriptor(new Variant( $"Get {x.name}", "Operator/Attribute/".AppendSeparator("Custom", 0), typeof(VFXAttributeParameter), new[] { new KeyValuePair(nameof(VFXAttributeParameter.attribute), x.name) }, null, null, false), null))); } if (m_AcceptedTypes == null || m_AcceptedTypes.Contains(typeof(VFXParameter))) { var parameterVariants = m_Controller.parameterControllers.Select(t => new VFXModelDescriptor( new VFXModelDescriptorParameters.ParameterVariant( t.exposedName, string.IsNullOrEmpty(t.model.category) ? "Property" : "Property/".AppendSeparator(t.model.category, 0), t.portType), null)); descs.AddRange(parameterVariants); } return m_Filter == null ? descs : descs.Where(t => m_Filter(t)); } } }