private string Run_Program(List <string> arguments, BackgroundWorker worker, DoWorkEventArgs e) { // Retrieve all arguments string path = arguments[0]; bool volumeSliders = arguments[1] == "True"; bool samplesetSliders = arguments[2] == "True"; bool volumeSpinners = arguments[3] == "True"; bool samplesetSpinners = arguments[4] == "True"; bool removeSliderendMuting = arguments[5] == "True"; bool resnapObjects = arguments[6] == "True"; bool resnapBookmarks = arguments[7] == "True"; int snap1 = int.Parse(arguments[8].Split('/')[1]); int snap2 = int.Parse(arguments[9].Split('/')[1]); Editor editor = new Editor(path); int greenlinesRemoved = 0; int timingpointsProcessed = 0; int num_timingPoints = editor.Beatmap.BeatmapTiming.TimingPoints.Count; Timing timing = editor.Beatmap.BeatmapTiming; Timeline timeline = editor.Beatmap.GetTimeline(); int mode = editor.Beatmap.General["Mode"].Value; List <TimingPoint> newTimingPoints = new List <TimingPoint>(); double lastMpB = -100; int lastSampleSet = 1; int lastSampleIndex = 0; double lastVolume = 100; bool lastKiai = false; foreach (TimingPoint tp in editor.Beatmap.BeatmapTiming.TimingPoints) { Print("evaluating timingpoint: " + tp.GetLine()); bool redUseful = false; bool kiaiUseful = false; bool svUseful = false; bool volumeUseful = false; bool samplesetUseful = false; bool sampleindexUseful = false; double firstUsefulTime = 1E99; if (tp.Inherited) // If it's a red line it's usefull { redUseful = true; firstUsefulTime = tp.Offset; Print("usefull by redline"); } if (tp.Kiai != lastKiai) // Kiai toggle is instant usefull and no move { kiaiUseful = true; firstUsefulTime = tp.Offset; Print("usefull by kiai"); } // Get the object parts on the greenline affect range double startTime = tp.Offset; double endTime = editor.Beatmap.BeatmapTiming.GetTimingPointEffectiveRange(tp); // Not including this exact time in the range Print("startTime: " + startTime + " , endTime: " + endTime); Timeline timeLineObjectsInRange = timeline.GetTimeLineObjectsInRange(startTime, endTime); List <HitObject> bodiesInRange = editor.Beatmap.GetHitObjectsWithRangeInRange(startTime, endTime); bool svChange = tp.MpB != lastMpB; bool volumeChange = tp.Volume != lastVolume; bool samplesetChange = tp.SampleSet != lastSampleSet; bool sampleindexChange = tp.SampleIndex != lastSampleIndex; if (svChange && !tp.Inherited) { // SV change is always impactfull in taiko and mania if (mode == 3 || mode == 1) { svUseful = true; firstUsefulTime = tp.Offset; Print("usefull by gamemode SV"); } // Check for sliderhead foreach (TimelineObject tlo in timeLineObjectsInRange.TimeLineObjects) { if (tlo.IsSliderHead) { svUseful = true; if (tlo.Time < firstUsefulTime) { firstUsefulTime = tlo.Time; } Print("usefull by SV sliderhead"); } } } if (volumeChange) { foreach (TimelineObject tlo in timeLineObjectsInRange.TimeLineObjects) { if (tlo.HasHitsound) { if (removeSliderendMuting && tlo.IsSliderEnd && tp.Volume == 5) { continue; } volumeUseful = true; if (tlo.Time < firstUsefulTime) { firstUsefulTime = tlo.Time; } Print("usefull by volume hitsound"); } } foreach (HitObject ho in bodiesInRange) // Check for purpose in slider/spinner bodies { if ((ho.IsSlider) && volumeSliders) { volumeUseful = true; if (ho.Time > tp.Offset && ho.Time < firstUsefulTime) { firstUsefulTime = ho.Time; } else { firstUsefulTime = tp.Offset; } Print("usefull by volume sliderslide"); } else if (ho.IsSpinner && volumeSpinners) { volumeUseful = true; if (ho.Time > tp.Offset && ho.Time < firstUsefulTime) { firstUsefulTime = ho.Time; } else { firstUsefulTime = tp.Offset; } Print("usefull by volume spinnerspin"); } } } if (samplesetChange) { foreach (TimelineObject tlo in timeLineObjectsInRange.TimeLineObjects) { if (tlo.HasHitsound && tlo.SampleSet == 0) // 0 is Auto so it will be affected by greenlines { samplesetUseful = true; if (tlo.Time < firstUsefulTime) { firstUsefulTime = tlo.Time; } Print("usefull by sampleset hitsound"); } } foreach (HitObject ho in bodiesInRange) // Check for purpose in slider/spinner bodies { if ((ho.IsSlider) && samplesetSliders) { samplesetUseful = true; if (ho.Time > tp.Offset && ho.Time < firstUsefulTime) { firstUsefulTime = ho.Time; } else { firstUsefulTime = tp.Offset; } Print("usefull by sampleset sliderslide"); } else if (ho.IsSpinner && samplesetSpinners) { samplesetUseful = true; if (ho.Time > tp.Offset && ho.Time < firstUsefulTime) { firstUsefulTime = ho.Time; } else { firstUsefulTime = tp.Offset; } Print("usefull by sampleset spinnerspin"); } } } if (sampleindexChange) { foreach (TimelineObject tlo in timeLineObjectsInRange.TimeLineObjects) { if (tlo.HasHitsound) // 0 is Auto so it will be affected by greenlines { sampleindexUseful = true; if (tlo.Time < firstUsefulTime) { firstUsefulTime = tlo.Time; } Print("usefull by sampleindex hitsound"); } } foreach (HitObject ho in bodiesInRange) // Check for purpose in slider/spinner bodies { if ((ho.IsSlider) && samplesetSliders) { sampleindexUseful = true; if (ho.Time > tp.Offset && ho.Time < firstUsefulTime) { firstUsefulTime = ho.Time; } else { firstUsefulTime = tp.Offset; } Print("usefull by sampleindex sliderslide"); } else if (ho.IsSpinner && samplesetSpinners) { sampleindexUseful = true; if (ho.Time > tp.Offset && ho.Time < firstUsefulTime) { firstUsefulTime = ho.Time; } else { firstUsefulTime = tp.Offset; } Print("usefull by sampleindex spinnerspin"); } } } // Only let them have the thing that made them usefull if (redUseful) { lastMpB = -100; } // Redlines have 1.00x SV else { if (svUseful) { lastMpB = tp.MpB; } else { tp.MpB = lastMpB; } } // Don't change the MpB of the redline if (kiaiUseful) { lastKiai = tp.Kiai; } else { tp.Kiai = lastKiai; } if (volumeUseful) { lastVolume = tp.Volume; } else { tp.Volume = lastVolume; } if (samplesetUseful) { lastSampleSet = tp.SampleSet; } else { tp.SampleSet = lastSampleSet; } if (sampleindexUseful) { lastSampleIndex = tp.SampleIndex; } else { tp.SampleIndex = lastSampleIndex; } bool usefull = redUseful || kiaiUseful || svUseful || samplesetUseful || sampleindexUseful || volumeUseful; // Move to earliest usefull thing if (usefull) { tp.Offset = firstUsefulTime; newTimingPoints.Add(tp); } else { greenlinesRemoved += 1; } timingpointsProcessed += 1; // Update progressbar if (worker != null) { if (worker.WorkerReportsProgress) { int percentComplete = (int)((timingpointsProcessed / num_timingPoints) * 100); worker.ReportProgress(percentComplete); } } } // Replace the timingpoints timing.TimingPoints = newTimingPoints; if (resnapObjects) { // Snap all objects and timingpoints foreach (TimingPoint tp in timing.TimingPoints) { tp.Offset = Math.Floor(timing.Resnap(tp.Offset, snap1, snap2)); } foreach (HitObject ho in editor.Beatmap.HitObjects) { ho.Time = Math.Floor(timing.Resnap(ho.Time, snap1, snap2)); } } if (resnapBookmarks) { // Snap the bookmarks List <double> newBookmarks = new List <double>(); foreach (double bookmark in editor.Beatmap.GetBookmarks()) { newBookmarks.Add(timing.Resnap(bookmark, snap1, snap2)); } editor.Beatmap.SetBookmarks(newBookmarks); } editor.SaveFile(); return("Succesfully removed " + greenlinesRemoved + " greenlines!"); }
private string Run_Program2(List <string> arguments, BackgroundWorker worker, DoWorkEventArgs e) { // Retrieve all arguments string path = arguments[0]; bool volumeSliders = arguments[1] == "True"; bool samplesetSliders = arguments[2] == "True"; bool volumeSpinners = arguments[3] == "True"; bool resnapObjects = arguments[4] == "True"; bool resnapBookmarks = arguments[5] == "True"; int snap1 = int.Parse(arguments[6].Split('/')[1]); int snap2 = int.Parse(arguments[7].Split('/')[1]); bool removeSliderendMuting = arguments[8] == "True"; bool removeUnclickabeHitsounds = arguments[9] == "True"; Editor editor = new Editor(path); Timing timing = editor.Beatmap.BeatmapTiming; Timeline timeline = editor.Beatmap.GetTimeline(); int mode = editor.Beatmap.General["Mode"].Value; int num_timingPoints = editor.Beatmap.BeatmapTiming.TimingPoints.Count; int objectsResnapped = 0; // Count total stages int maxStages = 11; // Collect Kiai toggles and SV changes for mania/taiko List <TimingPoint> kiaiToggles = new List <TimingPoint>(); List <TimingPoint> svChanges = new List <TimingPoint>(); bool lastKiai = false; double lastSV = -100; for (int i = 0; i < timing.TimingPoints.Count; i++) { TimingPoint tp = timing.TimingPoints[i]; if (tp.Kiai != lastKiai) { kiaiToggles.Add(tp.Copy()); lastKiai = tp.Kiai; } if (tp.Inherited) { lastSV = -100; } else { if (tp.MpB != lastSV) { svChanges.Add(tp.Copy()); lastSV = tp.MpB; } } UpdateProgressbar(worker, (double)i / timing.TimingPoints.Count, 0, maxStages); } // Resnap shit if (resnapObjects) { // Resnap all objects for (int i = 0; i < editor.Beatmap.HitObjects.Count; i++) { HitObject ho = editor.Beatmap.HitObjects[i]; bool resnapped = ho.ResnapSelf(timing, snap1, snap2); if (resnapped) { objectsResnapped += 1; } ho.ResnapEnd(timing, snap1, snap2); UpdateProgressbar(worker, (double)i / editor.Beatmap.HitObjects.Count, 1, maxStages); } // Resnap Kiai toggles and SV changes for (int i = 0; i < kiaiToggles.Count; i++) { TimingPoint tp = kiaiToggles[i]; tp.ResnapSelf(timing, snap1, snap2); UpdateProgressbar(worker, (double)i / kiaiToggles.Count, 2, maxStages); } for (int i = 0; i < svChanges.Count; i++) { TimingPoint tp = svChanges[i]; tp.ResnapSelf(timing, snap1, snap2); UpdateProgressbar(worker, (double)i / svChanges.Count, 3, maxStages); } } if (resnapBookmarks) { // Resnap the bookmarks List <double> newBookmarks = new List <double>(); List <double> bookmarks = editor.Beatmap.GetBookmarks(); for (int i = 0; i < bookmarks.Count; i++) { double bookmark = bookmarks[i]; newBookmarks.Add(Math.Floor(timing.Resnap(bookmark, snap1, snap2))); UpdateProgressbar(worker, (double)i / bookmarks.Count, 4, maxStages); } editor.Beatmap.SetBookmarks(newBookmarks); } // Maybe mute unclickable timelineobjects if (removeUnclickabeHitsounds) { foreach (TimelineObject tlo in timeline.TimeLineObjects) { if (!(tlo.IsCircle || tlo.IsSliderHead || tlo.IsHoldnoteHead)) // Not clickable { tlo.FenoSampleVolume = 5; // 5% volume mute } } } // Make new timingpoints List <Change> changes = new List <Change>(); // Add redlines List <TimingPoint> redlines = timing.GetAllRedlines(); for (int i = 0; i < redlines.Count; i++) { TimingPoint tp = redlines[i]; changes.Add(new Change(tp, mpb: true, meter: true, inherited: true)); UpdateProgressbar(worker, (double)i / redlines.Count, 5, maxStages); } // Add SV changes for taiko and mania if (mode == 1 || mode == 3) { for (int i = 0; i < svChanges.Count; i++) { TimingPoint tp = svChanges[i]; changes.Add(new Change(tp, mpb: true)); UpdateProgressbar(worker, (double)i / svChanges.Count, 6, maxStages); } } // Add Kiai toggles for (int i = 0; i < kiaiToggles.Count; i++) { TimingPoint tp = kiaiToggles[i]; changes.Add(new Change(tp, kiai: true)); UpdateProgressbar(worker, (double)i / kiaiToggles.Count, 7, maxStages); } // Add Hitobject stuff for (int i = 0; i < editor.Beatmap.HitObjects.Count; i++) { HitObject ho = editor.Beatmap.HitObjects[i]; if (ho.IsSlider) // SV changes { TimingPoint tp = ho.TP.Copy(); tp.Offset = ho.Time; tp.MpB = ho.SV; changes.Add(new Change(tp, mpb: true)); } // Body hitsounds bool vol = (ho.IsSlider && volumeSliders) || (ho.IsSpinner && volumeSpinners); bool sam = (ho.IsSlider && samplesetSliders && ho.SampleSet == 0); bool ind = (ho.IsSlider && samplesetSliders); bool samplesetActuallyChanged = false; foreach (TimingPoint tp in ho.BodyHitsounds) { if (tp.Volume == 5 && removeSliderendMuting) { vol = false; } // Removing sliderbody silencing changes.Add(new Change(tp, volume: vol, index: ind, sampleset: sam)); if (tp.SampleSet != ho.HitsoundTP.SampleSet) { samplesetActuallyChanged = samplesetSliders && ho.SampleSet == 0; } // True for sampleset change in sliderbody } if (ho.IsSlider && (!samplesetActuallyChanged) && ho.SampleSet == 0) // Case can put sampleset on sliderbody { ho.SampleSet = ho.HitsoundTP.SampleSet; ho.SliderExtras = true; } if (ho.IsSlider && samplesetActuallyChanged) // Make it start out with the right sampleset { TimingPoint tp = ho.HitsoundTP.Copy(); tp.Offset = ho.Time; changes.Add(new Change(tp, sampleset: true)); } UpdateProgressbar(worker, (double)i / editor.Beatmap.HitObjects.Count, 8, maxStages); } // Add timeline hitsounds for (int i = 0; i < timeline.TimeLineObjects.Count; i++) { TimelineObject tlo = timeline.TimeLineObjects[i]; // Change the samplesets in the hitobjects if (tlo.Origin.IsCircle) { tlo.Origin.SampleSet = tlo.FenoSampleSet; tlo.Origin.AdditionSet = tlo.FenoAdditionSet; if (mode == 3) { tlo.Origin.CustomIndex = tlo.FenoCustomIndex; tlo.Origin.SampleVolume = tlo.FenoSampleVolume; } } else if (tlo.Origin.IsSlider) { tlo.Origin.EdgeHitsounds[tlo.Repeat] = tlo.GetHitsounds(); tlo.Origin.EdgeSampleSets[tlo.Repeat] = tlo.FenoSampleSet; tlo.Origin.EdgeAdditionSets[tlo.Repeat] = tlo.FenoAdditionSet; tlo.Origin.SliderExtras = true; if (tlo.Origin.EdgeAdditionSets[tlo.Repeat] == tlo.Origin.EdgeSampleSets[tlo.Repeat]) // Simplify additions to auto { tlo.Origin.EdgeAdditionSets[tlo.Repeat] = 0; } } else if (tlo.Origin.IsSpinner) { if (tlo.Repeat == 1) { tlo.Origin.SampleSet = tlo.FenoSampleSet; tlo.Origin.AdditionSet = tlo.FenoAdditionSet; } } else if (tlo.Origin.IsHoldNote) { if (tlo.Repeat == 0) { tlo.Origin.SampleSet = tlo.FenoSampleSet; tlo.Origin.AdditionSet = tlo.FenoAdditionSet; tlo.Origin.CustomIndex = tlo.FenoCustomIndex; tlo.Origin.SampleVolume = tlo.FenoSampleVolume; } } if (tlo.Origin.AdditionSet == tlo.Origin.SampleSet) // Simplify additions to auto { tlo.Origin.AdditionSet = 0; } if (mode == 0 && tlo.HasHitsound) // Add greenlines for custom indexes and volumes { TimingPoint tp = tlo.Origin.TP.Copy(); tp.Offset = tlo.Time; tp.SampleIndex = tlo.FenoCustomIndex; tp.Volume = tlo.FenoSampleVolume; bool ind = !(tlo.Filename != "" && (tlo.IsCircle || tlo.IsHoldnoteHead || tlo.IsSpinnerEnd)); // Index doesnt have to change if custom is overridden by Filename bool vol = !(tp.Volume == 5 && removeSliderendMuting && (tlo.IsSliderEnd || tlo.IsSpinnerEnd)); // Remove volume change if sliderend muting or spinnerend muting changes.Add(new Change(tp, volume: vol, index: ind)); } UpdateProgressbar(worker, (double)i / timeline.TimeLineObjects.Count, 9, maxStages); } // Add the new timingpoints changes = changes.OrderBy(o => o.TP.Offset).ToList(); List <TimingPoint> newTimingPoints = new List <TimingPoint>(); for (int i = 0; i < changes.Count; i++) { Change c = changes[i]; c.AddChange(newTimingPoints, timing); UpdateProgressbar(worker, (double)i / changes.Count, 10, maxStages); } // Replace the old timingpoints timing.TimingPoints = newTimingPoints; // Save the file editor.SaveFile(); // Complete progressbar if (worker != null && worker.WorkerReportsProgress) { worker.ReportProgress(100); } // Make an accurate message (Softwareporn) int removed = num_timingPoints - newTimingPoints.Count; string message = ""; if (removed < 0) { message += "Succesfully added " + Math.Abs(removed); } else { message += "Succesfully removed " + removed; } if (Math.Abs(removed) == 1) { message += " greenline and resnapped " + objectsResnapped; } else { message += " greenlines and resnapped " + objectsResnapped; } if (Math.Abs(objectsResnapped) == 1) { message += " object!"; } else { message += " objects!"; } return(message); }