public override Beatmap Decode(TextReader stream) { var beatmap = new Beatmap { HitObjects = new List <HitObject>(), ControlPoints = new List <ControlPoint>(), ComboColors = new List <Color4>(), BeatmapInfo = new BeatmapInfo { Metadata = new BeatmapMetadata(), BaseDifficulty = new BaseDifficulty(), }, }; var section = Section.None; string line; while (true) { line = stream.ReadLine(); if (line == null) { break; } if (string.IsNullOrEmpty(line)) { continue; } if (line.StartsWith(@"osu file format v")) { continue; } if (line.StartsWith(@"[") && line.EndsWith(@"]")) { if (!Enum.TryParse(line.Substring(1, line.Length - 2), out section)) { throw new InvalidDataException($@"Unknown osu section {line}"); } continue; } string val = line, key = null; if (section != Section.Events && section != Section.TimingPoints && section != Section.HitObjects) { key = val.Remove(val.IndexOf(':')).Trim(); val = val.Substring(val.IndexOf(':') + 1).Trim(); } switch (section) { case Section.General: handleGeneral(beatmap, key, val); break; case Section.Editor: handleEditor(beatmap, key, val); break; case Section.Metadata: handleMetadata(beatmap, key, val); break; case Section.Difficulty: handleDifficulty(beatmap, key, val); break; case Section.Events: handleEvents(beatmap, val); break; case Section.TimingPoints: handleTimingPoints(beatmap, val); break; case Section.Colours: handleColours(beatmap, key, val); break; case Section.HitObjects: beatmap.HitObjects.Add(HitObject.Parse(beatmap.BeatmapInfo.Mode, val)); break; } } return(beatmap); }