Esempio n. 1
0
    public void GenerateStrobe(IEnumerable <StrobeGeneratorPass> passes)
    {
        List <BeatmapObject>   generatedObjects = new List <BeatmapObject>();
        IEnumerable <MapEvent> containers       = SelectionController.SelectedObjects.Where(x => x is MapEvent).Cast <MapEvent>(); //Grab selected objects
        List <BeatmapObject>   oldEvents        = new List <BeatmapObject>();                                                      //For the Action
        //Order by type, then by descending time
        var groupings = containers.GroupBy(x => x._type);

        foreach (var group in groupings)
        {
            int type = group.Key;

            // Try and do this in one pass so we don't tank performance
            var partitioned = group.GroupBy(y => y.IsLightIdEvent ? EventsContainer.PropMode.Light : EventsContainer.PropMode.Off)
                              .ToDictionary(z => z.Key, modeGroup =>
                                            modeGroup.Key == EventsContainer.PropMode.Off ? modeGroup.GroupBy(y => 1) : modeGroup.GroupBy(y => y.LightId[0]));

            foreach (var mode in partitioned)
            {
                var propMode   = mode.Key;
                var propGroups = mode.Value;

                foreach (var propGroup in propGroups)
                {
                    var customData = propGroup.FirstOrDefault()?._customData;
                    var lightIds   = customData == null ? null : customData["_lightID"];
                    if (propGroup.Count() >= 2)
                    {
                        IEnumerable <MapEvent> ordered = propGroup.OrderByDescending(x => x._time);
                        MapEvent end   = ordered.First();
                        MapEvent start = ordered.Last();

                        IEnumerable <MapEvent> containersBetween = eventsContainer.LoadedObjects.GetViewBetween(start, end).Cast <MapEvent>().Where(x =>
                                                                                                                                                    x._type == start._type && //Grab all events between start and end point.
                                                                                                                                                                              // This check isn't perfect but I think it covers anything that could occur without manual mischief
                                                                                                                                                    (propMode != EventsContainer.PropMode.Light || start.IsLightIdEvent == x.IsLightIdEvent && (!start.IsLightIdEvent || x.LightId.Contains(start.LightId[0])))
                                                                                                                                                    );
                        oldEvents.AddRange(containersBetween);

                        foreach (StrobeGeneratorPass pass in passes)
                        {
                            IEnumerable <MapEvent> validEvents = containersBetween.Where(x => pass.IsEventValidForPass(x));
                            if (validEvents.Count() >= 2)
                            {
                                List <MapEvent> strobePassGenerated = pass.StrobePassForLane(validEvents.OrderBy(x => x._time), type, propMode, lightIds).ToList();
                                // REVIEW: Perhaps implement a "smart merge" to conflicting events, rather than outright removing those from previous passes
                                // Now, what would a "smart merge" entail? I have no clue.
                                generatedObjects.RemoveAll(x => strobePassGenerated.Any(y => y.IsConflictingWith(x)));
                                generatedObjects.AddRange(strobePassGenerated);
                            }
                        }
                    }
                }
            }
        }
        generatedObjects.OrderBy(x => x._time);
        if (generatedObjects.Count > 0)
        {
            //Delete conflicting vanilla events
            foreach (MapEvent e in oldEvents)
            {
                eventsContainer.DeleteObject(e, false, false);
            }
            //Spawn objects that were generated
            foreach (MapEvent data in generatedObjects)
            {
                eventsContainer.SpawnObject(data, false, false);
            }
            eventsContainer.RefreshPool(true);
            //yield return PersistentUI.Instance.FadeOutLoadingScreen();
            SelectionController.DeselectAll();
            SelectionController.SelectedObjects = new HashSet <BeatmapObject>(generatedObjects);
            SelectionController.SelectionChangedEvent?.Invoke();
            SelectionController.RefreshSelectionMaterial(false);
            BeatmapActionContainer.AddAction(new StrobeGeneratorGenerationAction(generatedObjects.ToArray(), oldEvents.ToArray()));
        }
    }