private string Copy_Timing(TimingCopierVm arg, BackgroundWorker worker, DoWorkEventArgs _) { string[] paths = arg.ExportPath.Split('|'); int mapsDone = 0; var reader = EditorReaderStuff.GetFullEditorReaderOrNot(); foreach (string exportPath in paths) { var editorTo = EditorReaderStuff.GetNewestVersionOrNot(exportPath, reader); var editorFrom = EditorReaderStuff.GetNewestVersionOrNot(arg.ImportPath, reader); Beatmap beatmapTo = editorTo.Beatmap; Beatmap beatmapFrom = editorFrom.Beatmap; Timing timingTo = beatmapTo.BeatmapTiming; Timing timingFrom = beatmapFrom.BeatmapTiming; // Get markers for hitobjects if mode 1 is used List <Marker> markers = new List <Marker>(); if (arg.ResnapMode == "Number of beats between objects stays the same") { markers = GetMarkers(beatmapTo, timingTo); } // Rid the beatmap of redlines // If a greenline exists at the same time as a redline then the redline ceizes to exist // Else convert the redline to a greenline: Inherited = false & MpB = -100 List <TimingPoint> removeList = new List <TimingPoint>(); foreach (TimingPoint redline in timingTo.GetAllRedlines()) { TimingPoint greenlineHere = timingTo.GetGreenlineAtTime(redline.Offset); if (greenlineHere.Offset == redline.Offset) { removeList.Add(redline); } else { redline.Uninherited = false; redline.MpB = -100; } } foreach (TimingPoint tp in removeList) { timingTo.TimingPoints.Remove(tp); } // Make new timing points changes List <TimingPointsChange> timingPointsChanges = new List <TimingPointsChange>(); // Add redlines List <TimingPoint> redlines = timingFrom.GetAllRedlines(); foreach (TimingPoint tp in redlines) { timingPointsChanges.Add(new TimingPointsChange(tp, mpb: true, meter: true, inherited: true, omitFirstBarLine: true)); } // Apply timing changes TimingPointsChange.ApplyChanges(timingTo, timingPointsChanges); if (arg.ResnapMode == "Number of beats between objects stays the same") { redlines = timingTo.GetAllRedlines(); List <double> newBookmarks = new List <double>(); double lastTime = redlines.FirstOrDefault().Offset; foreach (Marker marker in markers) { // Get redlines between this and last marker TimingPoint redline = timingTo.GetRedlineAtTime(lastTime, redlines.FirstOrDefault()); double beatsFromLastTime = marker.BeatsFromLastMarker; while (true) { List <TimingPoint> redlinesBetween = redlines.Where(o => o.Offset <= lastTime + redline.MpB * beatsFromLastTime && o.Offset > lastTime).ToList(); if (redlinesBetween.Count == 0) { break; } TimingPoint first = redlinesBetween.First(); double diff = first.Offset - lastTime; beatsFromLastTime -= diff / redline.MpB; redline = first; lastTime = first.Offset; } // Last time is the time of the last redline in between double newTime = lastTime + redline.MpB * beatsFromLastTime; newTime = timingTo.Resnap(newTime, arg.Snap1, arg.Snap2, firstTp: redlines.FirstOrDefault()); marker.Time = newTime; lastTime = marker.Time; } // Add the bookmarks foreach (Marker marker in markers) { // Check whether the marker is a bookmark if (marker.Object is double) { // Don't resnap bookmarks newBookmarks.Add((double)marker.Object); } } beatmapTo.SetBookmarks(newBookmarks); } else if (arg.ResnapMode == "Just resnap") { // Resnap hitobjects foreach (HitObject ho in beatmapTo.HitObjects) { ho.ResnapSelf(timingTo, arg.Snap1, arg.Snap2, firstTp: redlines.FirstOrDefault()); ho.ResnapEnd(timingTo, arg.Snap1, arg.Snap2, firstTp: redlines.FirstOrDefault()); } // Resnap greenlines foreach (TimingPoint tp in timingTo.GetAllGreenlines()) { tp.ResnapSelf(timingTo, arg.Snap1, arg.Snap2, firstTP: redlines.FirstOrDefault()); } } else { // Don't move objects } // Save the file editorTo.SaveFile(); // Update progressbar if (worker != null && worker.WorkerReportsProgress) { worker.ReportProgress(++mapsDone * 100 / paths.Length); } } // Make an accurate message string message = $"Successfully copied timing to {mapsDone} {(mapsDone == 1 ? "beatmap" : "beatmaps")}!"; return(message); }