Ejemplo n.º 1
0
        private void Run_DoneAndUpdate(object sender, RoutedEventArgs e)
        {
            UpdateAlertCounter();

            if (RunFinished != null)
            {
                RunFinished?.Invoke(this, null);
            }
        }
        private string PlaceHitsounds(Arguments args, BackgroundWorker worker, DoWorkEventArgs _)
        {
            if (args.Zones.Count == 0)
            {
                return("There are no zones!");
            }

            var reader = EditorReaderStuff.GetFullEditorReaderOrNot();

            foreach (string path in args.Paths)
            {
                var      editor   = EditorReaderStuff.GetNewestVersionOrNot(path, reader);
                Beatmap  beatmap  = editor.Beatmap;
                Timeline timeline = beatmap.GetTimeline();

                for (int i = 0; i < timeline.TimelineObjects.Count; i++)
                {
                    var tlo = timeline.TimelineObjects[i];

                    var    column = args.Zones.FirstOrDefault();
                    double best   = double.MaxValue;
                    foreach (var c in args.Zones)
                    {
                        double dist = c.Distance(tlo.Origin.Pos);
                        if (dist < best)
                        {
                            best   = dist;
                            column = c;
                        }
                    }

                    if (column == null)
                    {
                        continue;
                    }

                    tlo.Filename     = column.Filename;
                    tlo.SampleSet    = column.SampleSet;
                    tlo.AdditionSet  = column.AdditionsSet;
                    tlo.CustomIndex  = column.CustomIndex;
                    tlo.SampleVolume = 0;
                    tlo.SetHitsound(column.Hitsound);
                    tlo.HitsoundsToOrigin();

                    UpdateProgressBar(worker, (int)(100f * i / beatmap.HitObjects.Count));
                }

                // Save the file
                editor.SaveFile();
            }

            // Do stuff
            RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, reader != null, args.Quick));

            return(args.Quick ? "" : "Done!");
        }
Ejemplo n.º 3
0
        private string Run_Program(Arguments args, BackgroundWorker worker, DoWorkEventArgs _) {
            var result = new MapCleaner.MapCleanerResult();

            bool editorRead = EditorReaderStuff.TryGetFullEditorReader(out var reader);

            if (args.Paths.Length == 1) {
                var editor = EditorReaderStuff.GetBeatmapEditor(args.Paths[0], reader, editorRead);

                List<TimingPoint> orgininalTimingPoints = new List<TimingPoint>();
                foreach (TimingPoint tp in editor.Beatmap.BeatmapTiming.TimingPoints) { orgininalTimingPoints.Add(tp.Copy()); }
                int oldTimingPointsCount = editor.Beatmap.BeatmapTiming.TimingPoints.Count;

                result.Add(MapCleaner.CleanMap(editor, args.CleanerArguments, worker));

                // Update result with removed count
                int removed = oldTimingPointsCount - editor.Beatmap.BeatmapTiming.TimingPoints.Count;
                result.TimingPointsRemoved += removed;

                List<TimingPoint> newTimingPoints = editor.Beatmap.BeatmapTiming.TimingPoints;
                Monitor_Differences(orgininalTimingPoints, newTimingPoints);

                // Save the file
                editor.SaveFile();
            } else {
                foreach (string path in args.Paths) {
                    var editor = EditorReaderStuff.GetBeatmapEditor(path, reader, editorRead);

                    int oldTimingPointsCount = editor.Beatmap.BeatmapTiming.TimingPoints.Count;

                    result.Add(MapCleaner.CleanMap(editor, args.CleanerArguments, worker));

                    // Update result with removed count
                    int removed = oldTimingPointsCount - editor.Beatmap.BeatmapTiming.TimingPoints.Count;
                    result.TimingPointsRemoved += removed;

                    // Save the file
                    editor.SaveFile();
                }
            }

            // Do stuff
            if (args.Quick)
                RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, editorRead));

            // Make an accurate message
            string message = $"Successfully {(result.TimingPointsRemoved < 0 ? "added" : "removed")} {Math.Abs(result.TimingPointsRemoved)} {(Math.Abs(result.TimingPointsRemoved) == 1 ? "greenline" : "greenlines")}" +
                (args.CleanerArguments.ResnapObjects ? $" and resnapped {result.ObjectsResnapped} {(result.ObjectsResnapped == 1 ? "object" : "objects")}" : "") + 
                (args.CleanerArguments.RemoveUnusedSamples ? $" and removed {result.SamplesRemoved} unused {(result.SamplesRemoved == 1 ? "sample" : "samples")}" : "") + "!";
            return args.Quick ? "" : message;
        }
Ejemplo n.º 4
0
        private string ExportPattern(PatternGalleryVm args, BackgroundWorker worker, DoWorkEventArgs _)
        {
            var reader = EditorReaderStuff.GetFullEditorReaderOrNot();
            var editor = EditorReaderStuff.GetNewestVersionOrNot(IOHelper.GetCurrentBeatmapOrCurrentBeatmap(), reader);

            var pattern = args.Patterns.FirstOrDefault(o => o.IsSelected);

            if (pattern == null)
            {
                throw new Exception("No pattern has been selected to export.");
            }

            var patternBeatmap = pattern.GetPatternBeatmap(args.FileHandler);

            var patternPlacer = args.OsuPatternPlacer;

            if (reader != null)
            {
                patternPlacer.PlaceOsuPatternAtTime(patternBeatmap, editor.Beatmap, reader.EditorTime(), false);
            }
            else
            {
                patternPlacer.PlaceOsuPattern(patternBeatmap, editor.Beatmap, protectBeatmapPattern: false);
            }

            editor.SaveFile();

            // Increase pattern use count and time
            pattern.UseCount++;
            pattern.LastUsedTime = DateTime.Now;

            // Complete progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(100);
            }

            // Do stuff
            if (args.Quick)
            {
                RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, reader != null));
            }

            return("Successfully exported pattern!");
        }
Ejemplo n.º 5
0
        public void OnTestEvent(string report)
        {
            XmlNode xmlNode = XmlHelper.CreateXmlNode(report);

            switch (xmlNode.Name)
            {
            case "start-test":
                TestStarting?.Invoke(new TestNodeEventArgs(TestAction.TestStarting, new TestNode(xmlNode)));
                break;

            case "start-suite":
                SuiteStarting?.Invoke(new TestNodeEventArgs(TestAction.SuiteStarting, new TestNode(xmlNode)));
                break;

            case "start-run":
                RunStarting?.Invoke(new RunStartingEventArgs(xmlNode.GetAttribute("count", -1)));
                break;

            case "test-case":
                ResultNode result = new ResultNode(xmlNode);
                _resultIndex[result.Id] = result;
                TestFinished?.Invoke(new TestResultEventArgs(TestAction.TestFinished, result));
                break;

            case "test-suite":
                result = new ResultNode(xmlNode);
                _resultIndex[result.Id] = result;
                SuiteFinished?.Invoke(new TestResultEventArgs(TestAction.SuiteFinished, result));
                break;

            case "test-run":
                result = new ResultNode(xmlNode);
                _resultIndex[result.Id] = result;
                RunFinished?.Invoke(new TestResultEventArgs(TestAction.RunFinished, result));
                break;
            }
        }
 private void ViewModelRunFinished(object sender, EventArgs args)
 {
     RunFinished?.Invoke(this, EventArgs.Empty);
 }
Ejemplo n.º 7
0
        private string Sliderate(SlideratorVm arg, BackgroundWorker worker)
        {
            // Make a position function for Sliderator
            Classes.Tools.Sliderator.PositionFunctionDelegate positionFunction;
            // Test if the function is a constant velocity
            bool constantVelocity;

            // We convert the graph GetValue function to a function that works like ms -> px
            // d is a value representing the number of milliseconds into the slider
            if (arg.GraphModeSetting == SlideratorVm.GraphMode.Velocity)
            {
                // Here we use SvGraphMultiplier to get an accurate conversion from SV to slider completion per beat
                // Completion = (100 * SliderMultiplier / PixelLength) * SV * Beats
                positionFunction = d =>
                                   arg.GraphState.GetIntegral(0, d * arg.BeatsPerMinute / 60000) * arg.SvGraphMultiplier *
                                   arg.PixelLength;

                constantVelocity = Precision.AlmostEquals(AnchorCollection.GetMaxValue(arg.GraphState.Anchors),
                                                          AnchorCollection.GetMinValue(arg.GraphState.Anchors));
            }
            else
            {
                positionFunction = d => arg.GraphState.GetValue(d * arg.BeatsPerMinute / 60000) * arg.PixelLength;

                constantVelocity = Precision.AlmostEquals(AnchorCollection.GetMaxDerivative(arg.GraphState.Anchors),
                                                          AnchorCollection.GetMinDerivative(arg.GraphState.Anchors));
            }

            // Dont do Sliderator if the velocity is constant AND equal to the new velocity
            var simplifyShape = constantVelocity && Precision.AlmostEquals(
                arg.PixelLength / arg.GraphBeats / arg.GlobalSv / 100,
                arg.NewVelocity);

            // Get the highest velocity occuring in the graph
            double velocity = arg.NewVelocity; // Velocity is in SV

            // Do bad stuff to the velocity to make sure its the same SV as after writing it to .osu code
            velocity = -100 / double.Parse((-100 / velocity).ToInvariant(), CultureInfo.InvariantCulture);
            // Other velocity is in px / ms
            var otherVelocity = velocity * arg.SvGraphMultiplier * arg.PixelLength * arg.BeatsPerMinute / 60000;

            // Time between timeline ticks for stream export
            var deltaT = 60000 / arg.BeatsPerMinute / arg.BeatSnapDivisor;

            // Update progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(10);
            }

            List <Vector2> slideration = new List <Vector2>();
            var            sliderator  = new Classes.Tools.Sliderator {
                PositionFunction  = positionFunction, MaxT = arg.GraphBeats / arg.BeatsPerMinute * 60000,
                Velocity          = otherVelocity,
                MinDendriteLength = arg.MinDendrite
            };

            if (!simplifyShape)
            {
                // Get slider path like from the hit object preview
                var sliderPath = new SliderPath(arg.VisibleHitObject.SliderType,
                                                arg.VisibleHitObject.GetAllCurvePoints().ToArray(),
                                                GetMaxCompletion(arg, arg.GraphState.Anchors) * arg.PixelLength);
                var path = new List <Vector2>();
                sliderPath.GetPathToProgress(path, 0, 1);

                // Update progressbar
                if (worker != null && worker.WorkerReportsProgress)
                {
                    worker.ReportProgress(20);
                }

                // Do Sliderator
                sliderator.SetPath(path);

                slideration = arg.ExportAsStream ?
                              sliderator.SliderateStream(deltaT) :
                              sliderator.Sliderate();

                // Check for some illegal output
                if (double.IsInfinity(sliderator.MaxS) || double.IsNaN(sliderator.MaxS) ||
                    slideration.Any(v => double.IsNaN(v.X) || double.IsNaN(v.Y)))
                {
                    return("Encountered unexpected values from Sliderator. Please check your input.");
                }
            }

            // Update progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(60);
            }

            // Exporting stuff
            BeatmapEditor editor;
            bool          editorRead = false;

            if (arg.DoEditorRead)
            {
                editor = EditorReaderStuff.GetNewestVersionOrNot(arg.Path, out _, out var exception);

                if (exception == null)
                {
                    editorRead = true;
                }

                arg.DoEditorRead = false;
            }
            else
            {
                editor = new BeatmapEditor(arg.Path);
            }

            var beatmap = editor.Beatmap;
            var timing  = beatmap.BeatmapTiming;

            // Get hit object that might be present at the export time or make a new one
            var hitObjectHere = beatmap.HitObjects.FirstOrDefault(o => Math.Abs(arg.ExportTime - o.Time) < 5) ??
                                new HitObject(arg.ExportTime, 0, SampleSet.Auto, SampleSet.Auto);


            // Clone the hit object to not affect the already existing hit object instance with changes
            var clone = new HitObject(hitObjectHere.GetLine())
            {
                IsCircle = arg.ExportAsStream, IsSpinner = false, IsHoldNote = false, IsSlider = !arg.ExportAsStream
            };

            // Update progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(70);
            }

            if (!arg.ExportAsStream)
            {
                // Give the new hit object the sliderated anchors
                if (simplifyShape)
                {
                    // The velocity is constant, so you can simplify to the original slider shape
                    clone.SetAllCurvePoints(arg.VisibleHitObject.GetAllCurvePoints());
                    clone.SliderType = arg.VisibleHitObject.SliderType;
                }
                else
                {
                    clone.SetAllCurvePoints(slideration);
                    clone.SliderType = PathType.Bezier;
                }

                clone.PixelLength    = sliderator.MaxS;
                clone.SliderVelocity = -100 / velocity;

                // Add hit object
                if (arg.ExportModeSetting == SlideratorVm.ExportMode.Add)
                {
                    beatmap.HitObjects.Add(clone);
                }
                else
                {
                    beatmap.HitObjects.Remove(hitObjectHere);
                    beatmap.HitObjects.Add(clone);
                }

                // Add SV
                var timingPointsChanges = new List <TimingPointsChange>();

                if (arg.DelegateToBpm)
                {
                    var tpAfter = timing.GetRedlineAtTime(clone.Time).Copy();
                    var tpOn    = tpAfter.Copy();

                    tpAfter.Offset = clone.Time;
                    tpOn.Offset    = clone.Time - 1; // This one will be on the slider

                    tpAfter.OmitFirstBarLine = true;
                    tpOn.OmitFirstBarLine    = true;

                    // Express velocity in BPM
                    tpOn.MpB /= -100 / clone.SliderVelocity;
                    // NaN SV results in removal of slider ticks
                    clone.SliderVelocity = arg.RemoveSliderTicks ? double.NaN : -100;

                    // Add redlines
                    timingPointsChanges.Add(new TimingPointsChange(tpOn, mpb: true, inherited: true, omitFirstBarLine: true, fuzzyness: 0));
                    timingPointsChanges.Add(new TimingPointsChange(tpAfter, mpb: true, inherited: true, omitFirstBarLine: true, fuzzyness: 0));

                    clone.Time -= 1;
                }

                // Add SV for every hit object so the SV doesnt change for anything else than the sliderated slider
                timingPointsChanges.AddRange(beatmap.HitObjects.Select(ho => {
                    var sv    = ho == clone ? ho.SliderVelocity : timing.GetSvAtTime(ho.Time);
                    var tp    = timing.GetTimingPointAtTime(ho.Time).Copy();
                    tp.MpB    = sv;
                    tp.Offset = ho.Time;
                    return(new TimingPointsChange(tp, mpb: true, fuzzyness: 0));
                }));

                TimingPointsChange.ApplyChanges(timing, timingPointsChanges);
            }
            else
            {
                // Add hit objects
                if (arg.ExportModeSetting == SlideratorVm.ExportMode.Override)
                {
                    beatmap.HitObjects.Remove(hitObjectHere);
                }

                double t = arg.ExportTime;
                foreach (var pos in slideration)
                {
                    clone.Pos  = pos;
                    clone.Time = t;
                    beatmap.HitObjects.Add(clone);

                    clone = new HitObject(clone.GetLine())
                    {
                        IsCircle = true, IsSpinner = false, IsHoldNote = false, IsSlider = false, NewCombo = false
                    };
                    t += deltaT;
                }
            }

            // Update progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(80);
            }

            beatmap.SortHitObjects();

            editor.SaveFile();

            // Complete progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(100);
            }

            // Do stuff
            if (arg.Quick)
            {
                RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, editorRead));
            }

            return(arg.Quick ? string.Empty : "Done!");
        }
Ejemplo n.º 8
0
        private string ExportPattern(PatternGalleryVm args, BackgroundWorker worker, DoWorkEventArgs _)
        {
            EditorReader reader;
            double       exportTime       = 0;
            bool         usePatternOffset = false;

            switch (args.ExportTimeMode)
            {
            case ExportTimeMode.Current:
                try {
                    reader     = EditorReaderStuff.GetFullEditorReader();
                    exportTime = reader.EditorTime();
                }
                catch (Exception e) {
                    throw new Exception("Could not fetch the current editor time.", e);
                }
                break;

            case ExportTimeMode.Pattern:
                reader           = EditorReaderStuff.GetFullEditorReaderOrNot();
                usePatternOffset = true;
                break;

            case ExportTimeMode.Custom:
                reader     = EditorReaderStuff.GetFullEditorReaderOrNot();
                exportTime = args.CustomExportTime;
                break;

            default:
                throw new ArgumentOutOfRangeException(nameof(ExportTimeMode), "Invalid value encountered");
            }

            var editor = EditorReaderStuff.GetNewestVersionOrNot(args.Paths[0], reader);

            var patternCount = args.Patterns.Count(o => o.IsSelected);

            if (patternCount == 0)
            {
                throw new Exception("No pattern has been selected to export.");
            }

            var patternPlacer = args.OsuPatternPlacer;

            foreach (var pattern in args.Patterns.Where(o => o.IsSelected))
            {
                var patternBeatmap = pattern.GetPatternBeatmap(args.FileHandler);

                if (usePatternOffset)
                {
                    patternPlacer.PlaceOsuPattern(patternBeatmap, editor.Beatmap, protectBeatmapPattern: false);
                }
                else
                {
                    patternPlacer.PlaceOsuPatternAtTime(patternBeatmap, editor.Beatmap, exportTime, false);
                }

                // Increase pattern use count and time
                pattern.UseCount++;
                pattern.LastUsedTime = DateTime.Now;
            }

            editor.SaveFile();

            // Complete progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(100);
            }

            // Do stuff
            RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, reader != null, args.Quick));

            return("Successfully exported pattern!");
        }
Ejemplo n.º 9
0
        private string Complete_Sliders(SliderCompletionatorVm arg, BackgroundWorker worker, DoWorkEventArgs _)
        {
            int slidersCompleted = 0;

            var reader = EditorReaderStuff.GetFullEditorReaderOrNot(out var editorReaderException1);

            if (arg.ImportModeSetting == SliderCompletionatorVm.ImportMode.Selected && editorReaderException1 != null)
            {
                throw new Exception("Could not fetch selected hit objects.", editorReaderException1);
            }

            foreach (string path in arg.Paths)
            {
                var editor = EditorReaderStuff.GetNewestVersionOrNot(path, reader, out var selected, out var editorReaderException2);

                if (arg.ImportModeSetting == SliderCompletionatorVm.ImportMode.Selected && editorReaderException2 != null)
                {
                    throw new Exception("Could not fetch selected hit objects.", editorReaderException2);
                }

                Beatmap beatmap = editor.Beatmap;
                Timing  timing  = beatmap.BeatmapTiming;

                List <HitObject> markedObjects = arg.ImportModeSetting switch {
                    SliderCompletionatorVm.ImportMode.Selected => selected,
                    SliderCompletionatorVm.ImportMode.Bookmarked => beatmap.GetBookmarkedObjects(),
                    SliderCompletionatorVm.ImportMode.Time => beatmap.QueryTimeCode(arg.TimeCode).ToList(),
                    SliderCompletionatorVm.ImportMode.Everything => beatmap.HitObjects,
                    _ => throw new ArgumentException("Unexpected import mode.")
                };

                for (int i = 0; i < markedObjects.Count; i++)
                {
                    HitObject ho = markedObjects[i];
                    if (ho.IsSlider)
                    {
                        double mpb = timing.GetMpBAtTime(ho.Time);

                        double oldDuration = timing.CalculateSliderTemporalLength(ho.Time, ho.PixelLength);
                        double oldLength   = ho.PixelLength;
                        double oldSv       = timing.GetSvAtTime(ho.Time);

                        double newDuration = arg.UseEndTime ? arg.EndTime == -1 ? oldDuration : arg.EndTime - ho.Time :
                                             arg.Duration == -1 ? oldDuration : timing.WalkBeatsInMillisecondTime(arg.Duration, ho.Time) - ho.Time;
                        double newLength = arg.Length == -1 ? oldLength : ho.GetSliderPath(fullLength: true).Distance *arg.Length;
                        double newSv     = arg.SliderVelocity == -1 ? oldSv : -100 / arg.SliderVelocity;

                        switch (arg.FreeVariableSetting)
                        {
                        case SliderCompletionatorVm.FreeVariable.Velocity:
                            newSv = -10000 * timing.SliderMultiplier * newDuration / (newLength * mpb);
                            break;

                        case SliderCompletionatorVm.FreeVariable.Duration:
                            // This actually doesn't get used anymore because the .osu doesn't store the duration
                            newDuration = newLength * newSv * mpb / (-10000 * timing.SliderMultiplier);
                            break;

                        case SliderCompletionatorVm.FreeVariable.Length:
                            newLength = -10000 * timing.SliderMultiplier * newDuration / (newSv * mpb);
                            break;

                        default:
                            throw new ArgumentException("Unexpected free variable setting.");
                        }

                        if (double.IsNaN(newSv))
                        {
                            throw new Exception("Encountered NaN slider velocity. Make sure none of the inputs are zero.");
                        }

                        if (newDuration < 0)
                        {
                            throw new Exception("Encountered slider with negative duration. Make sure the end time is greater than the end time of all selected sliders.");
                        }

                        ho.SliderVelocity = newSv;
                        ho.PixelLength    = newLength;

                        // Scale anchors to completion
                        if (arg.MoveAnchors)
                        {
                            ho.SetAllCurvePoints(SliderPathUtil.MoveAnchorsToLength(
                                                     ho.GetAllCurvePoints(), ho.SliderType, ho.PixelLength, out var pathType));
                            ho.SliderType = pathType;
                        }

                        slidersCompleted++;
                    }
                    if (worker != null && worker.WorkerReportsProgress)
                    {
                        worker.ReportProgress(i / markedObjects.Count);
                    }
                }

                // Reconstruct SliderVelocity
                List <TimingPointsChange> timingPointsChanges = new List <TimingPointsChange>();
                // Add Hitobject stuff
                foreach (HitObject ho in beatmap.HitObjects)
                {
                    // SliderVelocity changes
                    if (ho.IsSlider)
                    {
                        if (markedObjects.Contains(ho) && arg.DelegateToBpm)
                        {
                            var tpAfter = timing.GetRedlineAtTime(ho.Time).Copy();
                            var tpOn    = tpAfter.Copy();

                            tpAfter.Offset = ho.Time;
                            tpOn.Offset    = ho.Time - 1; // This one will be on the slider

                            tpAfter.OmitFirstBarLine = true;
                            tpOn.OmitFirstBarLine    = true;

                            // Express velocity in BPM
                            tpOn.MpB *= ho.SliderVelocity / -100;
                            // NaN SV results in removal of slider ticks
                            ho.SliderVelocity = arg.RemoveSliderTicks ? double.NaN : -100;

                            // Add redlines
                            timingPointsChanges.Add(new TimingPointsChange(tpOn, mpb: true, unInherited: true, omitFirstBarLine: true, fuzzyness: Precision.DOUBLE_EPSILON));
                            timingPointsChanges.Add(new TimingPointsChange(tpAfter, mpb: true, unInherited: true, omitFirstBarLine: true, fuzzyness: Precision.DOUBLE_EPSILON));

                            ho.Time -= 1;
                        }

                        TimingPoint tp = ho.TimingPoint.Copy();
                        tp.Offset = ho.Time;
                        tp.MpB    = ho.SliderVelocity;
                        timingPointsChanges.Add(new TimingPointsChange(tp, mpb: true, fuzzyness: Precision.DOUBLE_EPSILON));
                    }
                }

                // Add the new SliderVelocity changes
                TimingPointsChange.ApplyChanges(timing, timingPointsChanges);

                // Save the file
                editor.SaveFile();
            }

            // Complete progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(100);
            }

            // Do stuff
            RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, reader != null, arg.Quick));

            // Make an accurate message
            string message = "";

            if (Math.Abs(slidersCompleted) == 1)
            {
                message += "Successfully completed " + slidersCompleted + " slider!";
            }
            else
            {
                message += "Successfully completed " + slidersCompleted + " sliders!";
            }
            return(arg.Quick ? "" : message);
        }
        private string Complete_Sliders(Arguments arg, BackgroundWorker worker, DoWorkEventArgs _)
        {
            int slidersCompleted = 0;

            bool editorRead = EditorReaderStuff.TryGetFullEditorReader(out var reader);

            foreach (string path in arg.Paths)
            {
                var editor = EditorReaderStuff.GetBeatmapEditor(path, reader, editorRead, out var selected, out var editorActuallyRead);

                if (arg.SelectionMode == 0 && !editorActuallyRead)
                {
                    return(EditorReaderStuff.SelectedObjectsReadFailText);
                }

                Beatmap          beatmap       = editor.Beatmap;
                Timing           timing        = beatmap.BeatmapTiming;
                List <HitObject> markedObjects = arg.SelectionMode == 0 ? selected :
                                                 arg.SelectionMode == 1 ? beatmap.GetBookmarkedObjects() :
                                                 beatmap.HitObjects;

                for (int i = 0; i < markedObjects.Count; i++)
                {
                    HitObject ho = markedObjects[i];
                    if (ho.IsSlider)
                    {
                        double oldSpatialLength = ho.PixelLength;
                        double newSpatialLength = arg.SpatialLength != -1 ? ho.GetSliderPath(fullLength: true).Distance *arg.SpatialLength : oldSpatialLength;

                        double oldTemporalLength = timing.CalculateSliderTemporalLength(ho.Time, ho.PixelLength);
                        double newTemporalLength = arg.TemporalLength != -1 ? timing.GetMpBAtTime(ho.Time) * arg.TemporalLength : oldTemporalLength;

                        double oldSv = timing.GetSvAtTime(ho.Time);
                        double newSv = oldSv / ((newSpatialLength / oldSpatialLength) / (newTemporalLength / oldTemporalLength));

                        ho.SliderVelocity = newSv;
                        ho.PixelLength    = newSpatialLength;

                        // Scale anchors to completion
                        if (arg.MoveAnchors)
                        {
                            ho.SetAllCurvePoints(SliderPathUtil.MoveAnchorsToLength(
                                                     ho.GetAllCurvePoints(), ho.SliderType, ho.PixelLength, out var pathType));
                            ho.SliderType = pathType;
                        }

                        slidersCompleted++;
                    }
                    if (worker != null && worker.WorkerReportsProgress)
                    {
                        worker.ReportProgress(i / markedObjects.Count);
                    }
                }

                // Reconstruct SliderVelocity
                List <TimingPointsChange> timingPointsChanges = new List <TimingPointsChange>();
                // Add Hitobject stuff
                foreach (HitObject ho in beatmap.HitObjects)
                {
                    if (ho.IsSlider) // SliderVelocity changes
                    {
                        TimingPoint tp = ho.TimingPoint.Copy();
                        tp.Offset = ho.Time;
                        tp.MpB    = ho.SliderVelocity;
                        timingPointsChanges.Add(new TimingPointsChange(tp, mpb: true));
                    }
                }

                // Add the new SliderVelocity changes
                TimingPointsChange.ApplyChanges(timing, timingPointsChanges);

                // Save the file
                editor.SaveFile();
            }

            // Complete progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(100);
            }

            // Do stuff
            if (arg.Quick)
            {
                RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, editorRead));
            }

            // Make an accurate message
            string message = "";

            if (Math.Abs(slidersCompleted) == 1)
            {
                message += "Successfully completed " + slidersCompleted + " slider!";
            }
            else
            {
                message += "Successfully completed " + slidersCompleted + " sliders!";
            }
            return(arg.Quick ? "" : message);
        }
Ejemplo n.º 11
0
        private string Merge_Sliders(SliderMergerVm arg, BackgroundWorker worker)
        {
            var slidersMerged = 0;

            var reader = EditorReaderStuff.GetFullEditorReaderOrNot(out var editorReaderException1);

            if (arg.ImportModeSetting == 0 && editorReaderException1 != null)
            {
                throw new Exception("Could not fetch selected hit objects.", editorReaderException1);
            }

            foreach (var path in arg.Paths)
            {
                var editor = EditorReaderStuff.GetNewestVersionOrNot(path, reader, out var selected, out var editorReaderException2);

                if (arg.ImportModeSetting == SliderMergerVm.ImportMode.Selected && editorReaderException2 != null)
                {
                    throw new Exception("Could not fetch selected hit objects.", editorReaderException2);
                }

                var beatmap       = editor.Beatmap;
                var markedObjects = arg.ImportModeSetting == 0 ? selected :
                                    arg.ImportModeSetting == SliderMergerVm.ImportMode.Bookmarked ? beatmap.GetBookmarkedObjects() :
                                    arg.ImportModeSetting == SliderMergerVm.ImportMode.Time ? beatmap.QueryTimeCode(arg.TimeCode).ToList() :
                                    beatmap.HitObjects;

                var mergeLast = false;
                for (var i = 0; i < markedObjects.Count - 1; i++)
                {
                    if (worker != null && worker.WorkerReportsProgress)
                    {
                        worker.ReportProgress(i / markedObjects.Count);
                    }

                    var ho1 = markedObjects[i];
                    var ho2 = markedObjects[i + 1];

                    var lastPos1 = ho1.IsSlider
                        ? arg.MergeOnSliderEnd ? ho1.GetSliderPath().PositionAt(1) : ho1.CurvePoints.Last()
                        : ho1.Pos;

                    double dist = Vector2.Distance(lastPos1, ho2.Pos);

                    if (dist > arg.Leniency)
                    {
                        mergeLast = false;
                        continue;
                    }

                    if (ho1.IsSlider && ho2.IsSlider)
                    {
                        if (arg.MergeOnSliderEnd)
                        {
                            // In order to merge on the slider end we first move the anchors such that the last anchor is exactly on the slider end
                            // After that merge as usual
                            ho1.SetAllCurvePoints(SliderPathUtil.MoveAnchorsToLength(
                                                      ho1.GetAllCurvePoints(), ho1.SliderType, ho1.PixelLength, out var pathType));
                            ho1.SliderType = pathType;
                        }

                        var sp1 = BezierConverter.ConvertToBezier(ho1.SliderPath).ControlPoints;
                        var sp2 = BezierConverter.ConvertToBezier(ho2.SliderPath).ControlPoints;

                        double extraLength = 0;
                        switch (arg.ConnectionModeSetting)
                        {
                        case SliderMergerVm.ConnectionMode.Move:
                            Move(sp2, sp1.Last() - sp2.First());
                            break;

                        case SliderMergerVm.ConnectionMode.Linear:
                            sp1.Add(sp1.Last());
                            sp1.Add(sp2.First());
                            extraLength = (ho1.CurvePoints.Last() - ho2.Pos).Length;
                            break;
                        }

                        var mergedAnchors = sp1.Concat(sp2).ToList();
                        mergedAnchors.Round();

                        var linearLinear = arg.LinearOnLinear && IsLinearBezier(sp1) && IsLinearBezier(sp2);
                        if (linearLinear)
                        {
                            for (var j = 0; j < mergedAnchors.Count - 1; j++)
                            {
                                if (mergedAnchors[j] != mergedAnchors[j + 1])
                                {
                                    continue;
                                }
                                mergedAnchors.RemoveAt(j);
                                j--;
                            }
                        }

                        var mergedPath = new SliderPath(linearLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(),
                                                        ho1.PixelLength + ho2.PixelLength + extraLength);
                        ho1.SliderPath = mergedPath;

                        beatmap.HitObjects.Remove(ho2);
                        markedObjects.Remove(ho2);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else if (ho1.IsSlider && ho2.IsCircle)
                    {
                        var sp1 = BezierConverter.ConvertToBezier(ho1.SliderPath).ControlPoints;

                        sp1.Add(sp1.Last());
                        sp1.Add(ho2.Pos);
                        var extraLength = (ho1.CurvePoints.Last() - ho2.Pos).Length;

                        var mergedAnchors = sp1;
                        mergedAnchors.Round();

                        var linearLinear = arg.LinearOnLinear && IsLinearBezier(sp1);
                        if (linearLinear)
                        {
                            for (var j = 0; j < mergedAnchors.Count - 1; j++)
                            {
                                if (mergedAnchors[j] != mergedAnchors[j + 1])
                                {
                                    continue;
                                }
                                mergedAnchors.RemoveAt(j);
                                j--;
                            }
                        }

                        var mergedPath = new SliderPath(linearLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(), ho1.PixelLength + extraLength);
                        ho1.SliderPath = mergedPath;

                        beatmap.HitObjects.Remove(ho2);
                        markedObjects.Remove(ho2);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else if (ho1.IsCircle && ho2.IsSlider)
                    {
                        var sp2 = BezierConverter.ConvertToBezier(ho2.SliderPath).ControlPoints;

                        sp2.Insert(0, sp2.First());
                        sp2.Insert(0, ho1.Pos);
                        var extraLength = (ho1.Pos - ho2.Pos).Length;

                        var mergedAnchors = sp2;
                        mergedAnchors.Round();

                        var linearLinear = arg.LinearOnLinear && IsLinearBezier(sp2);
                        if (linearLinear)
                        {
                            for (var j = 0; j < mergedAnchors.Count - 1; j++)
                            {
                                if (mergedAnchors[j] != mergedAnchors[j + 1])
                                {
                                    continue;
                                }
                                mergedAnchors.RemoveAt(j);
                                j--;
                            }
                        }

                        var mergedPath = new SliderPath(linearLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(), ho2.PixelLength + extraLength);
                        ho2.SliderPath = mergedPath;

                        beatmap.HitObjects.Remove(ho1);
                        markedObjects.Remove(ho1);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else if (ho1.IsCircle && ho2.IsCircle)
                    {
                        var mergedAnchors = new List <Vector2> {
                            ho1.Pos, ho2.Pos
                        };

                        var mergedPath = new SliderPath(arg.LinearOnLinear ? PathType.Linear : PathType.Bezier, mergedAnchors.ToArray(), (ho1.Pos - ho2.Pos).Length);
                        ho1.SliderPath    = mergedPath;
                        ho1.IsCircle      = false;
                        ho1.IsSlider      = true;
                        ho1.Repeat        = 1;
                        ho1.EdgeHitsounds = new List <int> {
                            ho1.GetHitsounds(), ho2.GetHitsounds()
                        };
                        ho1.EdgeSampleSets = new List <SampleSet> {
                            ho1.SampleSet, ho2.SampleSet
                        };
                        ho1.EdgeAdditionSets = new List <SampleSet> {
                            ho1.AdditionSet, ho2.AdditionSet
                        };

                        beatmap.HitObjects.Remove(ho2);
                        markedObjects.Remove(ho2);
                        i--;

                        slidersMerged++;
                        if (!mergeLast)
                        {
                            slidersMerged++;
                        }
                        mergeLast = true;
                    }
                    else
                    {
                        mergeLast = false;
                    }
                }

                // Save the file
                editor.SaveFile();
            }

            // Complete progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(100);
            }

            // Do stuff
            if (arg.Quick)
            {
                RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, reader != null));
            }

            // Make an accurate message
            var message = "";

            if (Math.Abs(slidersMerged) == 1)
            {
                message += "Successfully merged " + slidersMerged + " slider!";
            }
            else
            {
                message += "Successfully merged " + slidersMerged + " sliders!";
            }
            return(arg.Quick ? "" : message);
        }
        private string Adjust_Timing(Arguments arg, BackgroundWorker worker, DoWorkEventArgs _)
        {
            // Count
            int RedlinesAdded = 0;

            bool editorRead = EditorReaderStuff.TryGetFullEditorReader(out var reader);

            foreach (string path in arg.Paths)
            {
                // Open beatmap
                var     editor  = EditorReaderStuff.GetBeatmapEditor(path, reader, editorRead);
                Beatmap beatmap = editor.Beatmap;
                Timing  timing  = beatmap.BeatmapTiming;

                // Get all the times to snap
                List <Marker> markers = new List <Marker>();
                if (arg.Objects)
                {
                    foreach (HitObject ho in beatmap.HitObjects)
                    {
                        markers.Add(new Marker(ho.Time));
                    }
                }
                if (arg.Bookmarks)
                {
                    foreach (double time in beatmap.GetBookmarks())
                    {
                        markers.Add(new Marker(time));
                    }
                }
                if (arg.Greenlines)
                {
                    // Get the offsets of greenlines
                    foreach (TimingPoint tp in timing.TimingPoints)
                    {
                        if (!tp.Uninherited)
                        {
                            markers.Add(new Marker(tp.Offset));
                        }
                    }
                }
                if (arg.Redlines)
                {
                    // Get the offsets of redlines
                    foreach (TimingPoint tp in timing.TimingPoints)
                    {
                        if (tp.Uninherited)
                        {
                            markers.Add(new Marker(tp.Offset));
                        }
                    }
                }

                // Update progressbar
                if (worker != null && worker.WorkerReportsProgress)
                {
                    worker.ReportProgress(20);
                }

                // Sort the markers
                markers = markers.OrderBy(o => o.Time).ToList();

                // Calculate the beats between time and the last time or redline for each time
                // Time the same is 0
                // Time a little after is smallest snap
                for (int i = 0; i < markers.Count; i++)
                {
                    Marker marker = markers[i];
                    double time   = marker.Time;

                    TimingPoint redline = timing.GetRedlineAtTime(time - 1);

                    // Resnap to that redline only
                    double resnappedTime = timing.Resnap(time, arg.Snap1, arg.Snap2, false, redline);

                    // Calculate beats from the redline
                    double beatsFromRedline = (resnappedTime - redline.Offset) / redline.MpB;

                    // Avoid problems
                    if (MathHelper.ApproximatelyEquivalent(beatsFromRedline, 0, 0.0001))
                    {
                        beatsFromRedline = 1 / Math.Max(arg.Snap1, arg.Snap2);
                    }
                    if (time == redline.Offset)
                    {
                        beatsFromRedline = 0;
                    }

                    // Initialize the beats from last marker
                    double beatsFromLastMarker = beatsFromRedline;

                    // Get the times between redline and this time
                    List <Marker> timesBefore = markers.Where(o => o.Time <time && o.Time> redline.Offset).ToList();

                    if (timesBefore.Count > 0)
                    {
                        // Get the last time info
                        double lastTime       = timesBefore.Last().Time;
                        double resnappedTimeL = timing.Resnap(lastTime, arg.Snap1, arg.Snap2, false);

                        // Change the beats from last marker
                        beatsFromLastMarker = (resnappedTime - resnappedTimeL) / redline.MpB;

                        // Avoid problems
                        if (MathHelper.ApproximatelyEquivalent(beatsFromLastMarker, 0, 0.0001))
                        {
                            beatsFromLastMarker = 1f / Math.Max(arg.Snap1, arg.Snap2);
                        }
                        if (lastTime == time)
                        {
                            beatsFromLastMarker = 0;
                        }
                    }

                    // Set the variable
                    marker.BeatsFromLastMarker = beatsFromLastMarker;
                }

                // Remove redlines except the first redline
                if (!arg.Redlines)
                {
                    var first = timing.TimingPoints.FirstOrDefault(o => o.Uninherited);
                    timing.TimingPoints.RemoveAll(o => o.Uninherited && o != first);
                }

                // Update progressbar
                if (worker != null && worker.WorkerReportsProgress)
                {
                    worker.ReportProgress(40);
                }

                // Loop through all the markers
                for (int i = 0; i < markers.Count; i++)
                {
                    Marker marker = markers[i];
                    double time   = marker.Time;

                    TimingPoint redline = timing.GetRedlineAtTime(time - 1);

                    double beatsFromLastMarker = arg.BeatsBetween != -1 ? arg.BeatsBetween : marker.BeatsFromLastMarker;

                    // Skip if 0 beats from last marker
                    if (beatsFromLastMarker == 0)
                    {
                        continue;
                    }

                    // Get the times between redline and this time including this time
                    List <Marker> markersBefore = markers.Where(o => o.Time <time && o.Time> redline.Offset).ToList();
                    markersBefore.Add(marker);

                    // Calculate MpB
                    // Average MpB from timesBefore and use time from redline
                    double mpb = 0;
                    double beatsFromRedline = 0;
                    foreach (Marker markerB in markersBefore)
                    {
                        beatsFromRedline += markerB.BeatsFromLastMarker;
                        mpb += GetMpB(markerB.Time - redline.Offset, beatsFromRedline, 0);
                    }
                    mpb /= markersBefore.Count;

                    // Check if this MpB doesn't make the markers go offsnap too far
                    bool canChangeRedline = CheckMpB(mpb, markersBefore, redline, arg);

                    // Make changes
                    if (canChangeRedline)
                    {
                        // Round the MpB to human values first
                        mpb = HumanRoundMpB(mpb, markersBefore, redline, arg);

                        // Change the MpB of the redline
                        redline.MpB = mpb;
                    }
                    else
                    {
                        // Get the last time info and not the current
                        markersBefore.Remove(marker);
                        double lastTime = markersBefore.Last().Time;

                        // Make new redline
                        TimingPoint newRedline    = redline.Copy();
                        TimingPoint lastHitsounds = timing.GetTimingPointAtTime(lastTime + 5);
                        newRedline.Offset           = lastTime;
                        newRedline.OmitFirstBarLine = arg.OmitBarline; // Set omit to the argument
                        newRedline.Kiai             = lastHitsounds.Kiai;
                        newRedline.SampleIndex      = lastHitsounds.SampleIndex;
                        newRedline.SampleSet        = lastHitsounds.SampleSet;
                        newRedline.Volume           = lastHitsounds.Volume;
                        timing.TimingPoints.Add(newRedline);
                        timing.Sort();

                        // Set the MpB
                        newRedline.MpB = GetMpB(time - lastTime, beatsFromLastMarker, arg.Leniency);

                        // Update the counter
                        RedlinesAdded++;
                    }

                    // Update progressbar
                    if (worker != null && worker.WorkerReportsProgress)
                    {
                        worker.ReportProgress(i * 60 / markers.Count + 40);
                    }
                }

                // Save the file
                editor.SaveFile();
            }


            // Complete progressbar
            if (worker != null && worker.WorkerReportsProgress)
            {
                worker.ReportProgress(100);
            }

            // Do QuickRun stuff
            if (arg.Quick)
            {
                RunFinished?.Invoke(this, new RunToolCompletedEventArgs(true, editorRead));
            }

            // Make an accurate message
            string message = "Successfully added ";

            message += RedlinesAdded;
            if (Math.Abs(RedlinesAdded) == 1)
            {
                message += " redlines!";
            }
            else
            {
                message += " redlines!";
            }

            return(arg.Quick ? string.Empty : message);
        }