// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Collections.Generic; using System.Linq; using osu.Game.Rulesets; using osu.Game.Rulesets.Objects; namespace osu.Game.Beatmaps { /// /// Converts a Beatmap for another mode. /// /// The type of HitObject stored in the Beatmap. public abstract class BeatmapConverter : IBeatmapConverter where T : HitObject { private event Action> ObjectConverted; event Action> IBeatmapConverter.ObjectConverted { add => ObjectConverted += value; remove => ObjectConverted -= value; } public IBeatmap Beatmap { get; } protected BeatmapConverter(IBeatmap beatmap, Ruleset ruleset) { Beatmap = beatmap; } /// /// Whether can be converted by this . /// public abstract bool CanConvert(); /// /// Converts . /// /// The converted Beatmap. public IBeatmap Convert() { // We always operate on a clone of the original beatmap, to not modify it game-wide return ConvertBeatmap(Beatmap.Clone()); } /// /// Performs the conversion of a Beatmap using this Beatmap Converter. /// /// The un-converted Beatmap. /// The converted Beatmap. protected virtual Beatmap ConvertBeatmap(IBeatmap original) { var beatmap = CreateBeatmap(); beatmap.BeatmapInfo = original.BeatmapInfo; beatmap.ControlPointInfo = original.ControlPointInfo; beatmap.HitObjects = convertHitObjects(original.HitObjects, original); beatmap.Breaks = original.Breaks; return beatmap; } private List convertHitObjects(IReadOnlyList hitObjects, IBeatmap beatmap) { var result = new List(hitObjects.Count); foreach (var obj in hitObjects) { if (obj is T tObj) { result.Add(tObj); continue; } var converted = ConvertHitObject(obj, beatmap); if (ObjectConverted != null) { converted = converted.ToList(); ObjectConverted.Invoke(obj, converted); } foreach (var c in converted) { if (c != null) result.Add(c); } } return result; } /// /// Creates the that will be returned by this . /// protected virtual Beatmap CreateBeatmap() => new Beatmap(); /// /// Performs the conversion of a hit object. /// This method is generally executed sequentially for all objects in a beatmap. /// /// The hit object to convert. /// The un-converted Beatmap. /// The converted hit object. protected abstract IEnumerable ConvertHitObject(HitObject original, IBeatmap beatmap); } }