public void Serialize(Stream stream, ChartSortMode mode = ChartSortMode.Timing) { ArcaeaAffWriter writer = new ArcaeaAffWriter(stream, ArcAudioManager.Instance.AudioOffset); List <ArcEvent> events = new List <ArcEvent>(); events.AddRange(Timings); events.AddRange(Taps); events.AddRange(Holds); events.AddRange(Arcs); events.AddRange(Cameras); events.AddRange(SceneControl); switch (mode) { case ChartSortMode.Timing: events = events.OrderBy(arcEvent => arcEvent.Timing) .ThenBy(arcEvent => (arcEvent is ArcTiming ? 1 : arcEvent is ArcTap ? 2 : arcEvent is ArcHold ? 3 : arcEvent is ArcArc ? 4 : 5)) .ToList(); break; case ChartSortMode.Type: events = events.OrderBy(arcEvent => (arcEvent is ArcTiming ? 1 : arcEvent is ArcTap ? 2 : arcEvent is ArcHold ? 3 : arcEvent is ArcArc ? 4 : 5)) .ThenBy(arcEvent => arcEvent.Timing) .ToList(); break; } foreach (var e in events) { if (e is ArcTap) { var tap = e as ArcTap; writer.WriteEvent(new ArcaeaAffTap() { Timing = tap.Timing, Track = tap.Track, Type = Aff.EventType.Tap }); } else if (e is ArcHold) { var hold = e as ArcHold; writer.WriteEvent(new ArcaeaAffHold() { Timing = hold.Timing, Track = hold.Track, EndTiming = hold.EndTiming, Type = Aff.EventType.Hold }); } else if (e is ArcTiming) { var timing = e as ArcTiming; writer.WriteEvent(new ArcaeaAffTiming() { Timing = timing.Timing, BeatsPerLine = timing.BeatsPerLine, Bpm = timing.Bpm, Type = Aff.EventType.Timing }); } else if (e is ArcArc) { var arc = e as ArcArc; var a = new ArcaeaAffArc() { Timing = arc.Timing, EndTiming = arc.EndTiming, XStart = arc.XStart, XEnd = arc.XEnd, LineType = ToLineTypeString(arc.LineType), YStart = arc.YStart, YEnd = arc.YEnd, Color = arc.Color, IsVoid = arc.IsVoid, Type = Aff.EventType.Arc }; if (arc.ArcTaps != null && arc.ArcTaps.Count != 0) { a.ArcTaps = arc.ArcTaps.Select(arcTap => arcTap.Timing).OrderBy(time => time).ToList(); } writer.WriteEvent(a); } else if (e is ArcCamera) { var cam = e as ArcCamera; writer.WriteEvent(new ArcaeaAffCamera() { Timing = cam.Timing, Move = cam.Move, Rotate = cam.Rotate, CameraType = ToCameraTypeString(cam.CameraType), Duration = cam.Duration, Type = Aff.EventType.Camera }); } else if (e is ArcSceneControl) { var spe = e as ArcSceneControl; writer.WriteEvent(new ArcaeaAffSceneControl { Timing = spe.Timing, Type = Aff.EventType.SceneControl, SceneControlType = spe.Type }); } } writer.Close(); }
public static void ArcaeaToLanota(string affPath) { ArcaeaAffReader reader = new ArcaeaAffReader(affPath); LanotaChartManaged la = new LanotaChartManaged(); float baseBpm = (reader.Events[0] as ArcaeaAffTiming).Bpm; la.LanotaChangeBpm.Add(new Lanota.Managed.LanotaChangeBpm { Time = -3, Bpm = baseBpm }); la.LanotaScroll.Add(new Lanota.Managed.LanotaScroll { Speed = 1, Time = -10 }); foreach (ArcaeaAffEvent e in reader.Events) { switch (e.Type) { case Arcaea.EventType.Timing: ArcaeaAffTiming timing = e as ArcaeaAffTiming; la.LanotaChangeBpm.Add(new Lanota.Managed.LanotaChangeBpm() { Bpm = timing.Bpm, Time = (timing.Timing + reader.AudioOffset) / 1000f }); la.LanotaScroll.Add(new Lanota.Managed.LanotaScroll() { Speed = timing.Bpm / baseBpm, Time = (timing.Timing + reader.AudioOffset) / 1000f }); break; case Arcaea.EventType.Tap: ArcaeaAffTap tap = e as ArcaeaAffTap; la.LanotaTapNote.Add(new Lanota.Managed.LanotaTapNote() { Type = 0, Time = (tap.Timing + reader.AudioOffset) / 1000f, Size = 1, Degree = tap.Track * 30 - 70 }); break; case Arcaea.EventType.Hold: ArcaeaAffHold hold = e as ArcaeaAffHold; la.LanotaHoldNote.Add(new Lanota.Managed.LanotaHoldNote() { Type = 5, Time = (hold.Timing + reader.AudioOffset) / 1000f, Degree = hold.Track * 30 - 70, Duration = (hold.EndTiming - hold.Timing) / 1000f, Size = 1 }); break; case Arcaea.EventType.Arc: ArcaeaAffArc arc = e as ArcaeaAffArc; if (!arc.IsVoid) { la.LanotaHoldNote.Add(new Lanota.Managed.LanotaHoldNote() { Type = 5, Time = (arc.Timing + reader.AudioOffset) / 1000f, Duration = (arc.EndTiming - arc.Timing) / 1000f, Degree = ArcaeaUtility.ConvertDegree(arc.XStart, arc.YStart, arc.Color), Jcount = 1, Size = 1, Joints = new List <Lanota.Managed.LanotaJoints>() { new Lanota.Managed.LanotaJoints() { dDegree = ArcaeaUtility.ConvertDegree(arc.XEnd, arc.YEnd, arc.Color) - ArcaeaUtility.ConvertDegree(arc.XStart, arc.YStart, arc.Color), dTime = (arc.EndTiming - arc.Timing) / 1000f, Cfmi = ArcaeaUtility.DetermineEase(arc.LineType) } } }); } if (arc.ArcTaps != null) { float startDegree = ArcaeaUtility.ConvertDegree(arc.XStart, arc.YStart, arc.Color); float deltaDegree = ArcaeaUtility.ConvertDegree(arc.XEnd, arc.YEnd, arc.Color) - ArcaeaUtility.ConvertDegree(arc.XStart, arc.YStart, arc.Color); float duration = (arc.EndTiming - arc.Timing) / 1000f; float startTiming = (arc.Timing + reader.AudioOffset) / 1000f; int ease = ArcaeaUtility.DetermineEase(arc.LineType); foreach (int i in arc.ArcTaps) { float t = (i + reader.AudioOffset) / 1000f; float percent = (t - startTiming) / duration; float degree = startDegree + deltaDegree * ArcaeaUtility.CalculateEasedCurve(percent, ease); la.LanotaTapNote.Add(new Lanota.Managed.LanotaTapNote() { Type = 0, Time = t, Size = 2, Degree = degree }); } } break; } } File.WriteAllText(affPath.Replace(".aff", "_convert.txt"), la.ToString()); }