void ComputeEffectiveInputLinks(ref SubgraphInfos subgraphInfos, IEnumerable <VFXContext> compilableContexts)
        {
            var contextEffectiveInputLinks = subgraphInfos.contextEffectiveInputLinks;


            foreach (var context in compilableContexts.Where(t => !(t is VFXSubgraphContext)))
            {
                contextEffectiveInputLinks[context] = ComputeContextEffectiveLinks(context, ref subgraphInfos);

                ComputeEffectiveInputLinks(ref subgraphInfos, contextEffectiveInputLinks[context].SelectMany(t => t).Select(t => t.context).Where(t => !contextEffectiveInputLinks.ContainsKey(t)));
            }
        }
        private static void FillEvent(List <VFXEventDesc> outEventDesc, Dictionary <VFXContext, SpawnInfo> contextSpawnToSpawnInfo, IEnumerable <VFXContext> contexts, ref SubgraphInfos subgraphInfos)
        {
            var contextEffectiveInputLinks = subgraphInfos.contextEffectiveInputLinks;

            var allPlayNotLinked = contextSpawnToSpawnInfo.Where(o => !contextEffectiveInputLinks[o.Key][0].Any()).Select(o => (uint)o.Value.systemIndex).ToList();
            var allStopNotLinked = contextSpawnToSpawnInfo.Where(o => !contextEffectiveInputLinks[o.Key][1].Any()).Select(o => (uint)o.Value.systemIndex).ToList();

            var eventDescTemp = new[]
            {
                new { eventName = "OnPlay", playSystems = allPlayNotLinked, stopSystems = new List <uint>() },
                new { eventName = "OnStop", playSystems = new List <uint>(), stopSystems = allStopNotLinked },
            }.ToList();

            var specialNames = new HashSet <string>(new string[] { VisualEffectAsset.PlayEventName, VisualEffectAsset.StopEventName, VFXSubgraphContext.triggerEventName });


            var events = contexts.Where(o => o.contextType == VFXContextType.Event);

            foreach (var evt in events)
            {
                var eventName = (evt as VFXBasicEvent).eventName;

                if (subgraphInfos.spawnerSubgraph.ContainsKey(evt) && specialNames.Contains(eventName))
                {
                    continue;
                }

                foreach (var link in evt.outputFlowSlot[0].link)
                {
                    if (contextSpawnToSpawnInfo.ContainsKey(link.context))
                    {
                        var eventIndex = eventDescTemp.FindIndex(o => o.eventName == eventName);
                        if (eventIndex == -1)
                        {
                            eventIndex = eventDescTemp.Count;
                            eventDescTemp.Add(new
                            {
                                eventName   = eventName,
                                playSystems = new List <uint>(),
                                stopSystems = new List <uint>(),
                            });
                        }

                        var startSystem  = link.slotIndex == 0;
                        var spawnerIndex = (uint)contextSpawnToSpawnInfo[link.context].systemIndex;
                        if (startSystem)
                        {
                            eventDescTemp[eventIndex].playSystems.Add(spawnerIndex);
                        }
                        else
                        {
                            eventDescTemp[eventIndex].stopSystems.Add(spawnerIndex);
                        }
                    }
                }
            }
            outEventDesc.Clear();
            outEventDesc.AddRange(eventDescTemp.Select(o => new VFXEventDesc()
            {
                name = o.eventName, startSystems = o.playSystems.ToArray(), stopSystems = o.stopSystems.ToArray()
            }));
        }
        private static void FillSpawner(Dictionary <VFXContext, SpawnInfo> outContextSpawnToSpawnInfo,
                                        List <VFXCPUBufferDesc> outCpuBufferDescs,
                                        List <VFXEditorSystemDesc> outSystemDescs,
                                        IEnumerable <VFXContext> contexts,
                                        VFXExpressionGraph graph,
                                        List <VFXLayoutElementDesc> globalEventAttributeDescs,
                                        Dictionary <VFXContext, VFXContextCompiledData> contextToCompiledData,
                                        ref SubgraphInfos subgraphInfos)
        {
            var spawners = CollectSpawnersHierarchy(contexts, ref subgraphInfos);

            foreach (var it in spawners.Select((spawner, index) => new { spawner, index }))
            {
                outContextSpawnToSpawnInfo.Add(it.spawner, new SpawnInfo()
                {
                    bufferIndex = outCpuBufferDescs.Count, systemIndex = it.index
                });
                outCpuBufferDescs.Add(new VFXCPUBufferDesc()
                {
                    capacity    = 1u,
                    stride      = globalEventAttributeDescs.First().offset.structure,
                    layout      = globalEventAttributeDescs.ToArray(),
                    initialData = ComputeArrayOfStructureInitialData(globalEventAttributeDescs)
                });
            }
            foreach (var spawnContext in spawners)
            {
                var buffers = new List <VFXMapping>();
                buffers.Add(new VFXMapping()
                {
                    index = outContextSpawnToSpawnInfo[spawnContext].bufferIndex,
                    name  = "spawner_output"
                });

                for (int indexSlot = 0; indexSlot < 2 && indexSlot < spawnContext.inputFlowSlot.Length; ++indexSlot)
                {
                    foreach (var input in subgraphInfos.contextEffectiveInputLinks[spawnContext][indexSlot])
                    {
                        var inputContext = input.context;
                        if (outContextSpawnToSpawnInfo.ContainsKey(inputContext))
                        {
                            buffers.Add(new VFXMapping()
                            {
                                index = outContextSpawnToSpawnInfo[inputContext].bufferIndex,
                                name  = "spawner_input_" + (indexSlot == 0 ? "OnPlay" : "OnStop")
                            });
                        }
                    }
                }

                var contextData = contextToCompiledData[spawnContext];
                outSystemDescs.Add(new VFXEditorSystemDesc()
                {
                    buffers  = buffers.ToArray(),
                    capacity = 0u,
                    flags    = VFXSystemFlag.SystemDefault,
                    layer    = uint.MaxValue,
                    tasks    = spawnContext.activeFlattenedChildrenWithImplicit.Select((b, index) =>
                    {
                        var spawnerBlock = b as VFXAbstractSpawner;
                        if (spawnerBlock == null)
                        {
                            throw new InvalidCastException("Unexpected block type in spawnerContext");
                        }
                        if (spawnerBlock.spawnerType == VFXTaskType.CustomCallbackSpawner && spawnerBlock.customBehavior == null)
                        {
                            throw new InvalidOperationException("VFXAbstractSpawner excepts a custom behavior for custom callback type");
                        }
                        if (spawnerBlock.spawnerType != VFXTaskType.CustomCallbackSpawner && spawnerBlock.customBehavior != null)
                        {
                            throw new InvalidOperationException("VFXAbstractSpawner only expects a custom behavior for custom callback type");
                        }

                        var cpuExpression = contextData.cpuMapper.CollectExpression(index, false).Select(o =>
                        {
                            return(new VFXMapping
                            {
                                index = graph.GetFlattenedIndex(o.exp),
                                name = o.name
                            });
                        }).ToArray();

                        Object processor = null;
                        if (spawnerBlock.customBehavior != null)
                        {
                            var assets = AssetDatabase.FindAssets("t:TextAsset " + spawnerBlock.customBehavior.Name);
                            if (assets.Length != 1)
                            {
                                // AssetDatabase.FindAssets will not search in package by default. Search in our package explicitely
                                assets = AssetDatabase.FindAssets("t:TextAsset " + spawnerBlock.customBehavior.Name, new string[] { VisualEffectGraphPackageInfo.assetPackagePath });
                                if (assets.Length != 1)
                                {
                                    throw new InvalidOperationException("Unable to find the definition .cs file for " + spawnerBlock.customBehavior + " Make sure that the class name and file name match");
                                }
                            }

                            var assetPath = AssetDatabase.GUIDToAssetPath(assets[0]);
                            processor     = AssetDatabase.LoadAssetAtPath <TextAsset>(assetPath);
                        }

                        return(new VFXEditorTaskDesc
                        {
                            type = spawnerBlock.spawnerType,
                            buffers = new VFXMapping[0],
                            values = cpuExpression.ToArray(),
                            parameters = contextData.parameters,
                            externalProcessor = processor
                        });
                    }).ToArray()
                });
            }
        }
        static List <VFXContextLink>[] ComputeContextEffectiveLinks(VFXContext context, ref SubgraphInfos subgraphInfos)
        {
            List <VFXContextLink>[]  result          = new List <VFXContextLink> [context.inputFlowSlot.Length];
            Dictionary <string, int> eventNameIndice = new Dictionary <string, int>();

            for (int i = 0; i < context.inputFlowSlot.Length; ++i)
            {
                result[i] = new List <VFXContextLink>();
                VFXSubgraphContext parentSubgraph = null;

                subgraphInfos.spawnerSubgraph.TryGetValue(context, out parentSubgraph);

                List <VFXContext> subgraphAncestors = new List <VFXContext>();

                subgraphAncestors.Add(context);

                while (parentSubgraph != null)
                {
                    subgraphAncestors.Add(parentSubgraph);
                    if (!subgraphInfos.subgraphParents.TryGetValue(parentSubgraph, out parentSubgraph))
                    {
                        parentSubgraph = null;
                    }
                }

                List <List <int> > defaultEventPaths = new List <List <int> >();

                defaultEventPaths.Add(new List <int>(new int[] { i }));

                List <List <int> > newEventPaths = new List <List <int> >();

                var usedContexts = new List <VFXContext>();

                var namedEvents = new Dictionary <string, VFXContext>();

                for (int j = 0; j < subgraphAncestors.Count; ++j)
                {
                    var sg     = subgraphAncestors[j];
                    var nextSg = j < subgraphAncestors.Count - 1 ? subgraphAncestors[j + 1] as VFXSubgraphContext : null;

                    foreach (var path in defaultEventPaths)
                    {
                        int currentFlowIndex  = path.Last();
                        var eventSlot         = sg.inputFlowSlot[currentFlowIndex]; // -1 in path is Trigger therefore 2 in subgraph input
                        var eventSlotSpawners = eventSlot.link.Where(t => !(t.context is VFXBasicEvent));

                        if (eventSlotSpawners.Any())
                        {
                            foreach (var evt in eventSlotSpawners)
                            {
                                result[i].Add(evt);
                            }
                        }

                        var eventSlotEvents = eventSlot.link.Where(t => t.context is VFXBasicEvent);

                        if (eventSlotEvents.Any())
                        {
                            foreach (var evt in eventSlotEvents)
                            {
                                string eventName = (evt.context as VFXBasicEvent).eventName;

                                switch (eventName)
                                {
                                case VisualEffectAsset.PlayEventName:
                                    newEventPaths.Add(path.Concat(new int[] { 0 }).ToList());
                                    break;

                                case VisualEffectAsset.StopEventName:
                                    newEventPaths.Add(path.Concat(new int[] { 1 }).ToList());
                                    break;

                                default:
                                {
                                    if (nextSg != null)
                                    {
                                        int eventIndex = nextSg.GetInputFlowIndex(eventName);
                                        if (eventIndex != -1)
                                        {
                                            namedEvents[eventName] = evt.context;
                                            newEventPaths.Add(path.Concat(new int[] { eventIndex }).ToList());
                                        }
                                    }
                                    else
                                    {
                                        result[i].Add(evt);
                                    }
                                }

                                break;
                                }
                            }
                        }
                        else if (!eventSlot.link.Any())
                        {
                            if (!(sg is VFXSubgraphContext))
                            {
                                newEventPaths.Add(path.Concat(new int[] { currentFlowIndex }).ToList());
                            }
                            else
                            {
                                var sgsg = sg as VFXSubgraphContext;

                                var eventName = sgsg.GetInputFlowName(currentFlowIndex);

                                var eventCtx = sgsg.GetEventContext(eventName);
                                if (eventCtx != null)
                                {
                                    result[i].Add(new VFXContextLink()
                                    {
                                        slotIndex = 0, context = eventCtx
                                    });
                                }
                            }
                        }
                    }
                    defaultEventPaths.Clear();
                    defaultEventPaths.AddRange(newEventPaths);
                    newEventPaths.Clear();
                }
            }
            return(result);
        }
        private static VFXContext[] CollectSpawnersHierarchy(IEnumerable <VFXContext> vfxContext, ref SubgraphInfos subgraphContexts)
        {
            var initContext = vfxContext.Where(o => o.contextType == VFXContextType.Init).ToList();
            var spawnerList = CollectContextParentRecursively(initContext, ref subgraphContexts);

            return(spawnerList.Where(o => o.contextType == VFXContextType.Spawner).Reverse().ToArray());
        }
        private static List <VFXContext> CollectContextParentRecursively(IEnumerable <VFXContext> inputList, ref SubgraphInfos subgraphContexts)
        {
            var contextEffectiveInputLinks = subgraphContexts.contextEffectiveInputLinks;
            var contextList = inputList.SelectMany(o => contextEffectiveInputLinks[o].SelectMany(t => t)).Select(t => t.context).Distinct().ToList();

            if (contextList.Any(o => contextEffectiveInputLinks[o].Any()))
            {
                var parentContextList = CollectContextParentRecursively(contextList.Except(inputList), ref subgraphContexts);
                foreach (var context in parentContextList)
                {
                    if (!contextList.Contains(context))
                    {
                        contextList.Add(context);
                    }
                }
            }
            return(contextList);
        }