// Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; using System.Collections.Generic; using System.Linq; 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; } /// /// Checks if a Beatmap can be converted using this Beatmap Converter. /// /// The Beatmap to check. /// Whether the Beatmap can be converted using this Beatmap Converter. public bool CanConvert(Beatmap beatmap) => ValidConversionTypes.All(t => beatmap.HitObjects.Any(t.IsInstanceOfType)); /// /// Converts a Beatmap using this Beatmap Converter. /// /// The un-converted Beatmap. /// The converted Beatmap. public Beatmap Convert(Beatmap original) { // We always operate on a clone of the original beatmap, to not modify it game-wide return ConvertBeatmap(new Beatmap(original)); } void IBeatmapConverter.Convert(Beatmap original) => Convert(original); /// /// Performs the conversion of a Beatmap using this Beatmap Converter. /// /// The un-converted Beatmap. /// The converted Beatmap. protected virtual Beatmap ConvertBeatmap(Beatmap original) { var beatmap = CreateBeatmap(); // todo: this *must* share logic (or directly use) Beatmap's constructor. // right now this isn't easily possible due to generic entanglement. beatmap.BeatmapInfo = original.BeatmapInfo; beatmap.ControlPointInfo = original.ControlPointInfo; beatmap.HitObjects = original.HitObjects.SelectMany(h => convert(h, original)).ToList(); beatmap.Breaks = original.Breaks; return beatmap; } /// /// Converts a hit object. /// /// The hit object to convert. /// The un-converted Beatmap. /// The converted hit object. private IEnumerable convert(HitObject original, Beatmap beatmap) { // Check if the hitobject is already the converted type T tObject = original as T; if (tObject != null) { yield return tObject; yield break; } var converted = ConvertHitObject(original, beatmap).ToList(); ObjectConverted?.Invoke(original, converted); // Convert the hit object foreach (var obj in converted) { if (obj == null) continue; yield return obj; } } /// /// The types of HitObjects that can be converted to be used for this Beatmap. /// protected abstract IEnumerable ValidConversionTypes { get; } /// /// 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, Beatmap beatmap); } }