1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-18 11:12:57 +08:00
osu-lazer/osu.Game/Beatmaps/BeatmapConverter.cs

119 lines
4.4 KiB
C#
Raw Normal View History

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2022-06-17 15:37:17 +08:00
#nullable disable
2018-04-13 17:19:50 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using osu.Game.Rulesets;
2018-04-13 17:19:50 +08:00
using osu.Game.Rulesets.Objects;
namespace osu.Game.Beatmaps
{
/// <summary>
/// Converts a Beatmap for another mode.
/// </summary>
/// <typeparam name="T">The type of HitObject stored in the Beatmap.</typeparam>
public abstract class BeatmapConverter<T> : IBeatmapConverter
where T : HitObject
{
private event Action<HitObject, IEnumerable<HitObject>> objectConverted;
2019-02-28 12:31:40 +08:00
2018-04-13 17:19:50 +08:00
event Action<HitObject, IEnumerable<HitObject>> IBeatmapConverter.ObjectConverted
{
add => objectConverted += value;
remove => objectConverted -= value;
2018-04-13 17:19:50 +08:00
}
public IBeatmap Beatmap { get; }
protected BeatmapConverter(IBeatmap beatmap, Ruleset ruleset)
{
Beatmap = beatmap;
}
2018-04-13 17:19:50 +08:00
/// <summary>
/// Whether <see cref="Beatmap"/> can be converted by this <see cref="BeatmapConverter{T}"/>.
2018-04-13 17:19:50 +08:00
/// </summary>
public abstract bool CanConvert();
2018-04-13 17:19:50 +08:00
public IBeatmap Convert(CancellationToken cancellationToken = default)
2018-04-13 17:19:50 +08:00
{
// We always operate on a clone of the original beatmap, to not modify it game-wide
var original = Beatmap.Clone();
// Shallow clone isn't enough to ensure we don't mutate beatmap info unexpectedly.
// Can potentially be removed after `Beatmap.Difficulty` doesn't save back to `Beatmap.BeatmapInfo`.
original.BeatmapInfo = original.BeatmapInfo.Clone();
original.ControlPointInfo = original.ControlPointInfo.DeepClone();
return ConvertBeatmap(original, cancellationToken);
2018-04-13 17:19:50 +08:00
}
/// <summary>
/// Performs the conversion of a Beatmap using this Beatmap Converter.
/// </summary>
/// <param name="original">The un-converted Beatmap.</param>
/// <param name="cancellationToken">The cancellation token.</param>
2018-04-13 17:19:50 +08:00
/// <returns>The converted Beatmap.</returns>
protected virtual Beatmap<T> ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken)
2018-04-13 17:19:50 +08:00
{
var beatmap = CreateBeatmap();
beatmap.BeatmapInfo = original.BeatmapInfo;
beatmap.ControlPointInfo = original.ControlPointInfo;
beatmap.HitObjects = convertHitObjects(original.HitObjects, original, cancellationToken).OrderBy(s => s.StartTime).ToList();
2018-04-13 17:19:50 +08:00
beatmap.Breaks = original.Breaks;
return beatmap;
}
private List<T> convertHitObjects(IReadOnlyList<HitObject> hitObjects, IBeatmap beatmap, CancellationToken cancellationToken)
2018-04-13 17:19:50 +08:00
{
2018-10-11 19:29:26 +08:00
var result = new List<T>(hitObjects.Count);
2018-04-13 17:19:50 +08:00
2018-10-11 19:29:26 +08:00
foreach (var obj in hitObjects)
2018-04-13 17:19:50 +08:00
{
2018-10-11 19:29:26 +08:00
if (obj is T tObj)
{
result.Add(tObj);
2018-04-13 17:19:50 +08:00
continue;
2018-10-11 19:29:26 +08:00
}
var converted = ConvertHitObject(obj, beatmap, cancellationToken);
2018-04-13 17:19:50 +08:00
if (objectConverted != null)
2018-10-16 11:01:58 +08:00
{
converted = converted.ToList();
objectConverted.Invoke(obj, converted);
2018-10-16 11:01:58 +08:00
}
2018-10-11 19:29:26 +08:00
foreach (var c in converted)
{
if (c != null)
result.Add(c);
}
2018-04-13 17:19:50 +08:00
}
2018-10-11 19:29:26 +08:00
return result;
2018-04-13 17:19:50 +08:00
}
/// <summary>
2019-04-25 16:36:17 +08:00
/// Creates the <see cref="Beatmap{T}"/> that will be returned by this <see cref="BeatmapProcessor"/>.
2018-04-13 17:19:50 +08:00
/// </summary>
protected virtual Beatmap<T> CreateBeatmap() => new Beatmap<T>();
/// <summary>
/// Performs the conversion of a hit object.
/// This method is generally executed sequentially for all objects in a beatmap.
/// </summary>
/// <param name="original">The hit object to convert.</param>
/// <param name="beatmap">The un-converted Beatmap.</param>
/// <param name="cancellationToken">The cancellation token.</param>
2018-04-13 17:19:50 +08:00
/// <returns>The converted hit object.</returns>
2021-04-09 12:56:55 +08:00
protected virtual IEnumerable<T> ConvertHitObject(HitObject original, IBeatmap beatmap, CancellationToken cancellationToken) => Enumerable.Empty<T>();
2018-04-13 17:19:50 +08:00
}
}